diff --git a/blender_manifest_tree.toml b/blender_manifest_tree.toml index 5b5be0b..502829f 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.3.0" +version = "1.4.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 479b63d..67429f5 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.3.0", + "version": "1.4.0", "type": "add-on", "maintainer": "D4rkst3r", "license": [ @@ -48,9 +48,9 @@ "Mesh", "Modeling" ], - "archive_url": "./stylized_tree_generator-1.3.0.zip", - "archive_size": 10852, - "archive_hash": "sha256:31c7a72133a6c28d24f95d661cabf0be56dc00c3102ad57a4a3c1e1c5a30bcd4" + "archive_url": "./stylized_tree_generator-1.4.0.zip", + "archive_size": 11373, + "archive_hash": "sha256:421a702f2e5b088988db638dd7cbfb49de8126397476cfe192441bf069983c55" } ] } \ No newline at end of file diff --git a/dist/stylized_tree_generator-1.3.0.zip b/dist/stylized_tree_generator-1.3.0.zip deleted file mode 100644 index 5d0dc28..0000000 Binary files a/dist/stylized_tree_generator-1.3.0.zip and /dev/null differ diff --git a/dist/stylized_tree_generator-1.4.0.zip b/dist/stylized_tree_generator-1.4.0.zip new file mode 100644 index 0000000..52cb92a Binary files /dev/null and b/dist/stylized_tree_generator-1.4.0.zip differ diff --git a/stylized_tree_generator.py b/stylized_tree_generator.py index 096b44a..48409e0 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, 3, 0), + "version": (1, 4, 0), "blender": (4, 2, 0), "location": "View3D > Sidebar > Tree Gen", "description": "Parametrischer Baum-/Palmen-/Busch-Generator (Geometry Nodes) mit Wachstums-Stufen", @@ -36,10 +36,10 @@ DEFAULTS = { "Branch Up": 1.3, # >1 = Aeste zeigen nach oben; negativ = haengend "Branch Start": 0.35, # ab wo am Stamm Aeste sitzen (0..1) "Branch End": 0.95, - "Branch Bend": 0.45, # Variation je Ast (0 = gerade Staebe) + "Branch Bend": 0.75, # Krummheit je Ast/Zweig (0 = gerade Staebe) "Branch Droop": 0.0, # >0 haengt nach unten (Palme), <0 kruemmt nach oben (Kaktus) "Branch Thickness": 0.32, # Ast-Dicke relativ zum Stamm - "Branch Taper": 0.85, # wie der Stamm: laeuft NICHT auf 0 -> keine Nadeln + "Branch Taper": 0.55, # schwach verjuengen -> Roehre statt Kegel/Dorn "Sub Count": 3, # Sub-Aeste je Hauptast (0 = aus) "Sub Length": 0.55, "Sub Up": 1.4, @@ -403,20 +403,24 @@ def build_group(): L(V["Sub Length"], stop.inputs["Z"]) L(stop.outputs[0], _sock(sline, "End")) sres = N("GeometryNodeResampleCurve"); sres.location = (2250, 760) - _sock(sres, "Count").default_value = 6 + _sock(sres, "Count").default_value = 9 # genug Punkte, damit die Biegung sichtbar wird L(_out(sline, "Curve"), _sock(sres, "Curve")) # Sub-Aeste: gleiche Verjuengungs-Logik wie Hauptaeste (Branch Taper + Kuppel). # Vorher lief der Radius hier hart auf 0 -> die Sub-Aeste wurden zu Nadeln. sspar = N("GeometryNodeSplineParameter"); sspar.location = (2250, 900) + # ... und verjuengen sich nur SCHWACH. Ein dicker Ansatz, der spitz zulaeuft, + # ist genau die Dorn-Form - ein echter Zweig ist duenn und gleichmaessig. + shalf = N("ShaderNodeMath"); shalf.location = (2180, 1000); shalf.operation = 'MULTIPLY' + L(V["Branch Taper"], shalf.inputs[0]); shalf.inputs[1].default_value = 0.35 stap = N("ShaderNodeMath"); stap.location = (2330, 1000); stap.operation = 'MULTIPLY' - L(V["Branch Taper"], stap.inputs[0]); L(sspar.outputs["Factor"], stap.inputs[1]) + L(shalf.outputs[0], stap.inputs[0]); L(sspar.outputs["Factor"], stap.inputs[1]) sinv = N("ShaderNodeMath"); sinv.location = (2400, 900) sinv.operation = 'SUBTRACT'; sinv.inputs[0].default_value = 1.0 L(stap.outputs[0], sinv.inputs[1]) sbase = N("ShaderNodeMath"); sbase.location = (2550, 900); sbase.operation = 'MULTIPLY' L(V["Trunk Radius"], sbase.inputs[0]) - sbase.inputs[1].default_value = 0.32 # duenner als Hauptaeste, aber keine Nadel + sbase.inputs[1].default_value = 0.12 # Zweige sind DUENN ... sdome = _dome(sspar, 2550, 1200) srad2 = _shape(sinv.outputs[0], sdome, sbase.outputs[0], 2750, 900) ssetr = N("GeometryNodeSetCurveRadius"); ssetr.location = (2550, 760) @@ -443,8 +447,36 @@ def build_group(): sreal = N("GeometryNodeRealizeInstances"); sreal.location = (3000, 520) L(_out(sinst, "Instances", "Geometry"), _sock(sreal, "Geometry")) + # Sub-Aeste genauso biegen wie Stamm und Hauptaeste. Ohne diesen Schritt + # blieben sie schnurgerade - das ist der Grund, warum sie wie angeklebte + # Staebe wirkten. Auch hier NACH dem Realize, damit die Weltposition jedem + # Zweig ein eigenes Noise gibt (sonst biegen alle identisch). + sbspar = N("GeometryNodeSplineParameter"); sbspar.location = (3000, 300) + sbpos = N("GeometryNodeInputPosition"); sbpos.location = (3000, 160) + sbnoise = N("ShaderNodeTexNoise"); sbnoise.location = (3150, 160) + sbnoise.noise_dimensions = '4D' + _sock(sbnoise, "Scale").default_value = 1.6 + L(sbpos.outputs[0], _sock(sbnoise, "Vector")) + L(V["Seed"], _sock(sbnoise, "W")) + sbsub = N("ShaderNodeVectorMath"); sbsub.location = (3320, 160) + sbsub.operation = 'SUBTRACT'; sbsub.inputs[1].default_value = (0.5, 0.5, 0.5) + L(sbnoise.outputs["Color"], sbsub.inputs[0]) + sbfac = N("ShaderNodeMath"); sbfac.location = (3150, 300); sbfac.operation = 'MULTIPLY' + L(V["Branch Bend"], sbfac.inputs[0]) + L(sbspar.outputs["Factor"], sbfac.inputs[1]) + sbamt = N("ShaderNodeMath"); sbamt.location = (3320, 300); sbamt.operation = 'MULTIPLY' + sbamt.inputs[1].default_value = 0.5 # Zweige biegen etwas weniger als Aeste + L(sbfac.outputs[0], sbamt.inputs[0]) + sboff = N("ShaderNodeVectorMath"); sboff.location = (3480, 220) + sboff.operation = 'SCALE' + L(sbsub.outputs[0], sboff.inputs[0]) + L(sbamt.outputs[0], _sock(sboff, "Scale")) + sbset = N("GeometryNodeSetPosition"); sbset.location = (3640, 520) + L(_out(sreal, "Geometry"), _sock(sbset, "Geometry")) + L(sboff.outputs[0], _sock(sbset, "Offset")) + join = N("GeometryNodeJoinGeometry"); join.location = (3150, 200) - L(_out(sreal, "Geometry"), join.inputs[0]) + L(_out(sbset, "Geometry"), join.inputs[0]) L(_out(rsetp, "Geometry"), join.inputs[0]) L(_out(setrad, "Curve"), join.inputs[0])