From 55beb2bb2f126e888d04b8672760f533c37e967d Mon Sep 17 00:00:00 2001 From: D4rkst3r Date: Wed, 29 Jul 2026 11:17:36 +0200 Subject: [PATCH] Tree Generator v1.8.0: Profilaufloesung je Ast-Ebene (Branch Sides / Sub Sides) Stamm rund (8 Seiten), Aeste 4, Zweige 3 - wie im TreeIt-Referenzbaum. Runderer Stamm bei gleichzeitig ~25% weniger Tris (baum 1368 -> 1032). Co-Authored-By: Claude Opus 4.8 --- blender_manifest_tree.toml | 2 +- dist/index.json | 8 +- dist/stylized_tree_generator-1.7.0.zip | Bin 13398 -> 0 bytes dist/stylized_tree_generator-1.8.0.zip | Bin 0 -> 13440 bytes stylized_tree_generator.py | 196 ++++++++++++------------- 5 files changed, 102 insertions(+), 104 deletions(-) delete mode 100644 dist/stylized_tree_generator-1.7.0.zip create mode 100644 dist/stylized_tree_generator-1.8.0.zip diff --git a/blender_manifest_tree.toml b/blender_manifest_tree.toml index 8d72878..04f4798 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.7.0" +version = "1.8.0" name = "Stylized Tree Generator" tagline = "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen" maintainer = "D4rkst3r" diff --git a/dist/index.json b/dist/index.json index ecb43ac..2d79fbf 100644 --- a/dist/index.json +++ b/dist/index.json @@ -32,7 +32,7 @@ "id": "stylized_tree_generator", "name": "Stylized Tree Generator", "tagline": "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen", - "version": "1.7.0", + "version": "1.8.0", "type": "add-on", "maintainer": "D4rkst3r", "license": [ @@ -48,9 +48,9 @@ "Mesh", "Modeling" ], - "archive_url": "./stylized_tree_generator-1.7.0.zip", - "archive_size": 13398, - "archive_hash": "sha256:3817ce7433ef63918ddf75a827591b3bb712c8659141ae85f73f4f1fd19e20fb" + "archive_url": "./stylized_tree_generator-1.8.0.zip", + "archive_size": 13440, + "archive_hash": "sha256:e96e6ec6f8009708ce0611dea6ea50e3271b6603d60bce84ebeab2e365bba983" } ] } \ No newline at end of file diff --git a/dist/stylized_tree_generator-1.7.0.zip b/dist/stylized_tree_generator-1.7.0.zip deleted file mode 100644 index 197f40d542c1b444a51abddec81efa2a67f53e98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13398 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 diff --git a/dist/stylized_tree_generator-1.8.0.zip b/dist/stylized_tree_generator-1.8.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..9090f97ad70c631b547d9a4fee7646e732f8e8ec GIT binary patch literal 13440 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 Sidebar > Tree Gen", "description": "Parametrischer Baum-/Palmen-/Busch-Generator (Geometry Nodes) mit Wachstums-Stufen", @@ -43,7 +43,9 @@ DEFAULTS = { "Sub Count": 2, # Sub-Aeste je Hauptast (0 = aus) "Sub Length": 0.55, "Sub Up": 1.4, - "Sides": 5, + "Sides": 8, # Stamm rund (Referenz TreeIt: ~9) + "Branch Sides": 4, # Aeste sparsamer + "Sub Sides": 3, # Zweige nur Dreiecke - sieht man nicht "UV Scale": 1.0, # Rinden-Dichte; UVs sind world-space (m) "Tip Blunt": 0.18, # >0 verhindert Nadelspitzen (0 = spitz, 0.45 = Kaktus) "Root Flare": 1.1, # Wurzelanlauf: Stamm verbreitert sich am Fuss @@ -86,7 +88,7 @@ PRESETS = { "Branch Taper": 0.12, # Arme bleiben dick statt spitz zuzulaufen "Sub Count": 0, "Tip Blunt": 0.45, - "Sides": 18, "Ribs": 9.0, "Rib Depth": 0.09, + "Sides": 16, "Branch Sides": 12, "Ribs": 9.0, "Rib Depth": 0.09, }, } # =========================================================================== @@ -166,6 +168,8 @@ def build_group(): add_in("Sub Length", 'NodeSocketFloat', DEFAULTS["Sub Length"], 0.05, 5.0) add_in("Sub Up", 'NodeSocketFloat', DEFAULTS["Sub Up"], -3.0, 3.0) add_in("Sides", 'NodeSocketInt', DEFAULTS["Sides"], 3, 32) + add_in("Branch Sides", 'NodeSocketInt', DEFAULTS["Branch Sides"], 3, 16) + add_in("Sub Sides", 'NodeSocketInt', DEFAULTS["Sub Sides"], 3, 12) add_in("Tip Blunt", 'NodeSocketFloat', DEFAULTS["Tip Blunt"], 0.0, 0.9) add_in("UV Scale", 'NodeSocketFloat', DEFAULTS["UV Scale"], 0.01, 20.0) add_in("Detail", 'NodeSocketFloat', DEFAULTS["Detail"], 0.2, 2.0) @@ -573,108 +577,102 @@ def build_group(): L(_out(sreal, "Geometry"), _sock(sbset, "Geometry")) L(sboff.outputs[0], _sock(sbset, "Offset")) - join = N("GeometryNodeJoinGeometry"); join.location = (3150, 200) - L(_out(sbset, "Geometry"), join.inputs[0]) - L(_out(rsetp, "Geometry"), join.inputs[0]) - L(_out(setrad, "Curve"), join.inputs[0]) + # ---------- Curve -> Mesh, PRO EBENE mit eigener Profilaufloesung ---------- + # Referenz (TreeIt): Stamm ~9 Segmente, duenne Zweige nur Dreiecke. Ein + # "Curve to Mesh" kennt aber nur EIN Profil -> deshalb wird jede Ebene + # einzeln gewandelt und erst danach zusammengefuegt. Spart massiv Tris, + # weil die vielen duennen Zweige nicht die Rundung des Stammes brauchen. + def _profile(sides_socket, x, y): + c = N("GeometryNodeCurvePrimitiveCircle"); c.location = (x, y) + L(sides_socket, _sock(c, "Resolution")) + _sock(c, "Radius").default_value = 1.0 + # Rippen (Kaktus-Kanneluren): radiale Welle auf dem Profil + sp = N("GeometryNodeSplineParameter"); sp.location = (x, y - 200) + ang = N("ShaderNodeMath"); ang.location = (x + 150, y - 200); ang.operation = 'MULTIPLY' + ang.inputs[1].default_value = 6.283185 + L(sp.outputs["Factor"], ang.inputs[0]) + rb = N("ShaderNodeMath"); rb.location = (x + 300, y - 200); rb.operation = 'MULTIPLY' + L(ang.outputs[0], rb.inputs[0]); L(V["Ribs"], rb.inputs[1]) + co = N("ShaderNodeMath"); co.location = (x + 450, y - 200); co.operation = 'COSINE' + L(rb.outputs[0], co.inputs[0]) + am = N("ShaderNodeMath"); am.location = (x + 600, y - 200); am.operation = 'MULTIPLY' + L(co.outputs[0], am.inputs[0]); L(V["Rib Depth"], am.inputs[1]) + po = N("GeometryNodeInputPosition"); po.location = (x + 300, y - 340) + dn = N("ShaderNodeVectorMath"); dn.location = (x + 450, y - 340); dn.operation = 'NORMALIZE' + L(po.outputs[0], dn.inputs[0]) + of = N("ShaderNodeVectorMath"); of.location = (x + 750, y - 300); of.operation = 'SCALE' + L(dn.outputs[0], of.inputs[0]); L(am.outputs[0], _sock(of, "Scale")) + st = N("GeometryNodeSetPosition"); st.location = (x + 900, y) + L(_out(c, "Curve"), _sock(st, "Geometry")); L(of.outputs[0], _sock(st, "Offset")) + # uv_u = Bogenlaenge um das Profil + sp2 = N("GeometryNodeSplineParameter"); sp2.location = (x + 900, y - 200) + su = N("GeometryNodeStoreNamedAttribute"); su.location = (x + 1050, y) + su.domain = 'POINT'; su.data_type = 'FLOAT' + L(_out(st, "Geometry"), _sock(su, "Geometry")) + _sock(su, "Name").default_value = "uv_u" + L(sp2.outputs["Length"], _sock(su, "Value")) + return su - # ---------- Curve -> Mesh ---------- - # Falle 6: Der Profil-Radius wird mit dem Curve-Radius MULTIPLIZIERT. - # Profil deshalb auf 1.0 lassen waere richtig -- aber nur, wenn der - # Curve-Radius bereits die echte Staerke ist. Hier ist er das, also 1.0. - circ = N("GeometryNodeCurvePrimitiveCircle"); circ.location = (1350, -100) - L(V["Sides"], _sock(circ, "Resolution")) - _sock(circ, "Radius").default_value = 1.0 + def _to_mesh(curve_node, curve_out_name, sides_socket, x, y): + """Kurven -> Mesh inkl. world-space UVs. Pro Ast-Ebene einmal.""" + cs = N("GeometryNodeSplineParameter"); cs.location = (x, y - 140) + sv = N("GeometryNodeStoreNamedAttribute"); sv.location = (x + 150, y) + sv.domain = 'POINT'; sv.data_type = 'FLOAT' + L(_out(curve_node, curve_out_name), _sock(sv, "Geometry")) + _sock(sv, "Name").default_value = "uv_v" + L(cs.outputs["Length"], _sock(sv, "Value")) + rd = N("GeometryNodeInputRadius"); rd.location = (x, y - 280) + sw = N("GeometryNodeStoreNamedAttribute"); sw.location = (x + 300, y) + sw.domain = 'POINT'; sw.data_type = 'FLOAT' + L(_out(sv, "Geometry"), _sock(sw, "Geometry")) + _sock(sw, "Name").default_value = "uv_r" + L(rd.outputs[0], _sock(sw, "Value")) - # ---------- Rippen (senkrechte Kanneluren, Kaktus-Signatur) ---------- - # Das Profil bekommt eine radiale Welle: Offset entlang der Punktrichtung, - # moduliert mit cos(Rippen * Winkel). Rib Depth = 0 -> glatter Kreis. - pspar = N("GeometryNodeSplineParameter"); pspar.location = (1350, -420) - pang = N("ShaderNodeMath"); pang.location = (1500, -420); pang.operation = 'MULTIPLY' - pang.inputs[1].default_value = 6.283185 - L(pspar.outputs["Factor"], pang.inputs[0]) - pribs = N("ShaderNodeMath"); pribs.location = (1650, -420); pribs.operation = 'MULTIPLY' - L(pang.outputs[0], pribs.inputs[0]) - L(V["Ribs"], pribs.inputs[1]) - pcos = N("ShaderNodeMath"); pcos.location = (1800, -420); pcos.operation = 'COSINE' - L(pribs.outputs[0], pcos.inputs[0]) - pamp = N("ShaderNodeMath"); pamp.location = (1950, -420); pamp.operation = 'MULTIPLY' - L(pcos.outputs[0], pamp.inputs[0]) - L(V["Rib Depth"], pamp.inputs[1]) - ppos = N("GeometryNodeInputPosition"); ppos.location = (1650, -560) - pdir = N("ShaderNodeVectorMath"); pdir.location = (1800, -560) - pdir.operation = 'NORMALIZE' - L(ppos.outputs[0], pdir.inputs[0]) - poff = N("ShaderNodeVectorMath"); poff.location = (2100, -520) - poff.operation = 'SCALE' - L(pdir.outputs[0], poff.inputs[0]) - L(pamp.outputs[0], _sock(poff, "Scale")) - pset = N("GeometryNodeSetPosition"); pset.location = (2250, -100) - L(_out(circ, "Curve"), _sock(pset, "Geometry")) - L(poff.outputs[0], _sock(pset, "Offset")) + prof = _profile(sides_socket, x - 1100, y - 500) - # ---------- UVs (Curve to Mesh erzeugt KEINE - gemessen!) ---------- - # V = echte Bogenlaenge entlang Stamm/Ast, U = Bogenlaenge um das Profil mal - # Radius => world-space UVs: Rinde sitzt auf dickem Stamm und duennem Zweig - # gleich dicht. Attribute VOR Curve to Mesh ablegen, danach kombinieren. - cspar = N("GeometryNodeSplineParameter"); cspar.location = (2250, 60) - stv = N("GeometryNodeStoreNamedAttribute"); stv.location = (2400, 200) - stv.domain = 'POINT'; stv.data_type = 'FLOAT' - L(_out(join, "Geometry"), _sock(stv, "Geometry")) - _sock(stv, "Name").default_value = "uv_v" - L(cspar.outputs["Length"], _sock(stv, "Value")) + cm = N("GeometryNodeCurveToMesh"); cm.location = (x + 500, y) + L(_out(sw, "Geometry"), _sock(cm, "Curve")) + L(_out(prof, "Geometry"), _sock(cm, "Profile Curve")) + # Falle 7 (Blender 5.x): Radius-Attribut wird NICHT mehr implizit + # ausgewertet -> muss an den "Scale"-Eingang. + if "Scale" in cm.inputs: + ra = N("GeometryNodeInputRadius"); ra.location = (x + 350, y - 420) + L(ra.outputs[0], _sock(cm, "Scale")) + try: + _sock(cm, "Fill Caps").default_value = True + except KeyError: + pass - crad = N("GeometryNodeInputRadius"); crad.location = (2250, -80) - stw = N("GeometryNodeStoreNamedAttribute"); stw.location = (2550, 200) - stw.domain = 'POINT'; stw.data_type = 'FLOAT' - L(_out(stv, "Geometry"), _sock(stw, "Geometry")) - _sock(stw, "Name").default_value = "uv_r" - L(crad.outputs[0], _sock(stw, "Value")) + nu = N("GeometryNodeInputNamedAttribute"); nu.location = (x + 500, y - 200) + nu.data_type = 'FLOAT'; _sock(nu, "Name").default_value = "uv_u" + nv = N("GeometryNodeInputNamedAttribute"); nv.location = (x + 500, y - 320) + nv.data_type = 'FLOAT'; _sock(nv, "Name").default_value = "uv_v" + nr = N("GeometryNodeInputNamedAttribute"); nr.location = (x + 500, y - 440) + nr.data_type = 'FLOAT'; _sock(nr, "Name").default_value = "uv_r" + um = N("ShaderNodeMath"); um.location = (x + 650, y - 200); um.operation = 'MULTIPLY' + L(_out(nu, "Attribute"), um.inputs[0]); L(_out(nr, "Attribute"), um.inputs[1]) + us_ = N("ShaderNodeMath"); us_.location = (x + 800, y - 200); us_.operation = 'MULTIPLY' + L(um.outputs[0], us_.inputs[0]); L(V["UV Scale"], us_.inputs[1]) + vs_ = N("ShaderNodeMath"); vs_.location = (x + 800, y - 320); vs_.operation = 'MULTIPLY' + L(_out(nv, "Attribute"), vs_.inputs[0]); L(V["UV Scale"], vs_.inputs[1]) + uv = N("ShaderNodeCombineXYZ"); uv.location = (x + 950, y - 260) + L(us_.outputs[0], uv.inputs["X"]); L(vs_.outputs[0], uv.inputs["Y"]) + sm = N("GeometryNodeStoreNamedAttribute"); sm.location = (x + 1100, y) + sm.domain = 'CORNER'; sm.data_type = 'FLOAT2' + L(_out(cm, "Mesh", "Geometry"), _sock(sm, "Geometry")) + _sock(sm, "Name").default_value = "UVMap" + L(uv.outputs[0], _sock(sm, "Value")) + return sm - pspar2 = N("GeometryNodeSplineParameter"); pspar2.location = (2250, -700) - stu = N("GeometryNodeStoreNamedAttribute"); stu.location = (2400, -100) - stu.domain = 'POINT'; stu.data_type = 'FLOAT' - L(_out(pset, "Geometry"), _sock(stu, "Geometry")) - _sock(stu, "Name").default_value = "uv_u" - L(pspar2.outputs["Length"], _sock(stu, "Value")) + mesh_trunk = _to_mesh(setrad, "Curve", V["Sides"], 3400, 900) + mesh_branch = _to_mesh(rsetp, "Geometry", V["Branch Sides"], 3400, 200) + mesh_sub = _to_mesh(sbset, "Geometry", V["Sub Sides"], 3400, -500) - c2m = N("GeometryNodeCurveToMesh"); c2m.location = (1500, 200) - L(_out(stw, "Geometry"), _sock(c2m, "Curve")) - L(_out(stu, "Geometry"), _sock(c2m, "Profile Curve")) - # Falle 7 (Blender 5.x!): "Curve to Mesh" wertet das Radius-Attribut NICHT - # mehr implizit aus, sondern hat einen eigenen "Scale"-Eingang. Ohne diese - # Verbindung bleibt der Stamm immer bei Profil-Radius 1.0 (= 2 m dick), - # egal was "Trunk Radius" sagt. Gemessen: Stammbreite konstant 1.995. - if "Scale" in c2m.inputs: - radattr = N("GeometryNodeInputRadius"); radattr.location = (1350, -260) - L(radattr.outputs[0], _sock(c2m, "Scale")) - try: - _sock(c2m, "Fill Caps").default_value = True - except KeyError: - pass - - # UVMap aus den drei Attributen zusammensetzen (FACE_CORNER, sonst kein UV) - na_u = N("GeometryNodeInputNamedAttribute"); na_u.location = (2700, -300) - na_u.data_type = 'FLOAT'; _sock(na_u, "Name").default_value = "uv_u" - na_v = N("GeometryNodeInputNamedAttribute"); na_v.location = (2700, -420) - na_v.data_type = 'FLOAT'; _sock(na_v, "Name").default_value = "uv_v" - na_r = N("GeometryNodeInputNamedAttribute"); na_r.location = (2700, -540) - na_r.data_type = 'FLOAT'; _sock(na_r, "Name").default_value = "uv_r" - - umul = N("ShaderNodeMath"); umul.location = (2880, -300); umul.operation = 'MULTIPLY' - L(_out(na_u, "Attribute"), umul.inputs[0]); L(_out(na_r, "Attribute"), umul.inputs[1]) - us = N("ShaderNodeMath"); us.location = (3030, -300); us.operation = 'MULTIPLY' - L(umul.outputs[0], us.inputs[0]); L(V["UV Scale"], us.inputs[1]) - vs = N("ShaderNodeMath"); vs.location = (3030, -420); vs.operation = 'MULTIPLY' - L(_out(na_v, "Attribute"), vs.inputs[0]); L(V["UV Scale"], vs.inputs[1]) - uvvec = N("ShaderNodeCombineXYZ"); uvvec.location = (3180, -360) - L(us.outputs[0], uvvec.inputs["X"]); L(vs.outputs[0], uvvec.inputs["Y"]) - - stuv = N("GeometryNodeStoreNamedAttribute"); stuv.location = (1650, 60) - stuv.domain = 'CORNER'; stuv.data_type = 'FLOAT2' - L(_out(c2m, "Mesh", "Geometry"), _sock(stuv, "Geometry")) - _sock(stuv, "Name").default_value = "UVMap" - L(uvvec.outputs[0], _sock(stuv, "Value")) + join = N("GeometryNodeJoinGeometry"); join.location = (4700, 300) + L(_out(mesh_sub, "Geometry"), join.inputs[0]) + L(_out(mesh_branch, "Geometry"), join.inputs[0]) + L(_out(mesh_trunk, "Geometry"), join.inputs[0]) + stuv = join # Name beibehalten fuer den nachfolgenden Merge-Zweig # ---------- optional: Aeste mit dem Stamm VERSCHMELZEN ---------- # Voxel-Remesh (Mesh to Volume -> Volume to Mesh) macht aus den sich