import bpy, glob, sys, zipfile, os, tempfile, importlib.util, math, bmesh # Version NICHT fest verdrahten - sonst schlaegt der Test nach jedem # Versions-Bump fehl, obwohl am Addon nichts kaputt ist. _d = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "dist") _z = sorted(glob.glob(os.path.join(_d, "stylized_tree_generator-*.zip"))) if not _z: print("ERGEBNIS: FEHLER: kein gebautes Tree-Zip in dist/ (erst build.ps1)") sys.exit(1) ZIP = _z[-1] tmp=tempfile.mkdtemp() with zipfile.ZipFile(ZIP) as z: z.extractall(tmp) init=[os.path.join(r,"__init__.py") for r,_,f in os.walk(tmp) if "__init__.py" in f][0] spec=importlib.util.spec_from_file_location("stg",init) m=importlib.util.module_from_spec(spec); sys.modules["stg"]=m; spec.loader.exec_module(m) try: m.unregister() except Exception: pass m.register() fails=[] for o in list(bpy.data.objects): bpy.data.objects.remove(o,do_unlink=True) # Card wie beim User me=bpy.data.meshes.new("DiamondCard"); bm=bmesh.new() for ang in (0.0, math.pi/3, 2*math.pi/3): c,s_=math.cos(ang), math.sin(ang) vs=[bm.verts.new(p) for p in [(-c,-s_,-1.41),(c,s_,-1.41),(c,s_,1.41),(-c,-s_,1.41)]] bm.faces.new(vs) bm.to_mesh(me); bm.free(); me.uv_layers.new(name="UVMap") card=bpy.data.objects.new("Diamon Plane", me); bpy.context.collection.objects.link(card) s=bpy.context.scene.tree_gen_settings s.preset='eiche'; s.art_name="Eiche"; s.variant=1 # Groesse und Dichte aus den Defaults nehmen. Frueher stand hier fest # leaf_size=0.22 - der alte Blaettchen-Wert. Zusammen mit der neuen Dichte 170 # ergab das genau die Kombination, die wir loswerden wollten: hunderte winziger # Cards (gemessen 2778 Blatt-Tris statt ~1000). s.leaf_card=card s.make_leaf=True; s.use_growth=False r=bpy.ops.object.treegen_create() names=sorted(o.name for o in bpy.context.scene.objects if o.type=='MESH') print("OBJEKTE:", [n for n in names if n!="Diamon Plane"]) if "Eiche_01" not in names or "Eiche_01_Leaf" not in names: fails.append("objekte") bpy.context.view_layer.update() dg=bpy.context.evaluated_depsgraph_get() def tris(n): ob=bpy.context.scene.objects[n] return sum(len(p.vertices)-2 for p in ob.evaluated_get(dg).data.polygons) tt,tl=tris("Eiche_01"), tris("Eiche_01_Leaf") # Budget aus den Einstellungen holen, nicht fest verdrahten: es steht seit # ASSETS.md Teil 6 pro Wachstumsstufe (S1 800 / S2 1200 / S3+S4 4000) und wurde # von 2500 angehoben, weil bei ISM-Instanzen mit LOD-Kette nicht die Dreiecke # der Engpass sind, sondern Overdraw und Schatten der Cards. budget = s.leaf_budget print("TRIS Stamm=%d Blatt=%d Summe=%d / %d %s (Dichte %.0f)" % (tt,tl,tt+tl,budget,"OK" if tt+tl<=budget else "UEBER", s.leaf_density)) if tl==0: fails.append("blattwerk_leer") if tt+tl>budget: fails.append("budget") # Ursprung deckungsgleich a=bpy.context.scene.objects["Eiche_01"]; b=bpy.context.scene.objects["Eiche_01_Leaf"] d=(a.location-b.location).length print("URSPRUNG-Abstand: %.6f" % d) if d>1e-6: fails.append("ursprung") # Operator auf Auswahl for o in bpy.context.selected_objects: o.select_set(False) a.select_set(True); bpy.context.view_layer.objects.active=a r2=bpy.ops.object.treegen_leaves() print("OPERATOR treegen_leaves:", list(r2)) if 'FINISHED' not in r2: fails.append("operator") # Ohne Card -> leeres _Leaf for o in list(bpy.data.objects): if o.name.startswith("Eiche"): bpy.data.objects.remove(o,do_unlink=True) s.leaf_card=None; s.art_name="Birke"; s.preset='birke' bpy.ops.object.treegen_create() lf=bpy.context.scene.objects.get("Birke_01_Leaf") print("ohne Card -> _Leaf vorhanden:", lf is not None, "| leer:", lf and len(lf.data.polygons)==0) if lf is None: fails.append("leer_leaf") m.unregister() print("ERGEBNIS:", "ALLE CHECKS OK" if not fails else "FEHLER: "+", ".join(fails)) sys.exit(1 if fails else 0)