Tree Generator v1.7.0: Tri-Budget, Detail-Regler, Wurzelanlauf
- 'Detail' skaliert alle Resample-Counts -> zentrale Budget-Stellschraube - Defaults treffen jetzt das Projekt-Budget (baum 1368, busch 532 Tris) - 'Root Flare': Wurzelanlauf am Stammfuss, kostet keine Tris Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
schema_version = "1.0.0"
|
schema_version = "1.0.0"
|
||||||
|
|
||||||
id = "stylized_tree_generator"
|
id = "stylized_tree_generator"
|
||||||
version = "1.6.0"
|
version = "1.7.0"
|
||||||
name = "Stylized Tree Generator"
|
name = "Stylized Tree Generator"
|
||||||
tagline = "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen"
|
tagline = "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen"
|
||||||
maintainer = "D4rkst3r"
|
maintainer = "D4rkst3r"
|
||||||
|
|||||||
Vendored
+4
-4
@@ -32,7 +32,7 @@
|
|||||||
"id": "stylized_tree_generator",
|
"id": "stylized_tree_generator",
|
||||||
"name": "Stylized Tree Generator",
|
"name": "Stylized Tree Generator",
|
||||||
"tagline": "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen",
|
"tagline": "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen",
|
||||||
"version": "1.6.0",
|
"version": "1.7.0",
|
||||||
"type": "add-on",
|
"type": "add-on",
|
||||||
"maintainer": "D4rkst3r",
|
"maintainer": "D4rkst3r",
|
||||||
"license": [
|
"license": [
|
||||||
@@ -48,9 +48,9 @@
|
|||||||
"Mesh",
|
"Mesh",
|
||||||
"Modeling"
|
"Modeling"
|
||||||
],
|
],
|
||||||
"archive_url": "./stylized_tree_generator-1.6.0.zip",
|
"archive_url": "./stylized_tree_generator-1.7.0.zip",
|
||||||
"archive_size": 12916,
|
"archive_size": 13398,
|
||||||
"archive_hash": "sha256:48d7072d65d44c944fe7dd160147f37f496132d6c2583c5251f0d6aba499476b"
|
"archive_hash": "sha256:3817ce7433ef63918ddf75a827591b3bb712c8659141ae85f73f4f1fd19e20fb"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -1,7 +1,7 @@
|
|||||||
bl_info = {
|
bl_info = {
|
||||||
"name": "Stylized Tree Generator",
|
"name": "Stylized Tree Generator",
|
||||||
"author": "D4rkst3r",
|
"author": "D4rkst3r",
|
||||||
"version": (1, 6, 0),
|
"version": (1, 7, 0),
|
||||||
"blender": (4, 2, 0),
|
"blender": (4, 2, 0),
|
||||||
"location": "View3D > Sidebar > Tree Gen",
|
"location": "View3D > Sidebar > Tree Gen",
|
||||||
"description": "Parametrischer Baum-/Palmen-/Busch-Generator (Geometry Nodes) mit Wachstums-Stufen",
|
"description": "Parametrischer Baum-/Palmen-/Busch-Generator (Geometry Nodes) mit Wachstums-Stufen",
|
||||||
@@ -40,12 +40,14 @@ DEFAULTS = {
|
|||||||
"Branch Droop": 0.0, # >0 haengt nach unten (Palme), <0 kruemmt nach oben (Kaktus)
|
"Branch Droop": 0.0, # >0 haengt nach unten (Palme), <0 kruemmt nach oben (Kaktus)
|
||||||
"Branch Thickness": 0.32, # Ast-Dicke relativ zum Stamm
|
"Branch Thickness": 0.32, # Ast-Dicke relativ zum Stamm
|
||||||
"Branch Taper": 0.55, # schwach verjuengen -> Roehre statt Kegel/Dorn
|
"Branch Taper": 0.55, # schwach verjuengen -> Roehre statt Kegel/Dorn
|
||||||
"Sub Count": 3, # Sub-Aeste je Hauptast (0 = aus)
|
"Sub Count": 2, # Sub-Aeste je Hauptast (0 = aus)
|
||||||
"Sub Length": 0.55,
|
"Sub Length": 0.55,
|
||||||
"Sub Up": 1.4,
|
"Sub Up": 1.4,
|
||||||
"Sides": 6,
|
"Sides": 5,
|
||||||
"UV Scale": 1.0, # Rinden-Dichte; UVs sind world-space (m)
|
"UV Scale": 1.0, # Rinden-Dichte; UVs sind world-space (m)
|
||||||
"Tip Blunt": 0.18, # >0 verhindert Nadelspitzen (0 = spitz, 0.45 = Kaktus)
|
"Tip Blunt": 0.18, # >0 verhindert Nadelspitzen (0 = spitz, 0.45 = Kaktus)
|
||||||
|
"Root Flare": 1.1, # Wurzelanlauf: Stamm verbreitert sich am Fuss
|
||||||
|
"Detail": 0.55, # skaliert alle Resample-Counts = Tri-Budget-Regler
|
||||||
"Branch Collar": 0.4, # Ansatz-Verdickung: Uebergang Ast->Stamm (0 = aus)
|
"Branch Collar": 0.4, # Ansatz-Verdickung: Uebergang Ast->Stamm (0 = aus)
|
||||||
"Merge": 0.0, # 1 = Aeste per Voxel-Remesh mit dem Stamm verschmelzen
|
"Merge": 0.0, # 1 = Aeste per Voxel-Remesh mit dem Stamm verschmelzen
|
||||||
"Merge Voxel": 0.03, # Voxelgroesse (m): klein = feiner, aber teuer
|
"Merge Voxel": 0.03, # Voxelgroesse (m): klein = feiner, aber teuer
|
||||||
@@ -69,7 +71,8 @@ PRESETS = {
|
|||||||
"Branch Count": 14, "Branch Length": 0.9, "Branch Up": 1.0,
|
"Branch Count": 14, "Branch Length": 0.9, "Branch Up": 1.0,
|
||||||
"Branch Start": 0.15, "Branch End": 0.95,
|
"Branch Start": 0.15, "Branch End": 0.95,
|
||||||
"Branch Bend": 0.6, "Branch Droop": 0.0,
|
"Branch Bend": 0.6, "Branch Droop": 0.0,
|
||||||
"Sub Count": 2, "Sub Length": 0.35, "Sub Up": 1.6, "Sides": 5,
|
"Sub Count": 1, "Sub Length": 0.35, "Sub Up": 1.6, "Sides": 4,
|
||||||
|
"Detail": 0.3, "Branch Count": 10,
|
||||||
},
|
},
|
||||||
# Kaktus: dicker, kaum verjuengter Stamm, wenige Arme, die per NEGATIVEM
|
# Kaktus: dicker, kaum verjuengter Stamm, wenige Arme, die per NEGATIVEM
|
||||||
# Droop nach oben kruemmen (Saguaro-Silhouette). Keine Sub-Aeste.
|
# Droop nach oben kruemmen (Saguaro-Silhouette). Keine Sub-Aeste.
|
||||||
@@ -112,6 +115,18 @@ def build_group():
|
|||||||
N, L = ng.nodes.new, ng.links.new
|
N, L = ng.nodes.new, ng.links.new
|
||||||
iface = ng.interface
|
iface = ng.interface
|
||||||
|
|
||||||
|
def _count(base, x, y):
|
||||||
|
"""Resample-Count = base * Detail, mindestens 3. Der zentrale
|
||||||
|
Tri-Budget-Regler: die Segmentzahl entlang der Kurven dominiert die
|
||||||
|
Dreiecke (Tris ~ Segmente * Sides * 2)."""
|
||||||
|
mul = N("ShaderNodeMath"); mul.location = (x, y); mul.operation = 'MULTIPLY'
|
||||||
|
mul.inputs[0].default_value = float(base)
|
||||||
|
L(V["Detail"], mul.inputs[1])
|
||||||
|
mx = N("ShaderNodeMath"); mx.location = (x + 150, y); mx.operation = 'MAXIMUM'
|
||||||
|
mx.inputs[1].default_value = 3.0
|
||||||
|
L(mul.outputs[0], mx.inputs[0])
|
||||||
|
return mx
|
||||||
|
|
||||||
def _new_any(*bl_idnames):
|
def _new_any(*bl_idnames):
|
||||||
"""Falle 2: erster Node-Typ, den diese Blender-Version kennt."""
|
"""Falle 2: erster Node-Typ, den diese Blender-Version kennt."""
|
||||||
for bid in bl_idnames:
|
for bid in bl_idnames:
|
||||||
@@ -153,6 +168,8 @@ def build_group():
|
|||||||
add_in("Sides", 'NodeSocketInt', DEFAULTS["Sides"], 3, 32)
|
add_in("Sides", 'NodeSocketInt', DEFAULTS["Sides"], 3, 32)
|
||||||
add_in("Tip Blunt", 'NodeSocketFloat', DEFAULTS["Tip Blunt"], 0.0, 0.9)
|
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("UV Scale", 'NodeSocketFloat', DEFAULTS["UV Scale"], 0.01, 20.0)
|
||||||
|
add_in("Detail", 'NodeSocketFloat', DEFAULTS["Detail"], 0.2, 2.0)
|
||||||
|
add_in("Root Flare", 'NodeSocketFloat', DEFAULTS["Root Flare"], 0.0, 4.0)
|
||||||
add_in("Branch Collar", 'NodeSocketFloat', DEFAULTS["Branch Collar"], 0.0, 3.0)
|
add_in("Branch Collar", 'NodeSocketFloat', DEFAULTS["Branch Collar"], 0.0, 3.0)
|
||||||
add_in("Merge", 'NodeSocketFloat', DEFAULTS["Merge"], 0.0, 1.0)
|
add_in("Merge", 'NodeSocketFloat', DEFAULTS["Merge"], 0.0, 1.0)
|
||||||
add_in("Merge Voxel", 'NodeSocketFloat', DEFAULTS["Merge Voxel"], 0.005, 0.2)
|
add_in("Merge Voxel", 'NodeSocketFloat', DEFAULTS["Merge Voxel"], 0.005, 0.2)
|
||||||
@@ -170,7 +187,7 @@ def build_group():
|
|||||||
L(top.outputs[0], _sock(line, "End"))
|
L(top.outputs[0], _sock(line, "End"))
|
||||||
|
|
||||||
res = N("GeometryNodeResampleCurve"); res.location = (-950, 200)
|
res = N("GeometryNodeResampleCurve"); res.location = (-950, 200)
|
||||||
_sock(res, "Count").default_value = 24 # genug Punkte, damit die Kuppel rund wird
|
L(_count(24, -1150, 380).outputs[0], _sock(res, "Count"))
|
||||||
L(_out(line, "Curve"), _sock(res, "Curve"))
|
L(_out(line, "Curve"), _sock(res, "Curve"))
|
||||||
|
|
||||||
spar = N("GeometryNodeSplineParameter"); spar.location = (-950, -60)
|
spar = N("GeometryNodeSplineParameter"); spar.location = (-950, -60)
|
||||||
@@ -270,8 +287,25 @@ def build_group():
|
|||||||
L(inv.outputs[0], tmulr.inputs[0]); L(tdome.outputs[0], tmulr.inputs[1])
|
L(inv.outputs[0], tmulr.inputs[0]); L(tdome.outputs[0], tmulr.inputs[1])
|
||||||
tmaxr = N("ShaderNodeMath"); tmaxr.location = (-110, 60); tmaxr.operation = 'MAXIMUM'
|
tmaxr = N("ShaderNodeMath"); tmaxr.location = (-110, 60); tmaxr.operation = 'MAXIMUM'
|
||||||
L(tmulr.outputs[0], tmaxr.inputs[0]); L(ttip.outputs[0], tmaxr.inputs[1])
|
L(tmulr.outputs[0], tmaxr.inputs[0]); L(ttip.outputs[0], tmaxr.inputs[1])
|
||||||
trad = N("ShaderNodeMath"); trad.location = (40, 60); trad.operation = 'MULTIPLY'
|
|
||||||
L(V["Trunk Radius"], trad.inputs[0]); L(tmaxr.outputs[0], trad.inputs[1])
|
# Wurzelanlauf: der Stamm verbreitert sich am Fuss. Hoher Exponent -> nur
|
||||||
|
# das unterste Stueck ist betroffen. Kostet keine Tris, nur Radius.
|
||||||
|
rfi = N("ShaderNodeMath"); rfi.location = (-420, -220); rfi.operation = 'SUBTRACT'
|
||||||
|
rfi.inputs[0].default_value = 1.0
|
||||||
|
L(spar.outputs["Factor"], rfi.inputs[1])
|
||||||
|
rfp = N("ShaderNodeMath"); rfp.location = (-270, -220); rfp.operation = 'POWER'
|
||||||
|
rfp.inputs[1].default_value = 9.0
|
||||||
|
L(rfi.outputs[0], rfp.inputs[0])
|
||||||
|
rfm = N("ShaderNodeMath"); rfm.location = (-120, -220); rfm.operation = 'MULTIPLY'
|
||||||
|
L(V["Root Flare"], rfm.inputs[0]); L(rfp.outputs[0], rfm.inputs[1])
|
||||||
|
rfa = N("ShaderNodeMath"); rfa.location = (30, -220); rfa.operation = 'ADD'
|
||||||
|
rfa.inputs[0].default_value = 1.0
|
||||||
|
L(rfm.outputs[0], rfa.inputs[1])
|
||||||
|
tflare = N("ShaderNodeMath"); tflare.location = (30, -60); tflare.operation = 'MULTIPLY'
|
||||||
|
L(tmaxr.outputs[0], tflare.inputs[0]); L(rfa.outputs[0], tflare.inputs[1])
|
||||||
|
|
||||||
|
trad = N("ShaderNodeMath"); trad.location = (190, 60); trad.operation = 'MULTIPLY'
|
||||||
|
L(V["Trunk Radius"], trad.inputs[0]); L(tflare.outputs[0], trad.inputs[1])
|
||||||
|
|
||||||
setrad = N("GeometryNodeSetCurveRadius"); setrad.location = (-80, 200)
|
setrad = N("GeometryNodeSetCurveRadius"); setrad.location = (-80, 200)
|
||||||
L(_out(setpos, "Geometry"), _sock(setrad, "Curve"))
|
L(_out(setpos, "Geometry"), _sock(setrad, "Curve"))
|
||||||
@@ -301,7 +335,7 @@ def build_group():
|
|||||||
L(V["Branch Length"], btop.inputs["Z"])
|
L(V["Branch Length"], btop.inputs["Z"])
|
||||||
L(btop.outputs[0], _sock(bline, "End"))
|
L(btop.outputs[0], _sock(bline, "End"))
|
||||||
bres = N("GeometryNodeResampleCurve"); bres.location = (280, 40)
|
bres = N("GeometryNodeResampleCurve"); bres.location = (280, 40)
|
||||||
_sock(bres, "Count").default_value = 14 # zu wenig -> Kuppel wird zum Kegel
|
L(_count(14, 100, 200).outputs[0], _sock(bres, "Count"))
|
||||||
L(_out(bline, "Curve"), _sock(bres, "Curve"))
|
L(_out(bline, "Curve"), _sock(bres, "Curve"))
|
||||||
|
|
||||||
# Ast-Verjuengung: 1 - BranchTaper*factor. Bei Kakteen klein halten,
|
# Ast-Verjuengung: 1 - BranchTaper*factor. Bei Kakteen klein halten,
|
||||||
@@ -453,7 +487,7 @@ def build_group():
|
|||||||
L(V["Sub Length"], stop.inputs["Z"])
|
L(V["Sub Length"], stop.inputs["Z"])
|
||||||
L(stop.outputs[0], _sock(sline, "End"))
|
L(stop.outputs[0], _sock(sline, "End"))
|
||||||
sres = N("GeometryNodeResampleCurve"); sres.location = (2250, 760)
|
sres = N("GeometryNodeResampleCurve"); sres.location = (2250, 760)
|
||||||
_sock(sres, "Count").default_value = 9 # genug Punkte, damit die Biegung sichtbar wird
|
L(_count(9, 2100, 700).outputs[0], _sock(sres, "Count"))
|
||||||
L(_out(sline, "Curve"), _sock(sres, "Curve"))
|
L(_out(sline, "Curve"), _sock(sres, "Curve"))
|
||||||
|
|
||||||
# Sub-Aeste: gleiche Verjuengungs-Logik wie Hauptaeste (Branch Taper + Kuppel).
|
# Sub-Aeste: gleiche Verjuengungs-Logik wie Hauptaeste (Branch Taper + Kuppel).
|
||||||
|
|||||||
Reference in New Issue
Block a user