Tree Generator v1.22.0: Phototropismus (Attraction Up)
Aeste kruemmen sich zur Spitze hin zur Senkrechten - als echte Rotation um den Astansatz, nicht als Z-Versatz. Die Astlaenge bleibt dabei erhalten (gemessen: +0.08 m Hoehe statt +0.93 m beim alten Droop-Hack). Pro Preset abgestimmt. Idee aus UE 5.8 Procedural Vegetation / Weber-Penn. 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.21.0"
|
version = "1.22.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.21.0",
|
"version": "1.22.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.21.0.zip",
|
"archive_url": "./stylized_tree_generator-1.22.0.zip",
|
||||||
"archive_size": 18435,
|
"archive_size": 19331,
|
||||||
"archive_hash": "sha256:eb093c862dc7192728e86ef07d45fc1a9f4381044c2f8560b399f2a85911ec94"
|
"archive_hash": "sha256:5e5e3b5e0b73aabe416f93c27bbef4772b561122762dd52daf836f10c0e45b35"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
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, 21, 0),
|
"version": (1, 22, 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,6 +40,9 @@ DEFAULTS = {
|
|||||||
"Branch Bend": 0.75, # Krummheit je Ast/Zweig (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 Droop": 0.0, # >0 haengt nach unten (Palme), <0 kruemmt nach oben (Kaktus)
|
||||||
"Droop Curve": 2.0, # 2 = weicher Bogen, 4+ = scharfer Ellbogen
|
"Droop Curve": 2.0, # 2 = weicher Bogen, 4+ = scharfer Ellbogen
|
||||||
|
"Attraction Up": 0.45, # Phototropismus in Radiant: Ast dreht sich zur
|
||||||
|
# Spitze hin zur Senkrechten. Echte Rotation um
|
||||||
|
# den Ansatzpunkt -> Astlaenge bleibt erhalten
|
||||||
"Trunk Tip": 0.3, # Anteil von Tip Blunt fuer die Stammspitze;
|
"Trunk Tip": 0.3, # Anteil von Tip Blunt fuer die Stammspitze;
|
||||||
# klein = laeuft duenn aus, 1.0 = stumpfe Kuppe
|
# klein = laeuft duenn aus, 1.0 = stumpfe Kuppe
|
||||||
"Branch Thickness": 0.17, # Ast-Dicke relativ zum Stamm. Am TreeIt-Baum
|
"Branch Thickness": 0.17, # Ast-Dicke relativ zum Stamm. Am TreeIt-Baum
|
||||||
@@ -96,6 +99,7 @@ PRESETS = {
|
|||||||
"Branch Start": 0.9, "Branch End": 1.0,
|
"Branch Start": 0.9, "Branch End": 1.0,
|
||||||
"Branch Bend": 0.3,
|
"Branch Bend": 0.3,
|
||||||
"Branch Droop": 0.5, "Droop Curve": 2.2,
|
"Branch Droop": 0.5, "Droop Curve": 2.2,
|
||||||
|
"Attraction Up": 0.2, # Wedel schwingen leicht hoch, dann Bogen
|
||||||
"Branch Thickness": 0.16,
|
"Branch Thickness": 0.16,
|
||||||
"Branch Taper": 0.45,
|
"Branch Taper": 0.45,
|
||||||
"Root Flare": 0.5, # leichte Verdickung ...
|
"Root Flare": 0.5, # leichte Verdickung ...
|
||||||
@@ -119,6 +123,7 @@ PRESETS = {
|
|||||||
"Branch Count": 22, "Branch Length": 1.9, "Branch Up": -0.25,
|
"Branch Count": 22, "Branch Length": 1.9, "Branch Up": -0.25,
|
||||||
"Branch Start": 0.12, "Branch End": 0.97,
|
"Branch Start": 0.12, "Branch End": 0.97,
|
||||||
"Crown Taper": 0.9, "Crown Bulge": 0.0,
|
"Crown Taper": 0.9, "Crown Bulge": 0.0,
|
||||||
|
"Attraction Up": 0.0, # Tannenaeste haengen, streben nicht hoch
|
||||||
"Branch Bend": 0.3, "Branch Thickness": 0.12, "Sub Count": 1,
|
"Branch Bend": 0.3, "Branch Thickness": 0.12, "Sub Count": 1,
|
||||||
"Sub Length": 0.4, "Root Flare": 0.7,
|
"Sub Length": 0.4, "Root Flare": 0.7,
|
||||||
},
|
},
|
||||||
@@ -127,6 +132,7 @@ PRESETS = {
|
|||||||
"Branch Count": 10, "Branch Length": 2.2, "Branch Up": 0.9,
|
"Branch Count": 10, "Branch Length": 2.2, "Branch Up": 0.9,
|
||||||
"Branch Start": 0.3, "Branch End": 0.95,
|
"Branch Start": 0.3, "Branch End": 0.95,
|
||||||
"Crown Taper": -0.15, "Crown Bulge": 0.5,
|
"Crown Taper": -0.15, "Crown Bulge": 0.5,
|
||||||
|
"Attraction Up": 0.5, # Eiche: Aeste schwingen deutlich hoch
|
||||||
"Branch Bend": 0.9, "Branch Thickness": 0.24, "Sub Count": 3,
|
"Branch Bend": 0.9, "Branch Thickness": 0.24, "Sub Count": 3,
|
||||||
"Sub Length": 0.8, "Root Flare": 1.5, "Root Lobe Depth": 0.4,
|
"Sub Length": 0.8, "Root Flare": 1.5, "Root Lobe Depth": 0.4,
|
||||||
},
|
},
|
||||||
@@ -143,6 +149,7 @@ PRESETS = {
|
|||||||
"Branch Count": 12, "Branch Length": 2.0, "Branch Up": 0.5,
|
"Branch Count": 12, "Branch Length": 2.0, "Branch Up": 0.5,
|
||||||
"Branch Start": 0.35, "Branch End": 0.95,
|
"Branch Start": 0.35, "Branch End": 0.95,
|
||||||
"Crown Taper": -0.2, "Crown Bulge": 0.4,
|
"Crown Taper": -0.2, "Crown Bulge": 0.4,
|
||||||
|
"Attraction Up": -0.25, # Weide: Zweige haengen
|
||||||
"Branch Droop": 1.2, "Branch Bend": 0.7, "Branch Thickness": 0.16,
|
"Branch Droop": 1.2, "Branch Bend": 0.7, "Branch Thickness": 0.16,
|
||||||
"Sub Count": 3, "Sub Length": 0.9, "Root Flare": 1.2,
|
"Sub Count": 3, "Sub Length": 0.9, "Root Flare": 1.2,
|
||||||
},
|
},
|
||||||
@@ -151,6 +158,7 @@ PRESETS = {
|
|||||||
"Branch Count": 6, "Branch Length": 1.5, "Branch Up": 0.9,
|
"Branch Count": 6, "Branch Length": 1.5, "Branch Up": 0.9,
|
||||||
"Branch Start": 0.3, "Branch End": 0.9,
|
"Branch Start": 0.3, "Branch End": 0.9,
|
||||||
"Crown Taper": 0.3, "Crown Bulge": 0.0,
|
"Crown Taper": 0.3, "Crown Bulge": 0.0,
|
||||||
|
"Attraction Up": 0.35,
|
||||||
"Branch Bend": 1.4, "Branch Thickness": 0.18, "Sub Count": 1,
|
"Branch Bend": 1.4, "Branch Thickness": 0.18, "Sub Count": 1,
|
||||||
"Sub Length": 0.5, "Root Flare": 1.4, "Tip Blunt": 0.08,
|
"Sub Length": 0.5, "Root Flare": 1.4, "Tip Blunt": 0.08,
|
||||||
},
|
},
|
||||||
@@ -161,6 +169,7 @@ PRESETS = {
|
|||||||
"Branch Count": 2, "Branch Length": 1.9, "Branch Up": 0.12,
|
"Branch Count": 2, "Branch Length": 1.9, "Branch Up": 0.12,
|
||||||
"Branch Start": 0.30, "Branch End": 0.46,
|
"Branch Start": 0.30, "Branch End": 0.46,
|
||||||
"Branch Bend": 0.0,
|
"Branch Bend": 0.0,
|
||||||
|
"Attraction Up": 0.0, # Kaktus nutzt den Droop-Ellbogen
|
||||||
"Branch Droop": -1.35, # negativ = Arme kruemmen nach OBEN (Saguaro);
|
"Branch Droop": -1.35, # negativ = Arme kruemmen nach OBEN (Saguaro);
|
||||||
# zu gross und die Arme ueberragen den Stamm
|
# zu gross und die Arme ueberragen den Stamm
|
||||||
"Droop Curve": 4.5, # spaeter, dafuer scharfer Ellbogen
|
"Droop Curve": 4.5, # spaeter, dafuer scharfer Ellbogen
|
||||||
@@ -244,6 +253,7 @@ def build_group():
|
|||||||
# (= Kaktus-Arme statt Palmwedel).
|
# (= Kaktus-Arme statt Palmwedel).
|
||||||
add_in("Branch Droop", 'NodeSocketFloat', DEFAULTS["Branch Droop"], -3.0, 3.0)
|
add_in("Branch Droop", 'NodeSocketFloat', DEFAULTS["Branch Droop"], -3.0, 3.0)
|
||||||
add_in("Droop Curve", 'NodeSocketFloat', DEFAULTS["Droop Curve"], 1.0, 8.0)
|
add_in("Droop Curve", 'NodeSocketFloat', DEFAULTS["Droop Curve"], 1.0, 8.0)
|
||||||
|
add_in("Attraction Up", 'NodeSocketFloat', DEFAULTS["Attraction Up"], -1.5, 1.5)
|
||||||
add_in("Trunk Tip", 'NodeSocketFloat', DEFAULTS["Trunk Tip"], 0.05, 1.0)
|
add_in("Trunk Tip", 'NodeSocketFloat', DEFAULTS["Trunk Tip"], 0.05, 1.0)
|
||||||
add_in("Branch Thickness", 'NodeSocketFloat', DEFAULTS["Branch Thickness"], 0.05, 1.0)
|
add_in("Branch Thickness", 'NodeSocketFloat', DEFAULTS["Branch Thickness"], 0.05, 1.0)
|
||||||
add_in("Branch Taper", 'NodeSocketFloat', DEFAULTS["Branch Taper"], 0.0, 1.0)
|
add_in("Branch Taper", 'NodeSocketFloat', DEFAULTS["Branch Taper"], 0.0, 1.0)
|
||||||
@@ -546,8 +556,19 @@ def build_group():
|
|||||||
pfin = N("ShaderNodeMath"); pfin.location = (2100, 120); pfin.operation = 'MULTIPLY'
|
pfin = N("ShaderNodeMath"); pfin.location = (2100, 120); pfin.operation = 'MULTIPLY'
|
||||||
L(pscale.outputs[0], pfin.inputs[0]); L(ccl.outputs[0], pfin.inputs[1])
|
L(pscale.outputs[0], pfin.inputs[0]); L(ccl.outputs[0], pfin.inputs[1])
|
||||||
|
|
||||||
|
# Ansatzpunkt als Attribut mitgeben. Punkt-Attribute ueberleben
|
||||||
|
# "Instance on Points" + "Realize" (geprueft) - dadurch kennt spaeter JEDER
|
||||||
|
# Punkt eines Astes seinen eigenen Ursprung. Das ist die Voraussetzung fuer
|
||||||
|
# echtes Biegen (Rotation) statt blossem Verschieben.
|
||||||
|
apos = N("GeometryNodeInputPosition"); apos.location = (900, 480)
|
||||||
|
anch = N("GeometryNodeStoreNamedAttribute"); anch.location = (1050, 320)
|
||||||
|
anch.domain = 'POINT'; anch.data_type = 'FLOAT_VECTOR'
|
||||||
|
L(_out(c2p, "Points"), _sock(anch, "Geometry"))
|
||||||
|
_sock(anch, "Name").default_value = "anchor"
|
||||||
|
L(apos.outputs[0], _sock(anch, "Value"))
|
||||||
|
|
||||||
inst = N("GeometryNodeInstanceOnPoints"); inst.location = (1400, 320)
|
inst = N("GeometryNodeInstanceOnPoints"); inst.location = (1400, 320)
|
||||||
L(_out(c2p, "Points"), _sock(inst, "Points"))
|
L(_out(anch, "Geometry"), _sock(inst, "Points"))
|
||||||
L(_out(bsetr, "Curve"), _sock(inst, "Instance"))
|
L(_out(bsetr, "Curve"), _sock(inst, "Instance"))
|
||||||
L(pfin.outputs[0], _sock(inst, "Scale"))
|
L(pfin.outputs[0], _sock(inst, "Scale"))
|
||||||
if align is not None:
|
if align is not None:
|
||||||
@@ -561,6 +582,42 @@ def build_group():
|
|||||||
# des jeweiligen Astes. Dieselbe Noise liefert damit pro Ast einen anderen
|
# des jeweiligen Astes. Dieselbe Noise liefert damit pro Ast einen anderen
|
||||||
# Wert — vor dem Realize haetten alle Instanzen identische lokale Coords
|
# Wert — vor dem Realize haetten alle Instanzen identische lokale Coords
|
||||||
# (und wuerden exakt gleich gebogen).
|
# (und wuerden exakt gleich gebogen).
|
||||||
|
# ---------- Phototropismus (Lichtsuche) ----------
|
||||||
|
# Idee aus UE 5.8 Procedural Vegetation ("light detection") bzw. Weber-Penn
|
||||||
|
# ("attraction up"): Aeste kruemmen sich zur Spitze hin zur Senkrechten.
|
||||||
|
# Umgesetzt als echte ROTATION des Punktes um seinen Astansatz - im
|
||||||
|
# Gegensatz zum Z-Versatz (Droop) bleibt die Astlaenge dabei erhalten.
|
||||||
|
ph_spar = N("GeometryNodeSplineParameter"); ph_spar.location = (1200, 780)
|
||||||
|
ph_pos = N("GeometryNodeInputPosition"); ph_pos.location = (1200, 640)
|
||||||
|
ph_anch = N("GeometryNodeInputNamedAttribute"); ph_anch.location = (1200, 500)
|
||||||
|
ph_anch.data_type = 'FLOAT_VECTOR'
|
||||||
|
_sock(ph_anch, "Name").default_value = "anchor"
|
||||||
|
ph_rel = N("ShaderNodeVectorMath"); ph_rel.location = (1400, 640)
|
||||||
|
ph_rel.operation = 'SUBTRACT'
|
||||||
|
L(ph_pos.outputs[0], ph_rel.inputs[0])
|
||||||
|
L(_out(ph_anch, "Attribute"), ph_rel.inputs[1])
|
||||||
|
ph_up = N("ShaderNodeCombineXYZ"); ph_up.location = (1400, 500)
|
||||||
|
ph_up.inputs["Z"].default_value = 1.0
|
||||||
|
ph_ax = N("ShaderNodeVectorMath"); ph_ax.location = (1550, 570)
|
||||||
|
ph_ax.operation = 'CROSS_PRODUCT'
|
||||||
|
L(ph_rel.outputs[0], ph_ax.inputs[0]); L(ph_up.outputs[0], ph_ax.inputs[1])
|
||||||
|
ph_ang = N("ShaderNodeMath"); ph_ang.location = (1400, 780)
|
||||||
|
ph_ang.operation = 'MULTIPLY'
|
||||||
|
L(V["Attraction Up"], ph_ang.inputs[0])
|
||||||
|
L(ph_spar.outputs["Factor"], ph_ang.inputs[1])
|
||||||
|
ph_rot = N("ShaderNodeVectorRotate"); ph_rot.location = (1750, 640)
|
||||||
|
ph_rot.rotation_type = 'AXIS_ANGLE'
|
||||||
|
L(ph_rel.outputs[0], ph_rot.inputs["Vector"])
|
||||||
|
L(ph_ax.outputs[0], ph_rot.inputs["Axis"])
|
||||||
|
L(ph_ang.outputs[0], ph_rot.inputs["Angle"])
|
||||||
|
ph_new = N("ShaderNodeVectorMath"); ph_new.location = (1900, 640)
|
||||||
|
ph_new.operation = 'ADD'
|
||||||
|
L(_out(ph_anch, "Attribute"), ph_new.inputs[0])
|
||||||
|
L(ph_rot.outputs[0], ph_new.inputs[1])
|
||||||
|
ph_set = N("GeometryNodeSetPosition"); ph_set.location = (2050, 780)
|
||||||
|
L(_out(real, "Geometry"), _sock(ph_set, "Geometry"))
|
||||||
|
L(ph_new.outputs[0], _sock(ph_set, "Position"))
|
||||||
|
|
||||||
rspar = N("GeometryNodeSplineParameter"); rspar.location = (1200, 60)
|
rspar = N("GeometryNodeSplineParameter"); rspar.location = (1200, 60)
|
||||||
rpos = N("GeometryNodeInputPosition"); rpos.location = (1200, -100)
|
rpos = N("GeometryNodeInputPosition"); rpos.location = (1200, -100)
|
||||||
rnoise = N("ShaderNodeTexNoise"); rnoise.location = (1350, -140)
|
rnoise = N("ShaderNodeTexNoise"); rnoise.location = (1350, -140)
|
||||||
@@ -599,8 +656,8 @@ def build_group():
|
|||||||
L(rscale.outputs[0], roffs.inputs[0])
|
L(rscale.outputs[0], roffs.inputs[0])
|
||||||
L(dvec.outputs[0], roffs.inputs[1])
|
L(dvec.outputs[0], roffs.inputs[1])
|
||||||
|
|
||||||
rsetp = N("GeometryNodeSetPosition"); rsetp.location = (1950, 320)
|
rsetp = N("GeometryNodeSetPosition"); rsetp.location = (2200, 320)
|
||||||
L(_out(real, "Geometry"), _sock(rsetp, "Geometry"))
|
L(_out(ph_set, "Geometry"), _sock(rsetp, "Geometry"))
|
||||||
L(roffs.outputs[0], _sock(rsetp, "Offset"))
|
L(roffs.outputs[0], _sock(rsetp, "Offset"))
|
||||||
|
|
||||||
# ---------- Sub-Aeste (zweite Verzweigungsebene) ----------
|
# ---------- Sub-Aeste (zweite Verzweigungsebene) ----------
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""Prueft das gebaute Tree-Addon: registrieren, Operator ausfuehren, Ergebnis messen."""
|
"""Prueft das gebaute Tree-Addon: registrieren, Operator ausfuehren, Ergebnis messen."""
|
||||||
import bpy, sys, zipfile, os, tempfile, importlib.util, traceback
|
import bpy, sys, zipfile, os, tempfile, importlib.util, traceback
|
||||||
|
|
||||||
ZIP = r"A:\eco\stylized_rock_generator\dist\stylized_tree_generator-1.21.0.zip"
|
ZIP = r"A:\eco\stylized_rock_generator\dist\stylized_tree_generator-1.22.0.zip"
|
||||||
fails = []
|
fails = []
|
||||||
|
|
||||||
tmp = tempfile.mkdtemp()
|
tmp = tempfile.mkdtemp()
|
||||||
|
|||||||
Reference in New Issue
Block a user