Files
stylized-rock-generator/tests/test_tree_addon.py
T
D4rkst3randClaude Opus 4.8 1112797138 Tree Generator v1.22.0: Phototropismus (Attraction Up)
Aeste kruemmen sich zur Spitze hin zur Senkrechten - als echte Rotation um den
Astansatz, nicht als Z-Versatz. Die Astlaenge bleibt dabei erhalten (gemessen:
+0.08 m Hoehe statt +0.93 m beim alten Droop-Hack). Pro Preset abgestimmt.

Idee aus UE 5.8 Procedural Vegetation / Weber-Penn.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 09:52:45 +02:00

81 lines
3.3 KiB
Python

"""Prueft das gebaute Tree-Addon: registrieren, Operator ausfuehren, Ergebnis messen."""
import bpy, sys, zipfile, os, tempfile, importlib.util, traceback
ZIP = r"A:\eco\stylized_rock_generator\dist\stylized_tree_generator-1.22.0.zip"
fails = []
tmp = tempfile.mkdtemp()
with zipfile.ZipFile(ZIP) as z:
z.extractall(tmp)
init = None
for root, _, files in os.walk(tmp):
if "__init__.py" in files:
init = os.path.join(root, "__init__.py"); break
if not init:
print("FAIL: __init__.py nicht im Zip"); sys.exit(1)
print("Zip-Inhalt ok:", os.path.relpath(init, tmp))
spec = importlib.util.spec_from_file_location("stylized_tree_generator", init)
m = importlib.util.module_from_spec(spec)
sys.modules["stylized_tree_generator"] = m
try:
spec.loader.exec_module(m)
m.register()
print("registriert ok")
except Exception:
traceback.print_exc(); print("FAIL: register"); sys.exit(1)
s = bpy.context.scene.tree_gen_settings
# 1) einzelner Baum je Preset
for p in ("baum", "palme", "busch", "kaktus"):
for o in list(bpy.data.objects):
bpy.data.objects.remove(o, do_unlink=True)
s.preset = p; s.use_growth = False; s.seed = 3
r = bpy.ops.object.treegen_create()
obs = [o for o in bpy.data.objects if o.type == 'MESH']
bpy.context.view_layer.update()
dg = bpy.context.evaluated_depsgraph_get()
v = len(obs[0].evaluated_get(dg).data.vertices) if obs else 0
ok = ('FINISHED' in r) and v > 0
print("preset %-7s -> %s verts=%d" % (p, "ok" if ok else "FAIL", v))
if not ok: fails.append(p)
# 2) Wachstums-Stufen
for o in list(bpy.data.objects):
bpy.data.objects.remove(o, do_unlink=True)
s.preset = "baum"; s.use_growth = True; s.stages = 4
r = bpy.ops.object.treegen_create()
obs = sorted([o for o in bpy.data.objects if o.type == 'MESH'], key=lambda o: o.name)
bpy.context.view_layer.update()
dg = bpy.context.evaluated_depsgraph_get()
counts = [len(o.evaluated_get(dg).data.vertices) for o in obs]
growing = all(counts[i] < counts[i+1] for i in range(len(counts)-1))
print("stufen: %d Objekte verts=%s aufsteigend=%s" % (len(obs), counts, growing))
if len(obs) != 4 or not growing: fails.append("stages")
# 3) Modifier anwenden (Export-Pfad)
for o in list(bpy.data.objects):
bpy.data.objects.remove(o, do_unlink=True)
s.use_growth = False; s.apply_modifier = True
s.generate_lightmap_uv = True # Default ist AUS (EcoGame: dynamisches Licht)
bpy.ops.object.treegen_create()
obs = [o for o in bpy.data.objects if o.type == 'MESH']
real = len(obs[0].data.vertices) if obs else 0 # echte Mesh-Daten, nicht evaluated
uvs = [l.name for l in obs[0].data.uv_layers] if obs else []
print("apply_modifier -> echte Verts=%d mods=%d uvs=%s" % (real, len(obs[0].modifiers) if obs else -1, uvs))
if real == 0: fails.append("apply")
if "UVMap" not in uvs: fails.append("uv0")
if "Lightmap" not in uvs: fails.append("uv1")
# UV muss world-space sein: V-Bereich ~ Baumhoehe
if obs and obs[0].data.uv_layers.get("UVMap"):
d = obs[0].data.uv_layers["UVMap"].data
vs = [x.uv[1] for x in d]
h = max(v.co.z for v in obs[0].data.vertices)
print("UV world-space check: V-max=%.2f Baumhoehe=%.2f" % (max(vs), h))
if max(vs) < h * 0.5: fails.append("uv_scale")
m.unregister()
print("ERGEBNIS:", "ALLE TESTS BESTANDEN" if not fails else ("FEHLER: " + ", ".join(fails)))
sys.exit(1 if fails else 0)