"""Punkt 3: Blatt-Cards aus einer COLLECTION statt aus einem Einzelobjekt. Damit kann der Nutzer 4-6 Diamond-Cards mit unterschiedlichen Atlas-UVs anlegen und die Krone mischt sie. Rueckwaertskompatibel: ein einzelnes Objekt geht weiter. Beweisfuehrung: die Zufalls-Groesse wird ABGESCHALTET (Size Var 0). Dann kommt jede Groessenabweichung ausschliesslich von der Card-Variante, und die Anzahl verschiedener Face-Flaechen ist ein exakter Zaehler fuer die benutzten Varianten. Mit eingeschalteter Groessenstreuung waere das Mass unbrauchbar - alles streut. Aufruf: blender --background --factory-startup --python tests/test_blatt_varianten.py """ import os import sys import importlib.util import bpy ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) spec = importlib.util.spec_from_file_location( "tg", os.path.join(ROOT, "stylized_tree_generator.py")) tg = importlib.util.module_from_spec(spec) sys.modules["tg"] = tg spec.loader.exec_module(tg) tg.register() fails = [] for o in list(bpy.data.objects): bpy.data.objects.remove(o, do_unlink=True) def card(name, groesse): """Diamond-Card in definierter Groesse - die Groesse ist hier der Marker.""" me = bpy.data.meshes.new(name) g = groesse me.from_pydata([(-g, 0, 0), (0, 0, g * 1.4), (g, 0, 0), (0, 0, -g * 0.2)], [], [(0, 1, 2), (0, 2, 3)]) me.update() ob = bpy.data.objects.new(name, me) bpy.context.scene.collection.objects.link(ob) return ob coll = bpy.data.collections.new("Leaf_Cards") bpy.context.scene.collection.children.link(coll) einzel = card("Card_Single", 0.5) GROESSEN = (0.30, 0.45, 0.60, 0.75) for i, g in enumerate(GROESSEN): c = card("Card_%02d" % (i + 1), g) bpy.context.scene.collection.objects.unlink(c) coll.objects.link(c) s = bpy.context.scene.tree_gen_settings s.preset = 'baum' s.use_growth = False s.apply_modifier = True s.art_name = "Eiche" s.variant = 1 s.leaf_size_var = 0.0 # entscheidend: Groesse kommt NUR von der Variante bpy.ops.object.treegen_create() baum = [o for o in bpy.context.scene.objects if o.type == 'MESH' and o.name.startswith("Eiche_01") and not o.name.endswith(("_Leaf", "_Frucht"))][0] def streuen(collection, einzelcard, seed): s.leaf_cards = collection s.leaf_card = einzelcard s.seed = seed for o in bpy.context.scene.objects: o.select_set(o is baum) bpy.context.view_layer.objects.active = baum bpy.ops.object.treegen_leaves() bl = bpy.data.objects.get(baum.name + "_Leaf") dg = bpy.context.evaluated_depsgraph_get() ev = bl.evaluated_get(dg) me = ev.to_mesh() # Auf 4 Stellen runden, nicht auf 5: die Cards werden gedreht, und seit die # Kippung bei 0.9 steht streuen die Flaechen in der sechsten Stelle. Mit # 5 Stellen zerfiel eine einzige Card-Sorte in vier Eimer. flaechen = sorted({round(p.area, 4) for p in me.polygons}) n = len(me.polygons) ev.to_mesh_clear() return n, flaechen print("%-26s %7s %s" % ("Variante", "Faces", "verschiedene Flaechen")) # --- 1) Rueckwaertskompatibel: Einzelobjekt ------------------------------ n1, f1 = streuen(None, einzel, 0) print("%-26s %7d %d" % ("Einzel-Card", n1, len(f1))) if n1 == 0: fails.append("Einzel-Card erzeugt keine Blaetter - Rueckwaertskompatibilitaet weg") # Eine Card = zwei unterschiedlich grosse Tris = genau zwei Flaechen. if len(f1) > 3: fails.append("Einzel-Card liefert %d verschiedene Flaechen, erwartet <= 3 - " "die Groessenstreuung ist nicht wirklich aus" % len(f1)) # --- 2) Collection: alle Varianten kommen vor ---------------------------- n2, f2 = streuen(coll, None, 0) print("%-26s %7d %d" % ("Collection (%d Cards)" % len(GROESSEN), n2, len(f2))) if n2 == 0: fails.append("Collection erzeugt keine Blaetter") # Vier Cards mit je zwei Tris = acht verschiedene Flaechen, wenn wirklich alle # vier gezogen werden. Weniger heisst: es kommen nicht alle Varianten vor. erwartet = 2 * len(GROESSEN) if len(f2) < erwartet: fails.append("Nur %d verschiedene Flaechen, erwartet %d - es werden nicht " "alle %d Card-Varianten gezogen" % (len(f2), erwartet, len(GROESSEN))) # --- 3) Seed-stabil ------------------------------------------------------ n3, f3 = streuen(coll, None, 0) print("%-26s %7d %d" % ("gleicher Seed", n3, len(f3))) if (n3, f3) != (n2, f2): fails.append("Gleicher Seed liefert ein anderes Ergebnis - nicht stabil") n4, f4 = streuen(coll, None, 7) print("%-26s %7d %d" % ("anderer Seed", n4, len(f4))) if (n4, f4) == (n2, f2): fails.append("Anderer Seed liefert dasselbe Ergebnis - der Seed wirkt nicht") # --- 4) Collection hat Vorrang vor der Einzel-Card ----------------------- n5, f5 = streuen(coll, einzel, 0) print("%-26s %7d %d" % ("beides gesetzt", n5, len(f5))) if len(f5) < erwartet: fails.append("Mit gesetzter Einzel-Card faellt die Collection zurueck - " "die Sammlung muss Vorrang haben") print("") if fails: print("ERGEBNIS: %d FEHLER" % len(fails)) for x in fails: print(" - " + x) sys.exit(1) print("ERGEBNIS: ALLE CHECKS OK")