Tree Generator v1.10.0: Kronenform + 5 neue Baum-Varianten
Crown Taper / Crown Bulge steuern die botanische Huellkurve (kegelfoermig bis rund) - damit sind Tanne, Eiche, Birke, Weide und toter Baum als Presets moeglich. Alle neun Presets liegen im Tri-Budget des Projekts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
bl_info = {
|
||||
"name": "Stylized Tree Generator",
|
||||
"author": "D4rkst3r",
|
||||
"version": (1, 9, 0),
|
||||
"version": (1, 10, 0),
|
||||
"blender": (4, 2, 0),
|
||||
"location": "View3D > Sidebar > Tree Gen",
|
||||
"description": "Parametrischer Baum-/Palmen-/Busch-Generator (Geometry Nodes) mit Wachstums-Stufen",
|
||||
@@ -49,6 +49,8 @@ DEFAULTS = {
|
||||
"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)
|
||||
"Crown Taper": 0.35, # >0 kegelfoermig, 0 saeulig, <0 besenfoermig
|
||||
"Crown Bulge": 0.0, # >0 = Bauch in der Mitte (runde Krone)
|
||||
"Root Flare": 1.1, # Wurzelanlauf: Stamm verbreitert sich am Fuss
|
||||
"Root Lobes": 6.0, # Wurzelbretter; sollte in "Sides" aufgehen,
|
||||
# sonst sampelt das Profil die Lappen weg
|
||||
@@ -82,6 +84,47 @@ PRESETS = {
|
||||
"Sub Count": 1, "Sub Length": 0.35, "Sub Up": 1.6, "Sides": 4,
|
||||
"Detail": 0.3, "Branch Count": 10,
|
||||
},
|
||||
# --- Varianten ueber die Kronenform (Idee: modular_tree "envelope shapes") ---
|
||||
"tanne": { # kegelfoermig: unten lange Aeste, oben kurz, leicht haengend
|
||||
"Height": 7.0, "Trunk Radius": 0.15, "Bend": 0.15, "Taper": 0.95,
|
||||
"Branch Count": 22, "Branch Length": 1.9, "Branch Up": -0.25,
|
||||
"Branch Start": 0.12, "Branch End": 0.97,
|
||||
"Crown Taper": 0.9, "Crown Bulge": 0.0,
|
||||
"Branch Bend": 0.3, "Branch Thickness": 0.2, "Sub Count": 1,
|
||||
"Sub Length": 0.4, "Root Flare": 0.7,
|
||||
},
|
||||
"eiche": { # runde, breite Krone: Bauch in der Mitte, dicker Stamm
|
||||
"Height": 5.5, "Trunk Radius": 0.24, "Bend": 0.5, "Taper": 0.75,
|
||||
"Branch Count": 10, "Branch Length": 2.2, "Branch Up": 0.9,
|
||||
"Branch Start": 0.3, "Branch End": 0.95,
|
||||
"Crown Taper": -0.15, "Crown Bulge": 0.5,
|
||||
"Branch Bend": 0.9, "Branch Thickness": 0.4, "Sub Count": 3,
|
||||
"Sub Length": 0.8, "Root Flare": 1.6, "Root Lobe Depth": 1.6,
|
||||
},
|
||||
"birke": { # schlank, hoher Ansatz, feine Zweige
|
||||
"Height": 7.5, "Trunk Radius": 0.09, "Bend": 0.7, "Taper": 0.92,
|
||||
"Branch Count": 12, "Branch Length": 1.4, "Branch Up": 1.1,
|
||||
"Branch Start": 0.45, "Branch End": 0.98,
|
||||
"Crown Taper": 0.1, "Crown Bulge": 0.25,
|
||||
"Branch Bend": 0.8, "Branch Thickness": 0.22, "Sub Count": 3,
|
||||
"Sub Length": 0.5, "Root Flare": 0.6,
|
||||
},
|
||||
"weide": { # haengende Zweige (Droop positiv), breit ausladend
|
||||
"Height": 5.0, "Trunk Radius": 0.18, "Bend": 0.8, "Taper": 0.8,
|
||||
"Branch Count": 12, "Branch Length": 2.0, "Branch Up": 0.5,
|
||||
"Branch Start": 0.35, "Branch End": 0.95,
|
||||
"Crown Taper": -0.2, "Crown Bulge": 0.4,
|
||||
"Branch Droop": 1.2, "Branch Bend": 0.7, "Branch Thickness": 0.28,
|
||||
"Sub Count": 3, "Sub Length": 0.9, "Root Flare": 1.2,
|
||||
},
|
||||
"toter_baum": { # knorrig, kaum Zweige, starke Kruemmung
|
||||
"Height": 4.5, "Trunk Radius": 0.17, "Bend": 1.5, "Taper": 0.88,
|
||||
"Branch Count": 6, "Branch Length": 1.5, "Branch Up": 0.9,
|
||||
"Branch Start": 0.3, "Branch End": 0.9,
|
||||
"Crown Taper": 0.3, "Crown Bulge": 0.0,
|
||||
"Branch Bend": 1.4, "Branch Thickness": 0.3, "Sub Count": 1,
|
||||
"Sub Length": 0.5, "Root Flare": 1.4, "Tip Blunt": 0.08,
|
||||
},
|
||||
# Kaktus: dicker, kaum verjuengter Stamm, wenige Arme, die per NEGATIVEM
|
||||
# Droop nach oben kruemmen (Saguaro-Silhouette). Keine Sub-Aeste.
|
||||
"kaktus": {
|
||||
@@ -179,6 +222,8 @@ def build_group():
|
||||
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)
|
||||
add_in("Crown Taper", 'NodeSocketFloat', DEFAULTS["Crown Taper"], -1.5, 1.5)
|
||||
add_in("Crown Bulge", 'NodeSocketFloat', DEFAULTS["Crown Bulge"], -1.0, 2.0)
|
||||
add_in("Root Flare", 'NodeSocketFloat', DEFAULTS["Root Flare"], 0.0, 4.0)
|
||||
add_in("Root Lobes", 'NodeSocketFloat', DEFAULTS["Root Lobes"], 0.0, 12.0)
|
||||
add_in("Root Lobe Depth", 'NodeSocketFloat', DEFAULTS["Root Lobe Depth"], 0.0, 3.0)
|
||||
@@ -422,10 +467,50 @@ def build_group():
|
||||
pscale.inputs["To Max"].default_value = 1.0
|
||||
pscale.clamp = True
|
||||
|
||||
# ---------- Kronenform (botanische Huellkurve) ----------
|
||||
# Idee aus modular_tree / Weber-Penn: die Astlaenge haengt von der relativen
|
||||
# Hoehe am Stamm ab. Das entscheidet die Silhouette:
|
||||
# Crown Taper > 0 -> unten lang, oben kurz = kegelfoermig (Tanne)
|
||||
# Crown Taper = 0 -> ueberall gleich = saeulenfoermig (Pappel)
|
||||
# Crown Taper < 0 -> unten kurz, oben lang = besenfoermig
|
||||
# Crown Bulge > 0 -> Maximum in der Mitte = rund (Eiche)
|
||||
czp = N("GeometryNodeInputPosition"); czp.location = (750, -20)
|
||||
czs = N("ShaderNodeSeparateXYZ"); czs.location = (900, -20)
|
||||
L(czp.outputs[0], czs.inputs[0])
|
||||
czn = N("ShaderNodeMath"); czn.location = (1050, -20); czn.operation = 'DIVIDE'
|
||||
L(czs.outputs["Z"], czn.inputs[0]); L(V["Height"], czn.inputs[1])
|
||||
czc = N("ShaderNodeMath"); czc.location = (1200, -20); czc.operation = 'MINIMUM'
|
||||
czc.inputs[1].default_value = 1.0
|
||||
L(czn.outputs[0], czc.inputs[0])
|
||||
ctm = N("ShaderNodeMath"); ctm.location = (1350, -20); ctm.operation = 'MULTIPLY'
|
||||
L(V["Crown Taper"], ctm.inputs[0]); L(czc.outputs[0], ctm.inputs[1])
|
||||
cts = N("ShaderNodeMath"); cts.location = (1500, -20); cts.operation = 'SUBTRACT'
|
||||
cts.inputs[0].default_value = 1.0
|
||||
L(ctm.outputs[0], cts.inputs[1])
|
||||
# Bauch in der Mitte: sin(pi * t)
|
||||
cbs = N("ShaderNodeMath"); cbs.location = (1350, -180); cbs.operation = 'MULTIPLY'
|
||||
cbs.inputs[1].default_value = 3.14159
|
||||
L(czc.outputs[0], cbs.inputs[0])
|
||||
cbi = N("ShaderNodeMath"); cbi.location = (1500, -180); cbi.operation = 'SINE'
|
||||
L(cbs.outputs[0], cbi.inputs[0])
|
||||
cbm = N("ShaderNodeMath"); cbm.location = (1650, -180); cbm.operation = 'MULTIPLY'
|
||||
L(V["Crown Bulge"], cbm.inputs[0]); L(cbi.outputs[0], cbm.inputs[1])
|
||||
cba = N("ShaderNodeMath"); cba.location = (1800, -180); cba.operation = 'ADD'
|
||||
cba.inputs[0].default_value = 1.0
|
||||
L(cbm.outputs[0], cba.inputs[1])
|
||||
ccm = N("ShaderNodeMath"); ccm.location = (1800, -20); ccm.operation = 'MULTIPLY'
|
||||
L(cts.outputs[0], ccm.inputs[0]); L(cba.outputs[0], ccm.inputs[1])
|
||||
ccl = N("ShaderNodeMath"); ccl.location = (1950, -20); ccl.operation = 'MAXIMUM'
|
||||
ccl.inputs[1].default_value = 0.05
|
||||
L(ccm.outputs[0], ccl.inputs[0])
|
||||
# mit der Elterndicken-Skalierung kombinieren
|
||||
pfin = N("ShaderNodeMath"); pfin.location = (2100, 120); pfin.operation = 'MULTIPLY'
|
||||
L(pscale.outputs[0], pfin.inputs[0]); L(ccl.outputs[0], pfin.inputs[1])
|
||||
|
||||
inst = N("GeometryNodeInstanceOnPoints"); inst.location = (1400, 320)
|
||||
L(_out(c2p, "Points"), _sock(inst, "Points"))
|
||||
L(_out(bsetr, "Curve"), _sock(inst, "Instance"))
|
||||
L(pscale.outputs[0], _sock(inst, "Scale"))
|
||||
L(pfin.outputs[0], _sock(inst, "Scale"))
|
||||
if align is not None:
|
||||
L(align.outputs[0], _sock(inst, "Rotation"))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user