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:
2026-07-29 11:27:50 +02:00
co-authored by Claude Opus 4.8
parent e3ad1727b6
commit d9c642fcd2
6 changed files with 98 additions and 8 deletions
+6 -1
View File
@@ -17,7 +17,12 @@
Parametrischer **Geaest**-Generator (Stamm + Aeste + Sub-Aeste) als Geometry-Nodes-
Gruppe. Blaetter/Krone macht man selbst — das Addon liefert die Struktur.
- **Presets:** `baum`, `palme`, `busch`, `kaktus`
- **Presets:** `baum`, `palme`, `busch`, `tanne`, `eiche`, `birke`, `weide`,
`toter_baum`, `kaktus` — die Silhouette steuert die **Kronenform**
(`Crown Taper` / `Crown Bulge`, Idee aus modular_tree / Weber-Penn).
- **Tri-Budget:** alle Presets liegen unter dem Projektlimit (Baum ≤2500,
Busch ≤800). Stellschrauben: `Detail` (Segmente) und `Sides` / `Branch Sides` /
`Sub Sides` (Profilaufloesung je Ebene — Stamm rund, Zweige nur Dreiecke).
- **Wachstums-Stufen:** Haken setzen + Anzahl waehlen → Setzling bis ausgewachsen,
**gleicher Seed = dieselbe Baum-Identitaet** (fuer Wachstums-Systeme im Spiel).
- **Live bearbeiten:** Nach dem Erzeugen liegen alle Regler am Modifier `GN_Tree`
+1 -1
View File
@@ -1,7 +1,7 @@
schema_version = "1.0.0"
id = "stylized_tree_generator"
version = "1.9.0"
version = "1.10.0"
name = "Stylized Tree Generator"
tagline = "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen"
maintainer = "D4rkst3r"
+4 -4
View File
@@ -32,7 +32,7 @@
"id": "stylized_tree_generator",
"name": "Stylized Tree Generator",
"tagline": "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen",
"version": "1.9.0",
"version": "1.10.0",
"type": "add-on",
"maintainer": "D4rkst3r",
"license": [
@@ -48,9 +48,9 @@
"Mesh",
"Modeling"
],
"archive_url": "./stylized_tree_generator-1.9.0.zip",
"archive_size": 14478,
"archive_hash": "sha256:07c964096cd907dab9e22e1bc936621ed25476e188ebaa6176a18e98c5f76a4c"
"archive_url": "./stylized_tree_generator-1.10.0.zip",
"archive_size": 15650,
"archive_hash": "sha256:995b37759449eab7f767bc87dcd7917bdac4382c3a2a8d37e1e0c9dc9d11eb30"
}
]
}
Binary file not shown.
Binary file not shown.
+87 -2
View File
@@ -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"))