diff --git a/README.md b/README.md index 02f12d8..7798fbc 100644 --- a/README.md +++ b/README.md @@ -563,6 +563,30 @@ Der Kaktus erzeugt regulaer **0 Cards** — kein Ast ist duenner als `Max Radius und das ist botanisch richtig. Vorher lief das still durch und man stand vor einer leeren `_Leaf`-Ebene; jetzt sagt der Operator es und nennt den Regler. +### Die Gesamtdatei steht jetzt auch auf der Stammbasis + +`_Pieces_All.fbx` trug den SZENEN-Nullpunkt mit: ein Baum bei x = 18 m +exportierte gemessen mit X 16.5..19.3, Y -8.7..-6.2. Die Einzel-Teile hatten +das Problem nie - sie sitzen ohnehin auf ihrem Massenmittelpunkt -, und der +Stand-Baum folgt der Stammbasis-Konvention seit 1.36. Nur die +Zusammenbau-Datei fiel heraus. + +Der Versatz kommt aus **derselben Funktion** wie beim Stand-Baum +(`_stammbasis_versatz`, aus `_origin_bottom_center` herausgeloest). Zwei +Rechnungen fuer denselben Nullpunkt waeren genau die Fehlerklasse, die hier +schon dreimal zugeschlagen hat - und hier haette sie besonders weh getan: die +zusammengesetzten Truemmer muessen exakt auf dem Platz liegen, wo der Baum +stand. + +Angewendet wird der Versatz nur fuer diesen Export und danach zurueckgenommen. +Mit "Teile behalten" staenden sie sonst verschoben neben dem Baum in der Szene. + +Geprueft wird ueber den STAMMQUERSCHNITT auf Fusshoehe, nicht ueber die +Bbox-Mitte: die Krone haengt einseitig, eine Bbox-Mitte wuerde den Fehler +verwischen. Der Test stellt den Baum dafuer bewusst auf (18, -7.5) - bei +(0,0,0) faellt so etwas nicht auf. Gegenprobe ohne den Versatz: Stammfuss bei +18.000 / -7.500, genau der gemeldete Wert. + ### UCX auch in der Gesamtdatei - und zwei Fehler, die dabei auffielen `_Pieces_All.fbx` kam ohne Kollision an, waehrend die Einzeldateien welche diff --git a/blender_manifest_tree.toml b/blender_manifest_tree.toml index 9fe096c..008ecd7 100644 --- a/blender_manifest_tree.toml +++ b/blender_manifest_tree.toml @@ -1,7 +1,7 @@ schema_version = "1.0.0" id = "stylized_tree_generator" -version = "1.43.0" +version = "1.44.0" name = "Stylized Tree Generator" tagline = "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen" maintainer = "D4rkst3r" diff --git a/dist/index.html b/dist/index.html index d2ba893..e6ce996 100644 --- a/dist/index.html +++ b/dist/index.html @@ -50,17 +50,17 @@ 34.1KB - stylized_tree_generator-1.43.0 + stylized_tree_generator-1.44.0 Stylized Tree Generator Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen link 4.2.0 - ~ all all - 49.0KB + 49.5KB -

Built 2026-08-07, 04:53

+

Built 2026-08-07, 04:59

diff --git a/dist/index.json b/dist/index.json index 0aca9b6..9f9af94 100644 --- a/dist/index.json +++ b/dist/index.json @@ -82,7 +82,7 @@ "id": "stylized_tree_generator", "name": "Stylized Tree Generator", "tagline": "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen", - "version": "1.43.0", + "version": "1.44.0", "type": "add-on", "maintainer": "D4rkst3r", "license": [ @@ -98,9 +98,9 @@ "Mesh", "Modeling" ], - "archive_url": "./stylized_tree_generator-1.43.0.zip", - "archive_size": 50130, - "archive_hash": "sha256:2d87c780f90befc057e6895762c151bd6f4e9514485f5eb98b64993f6304893f" + "archive_url": "./stylized_tree_generator-1.44.0.zip", + "archive_size": 50734, + "archive_hash": "sha256:e10cf2efafc751b2e8b7cf6e15a793408f43ffff8b1dc0e98e43ad8ba809659a" } ] } \ No newline at end of file diff --git a/dist/stylized_tree_generator-1.43.0.zip b/dist/stylized_tree_generator-1.43.0.zip deleted file mode 100644 index dd3a23f..0000000 Binary files a/dist/stylized_tree_generator-1.43.0.zip and /dev/null differ diff --git a/dist/stylized_tree_generator-1.44.0.zip b/dist/stylized_tree_generator-1.44.0.zip new file mode 100644 index 0000000..13db121 Binary files /dev/null and b/dist/stylized_tree_generator-1.44.0.zip differ diff --git a/stylized_tree_generator.py b/stylized_tree_generator.py index 8e3a169..5906d3b 100644 --- a/stylized_tree_generator.py +++ b/stylized_tree_generator.py @@ -1,7 +1,7 @@ bl_info = { "name": "Stylized Tree Generator", "author": "D4rkst3r", - "version": (1, 43, 0), + "version": (1, 44, 0), "blender": (4, 2, 0), "location": "View3D > Sidebar > Tree Gen", "description": "Parametrischer Baum-/Palmen-/Busch-Generator (Geometry Nodes) mit Wachstums-Stufen", @@ -2804,8 +2804,22 @@ def _origin_bottom_center(ob): # Baum ohnehin fuer die Faell-Teile traegt. Ein Schwellwert auf den # Achsabstand waere die naheliegende Alternative und faellt beim Kaktus um: # dessen Stamm ist dicker als jeder sinnvolle Schwellwert. - stamm_verts = _stamm_koordinaten(me) + versatz = _stammbasis_versatz(_stamm_koordinaten(me)) + me.transform(versatz) + return versatz + +def _stammbasis_versatz(stamm_verts): + """Versatz, der die STAMMBASIS auf den Ursprung legt. + + Eine Stelle fuer beide Wege: der Stand-Baum-Export und die Gesamtdatei der + Faell-Teile muessen denselben Nullpunkt benutzen, sonst passen die + zusammengesetzten Truemmer nicht auf den Platz des Baums. Zwei Rechnungen + fuer dieselbe Frage waeren genau die Fehlerklasse, die hier schon dreimal + zugeschlagen hat. + """ + if not stamm_verts: + return Matrix.Identity(4) zs = [c.z for c in stamm_verts] z_fuss = min(zs) # X/Y aus dem UNTERSTEN RING, nicht aus der Bbox des ganzen Stammes: ein @@ -2823,9 +2837,7 @@ def _origin_bottom_center(ob): mx = (min(xs) + max(xs)) * 0.5 my = (min(ys) + max(ys)) * 0.5 - versatz = Matrix.Translation((-mx, -my, -z_fuss)) - me.transform(versatz) - return versatz + return Matrix.Translation((-mx, -my, -z_fuss)) @@ -3126,6 +3138,21 @@ class TREEGEN_OT_export_pieces(Operator): # Sie entstehen HIER und nicht in der Schleife weiter unten: dort # sitzt jedes Teil schon auf seinem eigenen Massenmittelpunkt, in # der Gesamtdatei stehen alle noch an ihrer Originalposition. + # URSPRUNG auf die STAMMBASIS, wie beim Stand-Baum seit 1.36. + # Vorher trug die Datei den Szenen-Nullpunkt mit: ein Baum bei + # x = 18 m exportierte gemessen mit X 16.5..19.3, und die Spielseite + # musste beim Import nachzentrieren. Die EINZEL-Teile hatten das + # Problem nie - sie sitzen ohnehin auf ihrem Massenmittelpunkt. + # + # Der Versatz kommt aus DERSELBEN Funktion wie beim Stand-Baum, denn + # die zusammengesetzten Truemmer muessen genau auf dem Platz liegen, + # wo der Baum stand. + basis_versatz = _stammbasis_versatz( + [stamm_src.matrix_world @ c + for c in _stamm_koordinaten(stamm_src.data)]) + for t in teile: + t.data.transform(basis_versatz) + hullen = [] if s.piece_ucx: for t in teile: @@ -3151,6 +3178,13 @@ class TREEGEN_OT_export_pieces(Operator): bpy.data.objects.remove(h, do_unlink=True) if hm.users == 0: bpy.data.meshes.remove(hm) + # Versatz zurueck. Fuer die Einzeldateien ist er egal - die setzen + # ihren Pivot ohnehin auf den Massenmittelpunkt -, aber mit "Teile + # behalten" staenden sie sonst verschoben neben dem Baum in der + # Szene. + zurueck = basis_versatz.inverted() + for t in teile: + t.data.transform(zurueck) # --- Je Teil eine Datei, Pivot = Massenmittelpunkt -------------- geschrieben = 0 diff --git a/tests/test_faell_teile.py b/tests/test_faell_teile.py index 9e85679..244405f 100644 --- a/tests/test_faell_teile.py +++ b/tests/test_faell_teile.py @@ -58,12 +58,19 @@ 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] +# Der Baum steht BEWUSST nicht am Ursprung. Die Gesamtdatei trug den +# Szenen-Nullpunkt mit (gemessen X 16.5..19.3 bei einem Baum auf x = 18), und +# bei (0,0,0) faellt genau das nicht auf. +STANDORT = (18.0, -7.5, 0.0) +baum.location = STANDORT for o in bpy.context.scene.objects: o.select_set(o is baum) bpy.context.view_layer.objects.active = baum s.leaf_card = card bpy.ops.object.treegen_leaves() blatt = bpy.data.objects.get(baum.name + "_Leaf") +if blatt is not None: + blatt.location = STANDORT # Referenz: wie viele Blatt-Faces hat der Stand-Baum? dg = bpy.context.evaluated_depsgraph_get() @@ -236,6 +243,26 @@ if gesamt: fails.append("Gesamtdatei nur %.2f m hoch - die Teile stehen nicht an " "ihrer Originalposition" % hoehe) + # URSPRUNG auf der Stammbasis, wie beim Stand-Baum. Geprueft ueber den + # STAMMQUERSCHNITT, nicht ueber die Bbox-Mitte: die Krone haengt einseitig, + # und eine Bbox-Mitte wuerde den Fehler verwischen. Gesucht wird auf + # Fusshoehe ein Ring von Vertices, der die Achse umschliesst. + stamm_teile = [o for o in teile if "_Piece_Stamm" in o.name] + if stamm_teile: + sco = [o.matrix_world @ v.co for o in stamm_teile + for v in o.data.vertices] + zmin = min(c.z for c in sco) + band = [c for c in sco if c.z <= zmin + hoehe * 0.03] + mx = sum(c.x for c in band) / len(band) + my = sum(c.y for c in band) / len(band) + print("Gesamtdatei: Stammfuss bei %.3f / %.3f / %.3f" % (mx, my, zmin)) + if math.hypot(mx, my) > hoehe * 0.02: + fails.append("Gesamtdatei: Stammfuss liegt bei %.2f/%.2f statt " + "ueber dem Ursprung - die Datei traegt den " + "Szenen-Nullpunkt mit" % (mx, my)) + if abs(zmin) > hoehe * 0.02: + fails.append("Gesamtdatei: Stammfuss bei Z %.3f statt 0" % zmin) + print("") if fails: print("ERGEBNIS: %d FEHLER" % len(fails))