1) Zwei-Pfade-Fehler behoben (von der Spielseite gemeldet) Blattwerk entstand an zwei Stellen - Haekchen "_Leaf anlegen" beim Erzeugen und Knopf "Blattwerk streuen" - und nur der zweite rechnete die Wachstums-Staffel. Am Modifier nachgemessen trug der S1-Setzling aus dem Create-Pfad Size 0.85, Max Radius 0.04, Min Height 0.25: die Altbaum-Werte. Zum dritten Mal dieselbe Fehlerklasse (nach Stufen-Deckung und build_group): zwei Quellen fuer dieselbe Frage. Die Staffel liegt jetzt in make_leaves selbst und zieht growth_t/preset vom Baum-Objekt - ein Aufrufer KANN sie nicht mehr vergessen. Darueber blattwerk_streuen() als der eine Einstieg fuer beide Knoepfe, inklusive der Dichte-Regelung, die vorher ebenfalls nur der Operator hatte. Nebenbei bekommt der Create-Pfad damit auch die Card-SAMMLUNG, die ihm bisher fehlte. test_zwei_pfade.py prueft die DIFFERENZ zwischen beiden Wegen, nicht die absoluten Werte - ein Test, der nur einen Weg anschaut, findet so etwas nie. Plus die Gegenprobe im Test selbst: waeren beide Wege gleich falsch, muss auffallen, dass S1 und S4 dieselbe Card-Groesse tragen. Gegenprobe gefahren: mit dem alten Create-Pfad meldet der Test 10 Fehler und reproduziert exakt die gemeldeten 0.85 / 0.04 / 0.25. 2) Generischer "baum" entsaeult Gemessen B/H 0.18 ueber fuenf Seeds - schmaler als jedes andere Laubgehoelz. Ursache dieselbe wie bei der Birke: Branch Up 1.3 aus den DEFAULTS. Zielband der Spielseite 0.45-0.60, jetzt 0.55 (0.52-0.56). Die DEFAULTS bleiben unangetastet - sie sind die Socket-Vorgaben, an denen die haendischen Regler haengen. Nur "baum" bekommt eigene Werte. 26 Tests bestehen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
128 lines
4.6 KiB
Python
128 lines
4.6 KiB
Python
"""Beide Wege zum Blattwerk muessen dasselbe ergeben.
|
|
|
|
Es gibt zwei Knoepfe, die Blattwerk erzeugen:
|
|
* "_Leaf anlegen" beim Erzeugen des Baums (TREEGEN_OT_create)
|
|
* "Blattwerk streuen" auf einer Auswahl (TREEGEN_OT_leaves)
|
|
|
|
Nur der zweite rechnete die Wachstums-Staffel. Von der Spielseite am Modifier
|
|
nachgemessen: der S1-Setzling aus dem Create-Pfad trug Size 0.85, Max Radius
|
|
0.04, Min Height 0.25 - exakt die Altbaum-Werte.
|
|
|
|
Das ist dieselbe Fehlerklasse, die vorher schon die Stufen-Deckung und
|
|
build_group erwischt hat: ZWEI QUELLEN fuer dieselbe Frage. Ein Test, der nur
|
|
einen der beiden Wege prueft, findet so etwas nie - deshalb prueft dieser hier
|
|
die DIFFERENZ zwischen ihnen und nicht die absoluten Werte.
|
|
|
|
Aufruf: blender --background --factory-startup --python tests/test_zwei_pfade.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)
|
|
|
|
me = bpy.data.meshes.new("Leaf_Card")
|
|
me.from_pydata([(-0.5, 0, 0), (0, 0, 0.7), (0.5, 0, 0), (0, 0, -0.1)],
|
|
[], [(0, 1, 2), (0, 2, 3)])
|
|
me.update()
|
|
card = bpy.data.objects.new("Leaf_Card", me)
|
|
bpy.context.scene.collection.objects.link(card)
|
|
|
|
s = bpy.context.scene.tree_gen_settings
|
|
s.leaf_card = card
|
|
s.apply_modifier = True
|
|
s.preset = "birke"
|
|
s.variant = 1
|
|
s.use_growth = True
|
|
s.stages = 4
|
|
|
|
# Die Werte, die die Staffel anfasst. "Density" steht bewusst NICHT dabei: sie
|
|
# wird nach dem Streuen per Bisektion eingeregelt und darf sich zwischen zwei
|
|
# Laeufen minimal unterscheiden.
|
|
GESTAFFELT = ("Size", "Max Radius", "Min Height")
|
|
|
|
|
|
def werte(leaf_obj):
|
|
md = leaf_obj.modifiers.get("GN_Leaves")
|
|
ids = tg.leaf_socket_ids(md.node_group)
|
|
return {k: round(float(md[ids[k]]), 6) for k in GESTAFFELT if k in ids}
|
|
|
|
|
|
def bauen(mit_haken):
|
|
for o in list(bpy.context.scene.objects):
|
|
if o is not card:
|
|
bpy.data.objects.remove(o, do_unlink=True)
|
|
s.art_name = "P" if mit_haken else "Q"
|
|
s.make_leaf = mit_haken
|
|
bpy.ops.object.treegen_create()
|
|
staemme = sorted((o for o in bpy.context.scene.objects
|
|
if o.type == 'MESH' and o is not card
|
|
and not o.name.endswith(("_Leaf", "_Frucht"))),
|
|
key=lambda o: o.name)
|
|
if not mit_haken:
|
|
for o in bpy.context.scene.objects:
|
|
o.select_set(o in staemme)
|
|
bpy.context.view_layer.objects.active = staemme[0]
|
|
bpy.ops.object.treegen_leaves()
|
|
out = []
|
|
for st in staemme:
|
|
bl = bpy.data.objects.get(st.name + "_Leaf")
|
|
out.append((st.name, float(st.get("growth_t", 1.0)),
|
|
werte(bl) if bl else None))
|
|
return out
|
|
|
|
|
|
erzeugt = bauen(True) # Haekchen "_Leaf anlegen"
|
|
operator = bauen(False) # Knopf "Blattwerk streuen"
|
|
|
|
print("%-5s %7s | %-34s | %-34s"
|
|
% ("Stufe", "growth", "beim Erzeugen", "per Operator"))
|
|
for (n1, gt, w1), (n2, _gt, w2) in zip(erzeugt, operator):
|
|
def zeig(w):
|
|
if w is None:
|
|
return "keine Blattebene"
|
|
return " ".join("%s %.3f" % (k[:3], w[k]) for k in GESTAFFELT if k in w)
|
|
gleich = "" if w1 == w2 else " <-- WEICHT AB"
|
|
print("%-5s %7.2f | %-34s | %-34s%s"
|
|
% (n1.split("_")[-1], gt, zeig(w1), zeig(w2), gleich))
|
|
if w1 is None or w2 is None:
|
|
fails.append("%s: eine der beiden Ebenen fehlt" % n1)
|
|
continue
|
|
for k in GESTAFFELT:
|
|
if k not in w1 or k not in w2:
|
|
continue
|
|
if abs(w1[k] - w2[k]) > 1e-6:
|
|
fails.append("%s: '%s' ist beim Erzeugen %.4f, per Operator %.4f - "
|
|
"die Wachstums-Staffel greift nur auf einem Weg"
|
|
% (n1, k, w1[k], w2[k]))
|
|
|
|
# Und die Staffel muss ueberhaupt greifen: waeren beide Wege gleich FALSCH,
|
|
# waere der Vergleich oben zufrieden. Also zusaetzlich, dass sich S1 von S4
|
|
# unterscheidet.
|
|
if len(erzeugt) >= 2 and erzeugt[0][2] and erzeugt[-1][2]:
|
|
s1, s4 = erzeugt[0][2], erzeugt[-1][2]
|
|
if s1.get("Size") is not None and abs(s1["Size"] - s4["Size"]) < 1e-6:
|
|
fails.append("S1 und S4 tragen dieselbe Card-Groesse (%.3f) - die "
|
|
"Staffel greift auf KEINEM der beiden Wege" % s1["Size"])
|
|
|
|
print("")
|
|
if fails:
|
|
print("ERGEBNIS: %d FEHLER" % len(fails))
|
|
for f in fails:
|
|
print(" - " + f)
|
|
sys.exit(1)
|
|
print("ERGEBNIS: ALLE CHECKS OK")
|