Weiter an den Baum Systemen gearbeitet

This commit is contained in:
2026-08-23 17:21:21 +02:00
parent d65ebbfeb6
commit 46b504e050
4 changed files with 246 additions and 150 deletions

View File

@@ -16,7 +16,8 @@ out vec2 texCoord;
out vec3 worldNormal; out vec3 worldNormal;
void main() { void main() {
float windW = inColor.r; float windW = inColor.r; // Ast-Wind (0=Wurzel, 1=Astspitze)
float leafFlutter = inColor.g; // Blatt-Flattern (0=Ansatz, 1=Blattspitze)
float t = g_Time * m_WindSpeed; float t = g_Time * m_WindSpeed;
vec4 worldPos = g_WorldMatrix * vec4(inPosition, 1.0); vec4 worldPos = g_WorldMatrix * vec4(inPosition, 1.0);
@@ -30,16 +31,20 @@ void main() {
vec2 hashPos = floor(vec2(g_WorldMatrix[3][0], g_WorldMatrix[3][2])); vec2 hashPos = floor(vec2(g_WorldMatrix[3][0], g_WorldMatrix[3][2]));
float randPhase = fract(sin(dot(hashPos, vec2(127.1, 311.7))) * 43758.5453) * 6.2832; float randPhase = fract(sin(dot(hashPos, vec2(127.1, 311.7))) * 43758.5453) * 6.2832;
// Ast-Schwingen (niedrige Frequenz, große Amplitude)
float mainSway = sin(t + wavePhase * 0.08 + randPhase) * windW * m_WindStrength; float mainSway = sin(t + wavePhase * 0.08 + randPhase) * windW * m_WindStrength;
float crossSway = cos(t * 0.73 + wavePhase * 0.06 + randPhase) * windW * m_WindStrength * 0.25; float crossSway = cos(t * 0.73 + wavePhase * 0.06 + randPhase) * windW * m_WindStrength * 0.25;
// Blatt-Flattern (hohe Frequenz, kleine Amplitude, unabhängig vom Ast-Wind)
float flutter = sin(t * 2.9 + wavePhase * 0.22 + randPhase * 1.6) * leafFlutter * m_WindStrength * 0.5;
// Y-Kompression: Äste neigen sich statt zu strecken → verhindert Breiterwerden der Spitzen // Y-Kompression: Äste neigen sich statt zu strecken → verhindert Breiterwerden der Spitzen
float sway2 = mainSway * mainSway + crossSway * crossSway; float sway2 = mainSway * mainSway + crossSway * crossSway;
vec3 animPos = inPosition + vec3( vec3 animPos = inPosition + vec3(
windN.x * mainSway + perpN.x * crossSway, windN.x * mainSway + perpN.x * crossSway + perpN.x * flutter,
-sway2 * 0.5, -sway2 * 0.5,
windN.y * mainSway + perpN.y * crossSway windN.y * mainSway + perpN.y * crossSway + perpN.y * flutter
); );
gl_Position = g_WorldViewProjectionMatrix * vec4(animPos, 1.0); gl_Position = g_WorldViewProjectionMatrix * vec4(animPos, 1.0);

View File

@@ -1939,9 +1939,9 @@ public class EditorApp extends Application {
levelSpinner.valueProperty().addListener((o, a, b) -> treeParams.levels = b); levelSpinner.valueProperty().addListener((o, a, b) -> treeParams.levels = b);
inner.getChildren().add(levelSpinner); inner.getChildren().add(levelSpinner);
// Gravitation // Stamm-Aufrichtung
inner.getChildren().add(paramSlider("Gravitation:", -0.15, 0.20, treeParams.gravityStrength, inner.getChildren().add(paramSlider("Stamm-Aufrichtung:", 0.0, 0.40, treeParams.trunkUprightness,
v -> treeParams.gravityStrength = v)); v -> treeParams.trunkUprightness = v));
inner.getChildren().add(new Separator()); inner.getChildren().add(new Separator());

View File

@@ -39,12 +39,14 @@ public class TreeMeshBuilder {
VertexCollector barkCol = new VertexCollector(); VertexCollector barkCol = new VertexCollector();
VertexCollector leafCol = new VertexCollector(); VertexCollector leafCol = new VertexCollector();
record BranchTask(Vector3f origin, Vector3f dir, int level, float windBase) {} // parentDir: Wachstumsrichtung des Elternastes an der Abzweigstelle
// (für L2+-Äste: 90° davon weg = natürliche Spreizung)
record BranchTask(Vector3f origin, Vector3f dir, Vector3f parentDir, int level, float windBase) {}
record SectionPt (Vector3f pos, Vector3f dir, float wind) {} record SectionPt (Vector3f pos, Vector3f dir, float wind) {}
Deque<BranchTask> stack = new ArrayDeque<>(); Deque<BranchTask> stack = new ArrayDeque<>();
stack.push(new BranchTask(new Vector3f(0, 0, 0), new Vector3f(0, 1, 0), stack.push(new BranchTask(new Vector3f(0, 0, 0), new Vector3f(0, 1, 0),
0, p.trunkFlexibility)); new Vector3f(0, 1, 0), 0, p.trunkFlexibility));
while (!stack.isEmpty()) { while (!stack.isEmpty()) {
BranchTask t = stack.pop(); BranchTask t = stack.pop();
@@ -75,28 +77,78 @@ public class TreeMeshBuilder {
Vector3f dir = t.dir().clone(); Vector3f dir = t.dir().clone();
List<SectionPt> sectionPts = new ArrayList<>(numSec); List<SectionPt> sectionPts = new ArrayList<>(numSec);
for (int s = 0; s < numSec; s++) { // Alle Sektionspunkte sammeln, danach als nahtlose Röhre (Bisektor-Ringe,
float rBot = baseRad * lerp(1f, tapFactor, (float) s / numSec); // kein Parallel-Transport-Twisting, keine Lücken an Richtungswechseln).
float rTop = baseRad * lerp(1f, tapFactor, (float)(s + 1) / numSec); Vector3f[] tubePts = new Vector3f[numSec + 1];
float wBot = lerp(t.windBase(), windEnd, (float) s / numSec); float[] tubeRad = new float[numSec + 1];
float wTop = lerp(t.windBase(), windEnd, (float)(s + 1) / numSec); float[] tubeWind = new float[numSec + 1];
tubePts[0] = pos.clone();
tubeRad[0] = baseRad;
tubeWind[0] = t.windBase();
// Gnarliness: dünne Äste stärker perturbieren (nur ab Level 1) for (int s = 0; s < numSec; s++) {
if (lv > 0 && gnarl > 1e-4f) { float t0 = (float) s / numSec;
float g = gnarl / (float) Math.sqrt(Math.max(0.01f, rBot)); float t1 = (float)(s + 1) / numSec;
float rBot = baseRad * lerp(1f, tapFactor, t0);
// Gnarliness auch für den Stamm (lv=0), dort aber gedämpft
if (gnarl > 1e-4f) {
float gScale = (lv == 0) ? 0.25f : 1.0f;
float g = gnarl * gScale / (float) Math.sqrt(Math.max(0.01f, rBot));
dir.x += rng.range(-g, g); dir.x += rng.range(-g, g);
dir.z += rng.range(-g, g); dir.z += rng.range(-g, g);
dir.normalizeLocal(); dir.normalizeLocal();
} }
// Gravitation: Richtung graduell zur Gravitations-Richtung drehen // Wachstumstendenz per Level
applyGravity(dir, rBot, p.gravityStrength); if (lv == 0) {
// Stamm: Drang nach oben (korrigiert Gnarliness-Knicke zurück)
applyTendency(dir, Vector3f.UNIT_Y, p.trunkUprightness);
} else {
float outw = TreeParams.lv(p.outwardness, lv);
if (outw > 1e-5f) {
Vector3f ideal;
if (lv == 1) {
// L1: vom Stamm weg, je höher am Stamm desto mehr nach oben
float hFrac = FastMath.clamp(t.origin().y / TreeParams.lv(p.length, 0), 0f, 1f);
ideal = new Vector3f(t.origin().x, 0f, t.origin().z);
if (ideal.lengthSquared() < 1e-6f) ideal = new Vector3f(1f, 0f, 0f);
ideal.normalizeLocal();
ideal.y = hFrac;
ideal.normalizeLocal();
} else {
// L2+: 90° weg vom Elternast + weg vom Stamm
Vector3f pDir = t.parentDir();
// Horizontale Senkrechte zum Elternast
Vector3f perpH = new Vector3f(pDir.z, 0f, -pDir.x);
if (perpH.lengthSquared() < 1e-6f) perpH = new Vector3f(1f, 0f, 0f);
perpH.normalizeLocal();
// Outward-Vektor vom Stammzentrum
Vector3f outXZ = new Vector3f(pos.x, 0f, pos.z);
if (outXZ.lengthSquared() > 1e-6f) {
outXZ.normalizeLocal();
if (perpH.dot(outXZ) < 0f) perpH.negateLocal();
}
ideal = perpH.add(outXZ);
if (ideal.lengthSquared() < 1e-6f) ideal = perpH.clone();
ideal.normalizeLocal();
}
applyTendency(dir, ideal, outw);
}
}
Vector3f end = pos.add(dir.mult(segLen)); Vector3f end = pos.add(dir.mult(segLen));
addCylinder(barkCol, pos, end, rBot, rTop, wBot, wTop, segs);
sectionPts.add(new SectionPt(pos.clone(), dir.clone(), wTop)); // t^1.5-Kurve: Stamm/Ast bleibt länger dick, verjüngt sich am Ende schneller
float tapT = FastMath.pow(t1, 1.5f);
tubePts[s + 1] = end.clone();
tubeRad[s + 1] = baseRad * lerp(1f, tapFactor, tapT);
tubeWind[s + 1] = lerp(t.windBase(), windEnd, t1);
sectionPts.add(new SectionPt(pos.clone(), dir.clone(), tubeWind[s + 1]));
pos = end; pos = end;
} }
buildTube(barkCol, tubePts, tubeRad, tubeWind, segs);
if (lv < maxLevel - 1) { if (lv < maxLevel - 1) {
// Kind-Äste stratifiziert entlang des Eltern-Astes verteilen // Kind-Äste stratifiziert entlang des Eltern-Astes verteilen
@@ -114,7 +166,7 @@ public class TreeMeshBuilder {
float nextAngle = TreeParams.lv(p.angle, lv + 1); float nextAngle = TreeParams.lv(p.angle, lv + 1);
stack.push(new BranchTask( stack.push(new BranchTask(
sp.pos(), branchDir(sp.dir(), yRot, nextAngle), sp.pos(), branchDir(sp.dir(), yRot, nextAngle),
lv + 1, sp.wind())); sp.dir().clone(), lv + 1, sp.wind()));
} }
} else if (p.generateLeaves) { } else if (p.generateLeaves) {
// Blätter entlang des gesamten letzten Astes (jede Sektion) // Blätter entlang des gesamten letzten Astes (jede Sektion)
@@ -137,9 +189,11 @@ public class TreeMeshBuilder {
+ rng.range(-0.5f, 0.5f); + rng.range(-0.5f, 0.5f);
Vector3f twigDir = branchDir(sp.dir(), yRot, twigAngle); Vector3f twigDir = branchDir(sp.dir(), yRot, twigAngle);
Vector3f twigEnd = sp.pos().add(twigDir.mult(twigLen)); Vector3f twigEnd = sp.pos().add(twigDir.mult(twigLen));
addCylinder(barkCol, sp.pos(), twigEnd, buildTube(barkCol,
twigRad, twigRad * 0.35f, new Vector3f[]{sp.pos(), twigEnd},
sp.wind(), windEnd, Math.max(3, segs - 1)); new float[]{twigRad, twigRad * 0.35f},
new float[]{sp.wind(), windEnd},
Math.max(3, segs - 1));
addLeafCluster(leafCol, twigEnd, windEnd, addLeafCluster(leafCol, twigEnd, windEnd,
p.leafScale, p.leafCount, p.leafAngle, rng); p.leafScale, p.leafCount, p.leafAngle, rng);
} }
@@ -151,20 +205,18 @@ public class TreeMeshBuilder {
return new MeshResult(barkCol.toMesh(), leafCol.toMesh(), computeBounds(barkCol)); return new MeshResult(barkCol.toMesh(), leafCol.toMesh(), computeBounds(barkCol));
} }
// ── Gravitations-Kraft ──────────────────────────────────────────────────── // ── Wachstumstendenz ─────────────────────────────────────────────────────
// Dreht dir pro Sektion um bis zu `strength` Radiant in Richtung ideal.
private static void applyGravity(Vector3f dir, float radius, float strength) { private static void applyTendency(Vector3f dir, Vector3f ideal, float strength) {
if (Math.abs(strength) < 1e-5f) return; if (strength < 1e-5f) return;
// strength > 0 → nach unten ziehen; strength < 0 → nach oben ziehen Vector3f axis = dir.cross(ideal);
Vector3f target = new Vector3f(0, strength > 0 ? -1f : 1f, 0); float sinA = axis.length();
Vector3f axis = dir.cross(target); if (sinA < 1e-6f) return;
float sinFull = axis.length(); axis.divideLocal(sinA);
if (sinFull < 1e-6f) return; float angle = FastMath.atan2(sinA, dir.dot(ideal));
axis.divideLocal(sinFull); float step = FastMath.clamp(strength, 0f, angle);
float fullAngle = FastMath.atan2(sinFull, dir.dot(target)); new Quaternion().fromAngleAxis(step, axis).multLocal(dir);
float step = Math.abs(strength) / Math.max(0.01f, radius);
float clamped = FastMath.clamp(step, 0f, Math.abs(fullAngle));
new Quaternion().fromAngleAxis(clamped, axis).multLocal(dir);
dir.normalizeLocal(); dir.normalizeLocal();
} }
@@ -172,48 +224,73 @@ public class TreeMeshBuilder {
private static float lerp(float a, float b, float t) { return a + (b - a) * t; } private static float lerp(float a, float b, float t) { return a + (b - a) * t; }
// ── Zylinder-Segment ───────────────────────────────────────────────────── // ── Nahtlose Röhre entlang eines Pfades ──────────────────────────────────
// Bisektor-Achsen an Gelenken → keine Lücken bei Richtungswechsel.
// Parallel-Transport des Perp-Vektors → kein Twisting.
private static void addCylinder(VertexCollector col, private static void buildTube(VertexCollector col,
Vector3f start, Vector3f end, Vector3f[] pts, float[] radii, float[] winds, int N) {
float rBot, float rTop, int nPts = pts.length;
float windBot, float windTop, if (nPts < 2) return;
int N) {
Vector3f axis = end.subtract(start);
if (axis.lengthSquared() < 1e-8f) return;
axis.normalizeLocal();
Vector3f perp1 = (Math.abs(axis.y) < 0.9f) Vector3f[] segDir = new Vector3f[nPts - 1];
? axis.cross(Vector3f.UNIT_Y).normalizeLocal() for (int i = 0; i < nPts - 1; i++) {
: axis.cross(Vector3f.UNIT_X).normalizeLocal(); segDir[i] = pts[i + 1].subtract(pts[i]);
Vector3f perp2 = axis.cross(perp1).normalizeLocal(); float len = segDir[i].length();
if (len > 1e-6f) segDir[i].divideLocal(len); else segDir[i].set(0, 1, 0);
int base = col.vertexCount;
int N1 = N + 1;
for (int ring = 0; ring < 2; ring++) {
Vector3f center = (ring == 0) ? start : end;
float r = (ring == 0) ? rBot : rTop;
float wind = (ring == 0) ? windBot : windTop;
float vCoord = ring;
for (int i = 0; i <= N; i++) {
float theta = FastMath.TWO_PI * i / N;
float cos = FastMath.cos(theta);
float sin = FastMath.sin(theta);
float nx = cos * perp1.x + sin * perp2.x;
float ny = cos * perp1.y + sin * perp2.y;
float nz = cos * perp1.z + sin * perp2.z;
col.add(center.x + nx * r, center.y + ny * r, center.z + nz * r,
nx, ny, nz,
(float) i / N, vCoord, wind);
}
} }
for (int i = 0; i < N; i++) { Vector3f[] ringAxis = new Vector3f[nPts];
int b0 = base + i, b1 = base + i + 1; ringAxis[0] = segDir[0].clone();
int t0 = base + N1 + i, t1 = base + N1 + i + 1; ringAxis[nPts - 1] = segDir[nPts - 2].clone();
col.tri(b0, b1, t1); for (int i = 1; i < nPts - 1; i++) {
col.tri(b0, t1, t0); ringAxis[i] = segDir[i - 1].add(segDir[i]);
float len = ringAxis[i].length();
if (len > 1e-6f) ringAxis[i].divideLocal(len); else ringAxis[i] = segDir[i].clone();
}
Vector3f axis0 = ringAxis[0];
Vector3f perp = (Math.abs(axis0.y) < 0.9f)
? axis0.cross(Vector3f.UNIT_Y).normalizeLocal()
: axis0.cross(Vector3f.UNIT_X).normalizeLocal();
int N1 = N + 1;
int base = col.vertexCount;
for (int i = 0; i < nPts; i++) {
Vector3f axis = ringAxis[i];
if (i > 0) {
float dot = perp.dot(axis);
perp = perp.subtract(axis.mult(dot));
float len = perp.length();
if (len > 1e-6f) perp.divideLocal(len);
else perp = (Math.abs(axis.y) < 0.9f)
? axis.cross(Vector3f.UNIT_Y).normalizeLocal()
: axis.cross(Vector3f.UNIT_X).normalizeLocal();
}
Vector3f perp2 = axis.cross(perp).normalizeLocal();
float r = radii[i];
float w = winds[i];
for (int j = 0; j <= N; j++) {
float theta = FastMath.TWO_PI * j / N;
float cosT = FastMath.cos(theta);
float sinT = FastMath.sin(theta);
float nx = cosT * perp.x + sinT * perp2.x;
float ny = cosT * perp.y + sinT * perp2.y;
float nz = cosT * perp.z + sinT * perp2.z;
col.add(pts[i].x + nx * r, pts[i].y + ny * r, pts[i].z + nz * r,
nx, ny, nz, (float) j / N, (float) i / (nPts - 1), w);
}
if (i > 0) {
int pb = base + (i - 1) * N1;
int cb = base + i * N1;
for (int j = 0; j < N; j++) {
col.tri(pb + j, pb + j + 1, cb + j + 1);
col.tri(pb + j, cb + j + 1, cb + j);
}
}
} }
} }
@@ -262,18 +339,17 @@ public class TreeMeshBuilder {
float ny = rz * gx - rx * gz; float ny = rz * gx - rx * gz;
float nz = rx * gy - ry * gx; float nz = rx * gy - ry * gx;
float windTip = Math.min(1.0f, wind + 0.25f);
int base = col.vertexCount; int base = col.vertexCount;
// Untere Kante am Ast (verankert) // Untere Kante: am Ast verankert schwingt mit dem Ast (flutter=0)
col.add(cx - rx * hw, cy - ry * hw, cz - rz * hw, col.add(cx - rx * hw, cy - ry * hw, cz - rz * hw,
nx, ny, nz, 0f, 0f, wind); nx, ny, nz, 0f, 0f, wind, 0f);
col.add(cx + rx * hw, cy + ry * hw, cz + rz * hw, col.add(cx + rx * hw, cy + ry * hw, cz + rz * hw,
nx, ny, nz, 1f, 0f, wind); nx, ny, nz, 1f, 0f, wind, 0f);
// Obere Kante frei (schwingt im Wind) // Obere Kante: flattert zusätzlich (flutter=1)
col.add(cx + rx * hw + gx * hh, cy + ry * hw + gy * hh, cz + rz * hw + gz * hh, col.add(cx + rx * hw + gx * hh, cy + ry * hw + gy * hh, cz + rz * hw + gz * hh,
nx, ny, nz, 1f, 1f, windTip); nx, ny, nz, 1f, 1f, wind, 1f);
col.add(cx - rx * hw + gx * hh, cy - ry * hw + gy * hh, cz - rz * hw + gz * hh, col.add(cx - rx * hw + gx * hh, cy - ry * hw + gy * hh, cz - rz * hw + gz * hh,
nx, ny, nz, 0f, 1f, windTip); nx, ny, nz, 0f, 1f, wind, 1f);
col.tri(base, base + 1, base + 2); col.tri(base, base + 1, base + 2);
col.tri(base, base + 2, base + 3); col.tri(base, base + 2, base + 3);
@@ -343,10 +419,16 @@ public class TreeMeshBuilder {
void add(float x, float y, float z, void add(float x, float y, float z,
float nx, float ny, float nz, float nx, float ny, float nz,
float u, float v, float wind) { float u, float v, float wind) {
add(x, y, z, nx, ny, nz, u, v, wind, 0f);
}
void add(float x, float y, float z,
float nx, float ny, float nz,
float u, float v, float wind, float flutter) {
pos.add(x); pos.add(y); pos.add(z); pos.add(x); pos.add(y); pos.add(z);
norm.add(nx); norm.add(ny); norm.add(nz); norm.add(nx); norm.add(ny); norm.add(nz);
uv.add(u); uv.add(v); uv.add(u); uv.add(v);
col.add(wind); col.add(0f); col.add(0f); col.add(1f); col.add(wind); col.add(flutter); col.add(0f); col.add(1f);
vertexCount++; vertexCount++;
} }

View File

@@ -9,9 +9,12 @@ package de.blight.editor.tree;
public class TreeParams { public class TreeParams {
// ── Global ──────────────────────────────────────────────────────────────── // ── Global ────────────────────────────────────────────────────────────────
public int seed = 42; public int seed = 42;
public int levels = 3; // Rekursionstiefe (14) public int levels = 3; // Rekursionstiefe (14)
public float gravityStrength = 0.03f; // >0 = Äste hängen, <0 = aufwärts (Tanne) /** Wie stark der Stamm pro Sektion zurück zur Senkrechten korrigiert (rad/Sektion). */
public float trunkUprightness = 0.12f;
/** Wie stark Äste pro Sektion vom Stamm / Elternast weg tendieren (rad/Sektion, per Level). */
public float[] outwardness = { 0f, 0.08f, 0.07f, 0.05f };
// ── Per-Level-Arrays (Index = Level) ────────────────────────────────────── // ── Per-Level-Arrays (Index = Level) ──────────────────────────────────────
/** Astwinkel zur Eltern-Richtung in Grad (Level 0 = Stamm, ignoriert). */ /** Astwinkel zur Eltern-Richtung in Grad (Level 0 = Stamm, ignoriert). */
@@ -53,18 +56,19 @@ public class TreeParams {
public static TreeParams oak() { public static TreeParams oak() {
TreeParams p = new TreeParams(); TreeParams p = new TreeParams();
p.seed = 35729; p.seed = 35729;
p.levels = 3; p.levels = 3;
p.gravityStrength = 0.04f; p.trunkUprightness = 0.14f;
p.angle = new float[]{ 0f, 54f, 58f, 32f }; p.outwardness = new float[]{ 0f, 0.09f, 0.07f, 0.05f };
p.children = new int[] { 6, 4, 3, 0 }; p.angle = new float[]{ 0f, 54f, 58f, 32f };
p.start = new float[]{ 0.0f, 0.35f, 0.20f, 0.10f }; p.children = new int[] { 6, 4, 3, 0 };
p.length = new float[]{ 14f, 11f, 8f, 1.5f}; p.start = new float[]{ 0.0f, 0.35f, 0.20f, 0.10f };
p.radius = new float[]{ 0.45f, 0.20f, 0.11f, 0.06f }; p.length = new float[]{ 14f, 11f, 8f, 1.5f};
p.sections = new int[] { 8, 6, 4, 2 }; p.radius = new float[]{ 0.45f, 0.20f, 0.11f, 0.06f };
p.segments = new int[] { 8, 6, 4, 3 }; p.sections = new int[] { 8, 6, 4, 2 };
p.taper = new float[]{ 0.73f, 0.65f, 0.69f, 0.75f }; p.segments = new int[] { 8, 6, 4, 3 };
p.gnarliness= new float[]{ 0.00f, 0.10f, 0.15f, 0.09f }; p.taper = new float[]{ 0.22f, 0.30f, 0.42f, 0.58f };
p.gnarliness = new float[]{ 0.40f, 0.10f, 0.15f, 0.09f };
p.leafScale = 1.4f; p.leafCount = 6; p.leafAngle = 42f; p.leafBranchings = 2; p.leafScale = 1.4f; p.leafCount = 6; p.leafAngle = 42f; p.leafBranchings = 2;
p.trunkFlexibility = 0.04f; p.branchFlexibility = 0.85f; p.trunkFlexibility = 0.04f; p.branchFlexibility = 0.85f;
p.barkTexture = "Textures/internal/bark/Bark001_Color.jpg"; p.barkTexture = "Textures/internal/bark/Bark001_Color.jpg";
@@ -74,18 +78,19 @@ public class TreeParams {
public static TreeParams birch() { public static TreeParams birch() {
TreeParams p = new TreeParams(); TreeParams p = new TreeParams();
p.seed = 11204; p.seed = 11204;
p.levels = 3; p.levels = 3;
p.gravityStrength = 0.01f; p.trunkUprightness = 0.18f; // Birke wächst besonders gerade
p.angle = new float[]{ 0f, 45f, 40f, 25f }; p.outwardness = new float[]{ 0f, 0.07f, 0.06f, 0.04f };
p.children = new int[] { 4, 3, 3, 0 }; p.angle = new float[]{ 0f, 45f, 40f, 25f };
p.start = new float[]{ 0.0f, 0.45f, 0.30f, 0.10f }; p.children = new int[] { 4, 3, 3, 0 };
p.length = new float[]{ 18f, 12f, 6f, 1.2f}; p.start = new float[]{ 0.0f, 0.45f, 0.30f, 0.10f };
p.radius = new float[]{ 0.30f, 0.12f, 0.07f, 0.04f }; p.length = new float[]{ 18f, 12f, 6f, 1.2f};
p.sections = new int[] { 10, 7, 4, 2 }; p.radius = new float[]{ 0.30f, 0.12f, 0.07f, 0.04f };
p.segments = new int[] { 7, 5, 4, 3 }; p.sections = new int[] { 10, 7, 4, 2 };
p.taper = new float[]{ 0.68f, 0.60f, 0.62f, 0.70f }; p.segments = new int[] { 7, 5, 4, 3 };
p.gnarliness= new float[]{ 0.00f, 0.05f, 0.10f, 0.04f }; p.taper = new float[]{ 0.16f, 0.25f, 0.38f, 0.55f };
p.gnarliness = new float[]{ 0.25f, 0.05f, 0.10f, 0.04f };
p.leafScale = 0.9f; p.leafCount = 4; p.leafAngle = 38f; p.leafBranchings = 1; p.leafScale = 0.9f; p.leafCount = 4; p.leafAngle = 38f; p.leafBranchings = 1;
p.trunkFlexibility = 0.03f; p.branchFlexibility = 0.95f; p.trunkFlexibility = 0.03f; p.branchFlexibility = 0.95f;
p.barkTexture = "Textures/internal/bark/Bark002_Color.jpg"; p.barkTexture = "Textures/internal/bark/Bark002_Color.jpg";
@@ -95,18 +100,19 @@ public class TreeParams {
public static TreeParams pine() { public static TreeParams pine() {
TreeParams p = new TreeParams(); TreeParams p = new TreeParams();
p.seed = 72831; p.seed = 72831;
p.levels = 3; p.levels = 3;
p.gravityStrength = -0.015f; p.trunkUprightness = 0.20f; // Kiefer sehr aufrecht
p.angle = new float[]{ 0f, 75f, 60f, 40f }; p.outwardness = new float[]{ 0f, 0.10f, 0.08f, 0.05f };
p.children = new int[] { 7, 5, 4, 0 }; p.angle = new float[]{ 0f, 75f, 60f, 40f };
p.start = new float[]{ 0.0f, 0.15f, 0.20f, 0.10f }; p.children = new int[] { 7, 5, 4, 0 };
p.length = new float[]{ 12f, 7f, 4f, 0.8f}; p.start = new float[]{ 0.0f, 0.15f, 0.20f, 0.10f };
p.radius = new float[]{ 0.35f, 0.12f, 0.07f, 0.04f }; p.length = new float[]{ 12f, 7f, 4f, 0.8f};
p.sections = new int[] { 8, 5, 3, 2 }; p.radius = new float[]{ 0.35f, 0.12f, 0.07f, 0.04f };
p.segments = new int[] { 7, 5, 4, 3 }; p.sections = new int[] { 8, 5, 3, 2 };
p.taper = new float[]{ 0.65f, 0.58f, 0.60f, 0.65f }; p.segments = new int[] { 7, 5, 4, 3 };
p.gnarliness= new float[]{ 0.00f, 0.03f, 0.08f, 0.02f }; p.taper = new float[]{ 0.20f, 0.28f, 0.40f, 0.58f };
p.gnarliness = new float[]{ 0.25f, 0.03f, 0.08f, 0.02f };
p.leafScale = 0.7f; p.leafCount = 8; p.leafAngle = 70f; p.leafBranchings = 1; p.leafScale = 0.7f; p.leafCount = 8; p.leafAngle = 70f; p.leafBranchings = 1;
p.trunkFlexibility = 0.03f; p.branchFlexibility = 0.70f; p.trunkFlexibility = 0.03f; p.branchFlexibility = 0.70f;
p.barkTexture = "Textures/internal/bark/Bark003_Color.jpg"; p.barkTexture = "Textures/internal/bark/Bark003_Color.jpg";
@@ -116,18 +122,19 @@ public class TreeParams {
public static TreeParams willow() { public static TreeParams willow() {
TreeParams p = new TreeParams(); TreeParams p = new TreeParams();
p.seed = 54321; p.seed = 54321;
p.levels = 3; p.levels = 3;
p.gravityStrength = 0.12f; p.trunkUprightness = 0.12f;
p.angle = new float[]{ 0f, 60f, 50f, 35f }; p.outwardness = new float[]{ 0f, 0.08f, 0.07f, 0.05f };
p.children = new int[] { 5, 4, 3, 0 }; p.angle = new float[]{ 0f, 60f, 50f, 35f };
p.start = new float[]{ 0.0f, 0.30f, 0.20f, 0.10f }; p.children = new int[] { 5, 4, 3, 0 };
p.length = new float[]{ 10f, 12f, 8f, 2.0f}; p.start = new float[]{ 0.0f, 0.30f, 0.20f, 0.10f };
p.radius = new float[]{ 0.38f, 0.16f, 0.09f, 0.05f }; p.length = new float[]{ 10f, 12f, 8f, 2.0f};
p.sections = new int[] { 8, 8, 5, 3 }; p.radius = new float[]{ 0.38f, 0.16f, 0.09f, 0.05f };
p.segments = new int[] { 7, 5, 4, 3 }; p.sections = new int[] { 8, 8, 5, 3 };
p.taper = new float[]{ 0.72f, 0.68f, 0.65f, 0.72f }; p.segments = new int[] { 7, 5, 4, 3 };
p.gnarliness= new float[]{ 0.00f, 0.25f, 0.35f, 0.15f }; p.taper = new float[]{ 0.26f, 0.32f, 0.44f, 0.58f };
p.gnarliness = new float[]{ 0.30f, 0.25f, 0.35f, 0.15f };
p.leafScale = 1.5f; p.leafCount = 7; p.leafAngle = 55f; p.leafBranchings = 2; p.leafScale = 1.5f; p.leafCount = 7; p.leafAngle = 55f; p.leafBranchings = 2;
p.trunkFlexibility = 0.06f; p.branchFlexibility = 0.98f; p.trunkFlexibility = 0.06f; p.branchFlexibility = 0.98f;
p.barkTexture = "Textures/internal/bark/Bark001_Color.jpg"; p.barkTexture = "Textures/internal/bark/Bark001_Color.jpg";
@@ -137,18 +144,19 @@ public class TreeParams {
public static TreeParams bush() { public static TreeParams bush() {
TreeParams p = new TreeParams(); TreeParams p = new TreeParams();
p.seed = 9876; p.seed = 9876;
p.levels = 2; p.levels = 2;
p.gravityStrength = 0.02f; p.trunkUprightness = 0.08f;
p.angle = new float[]{ 0f, 65f, 55f, 40f }; p.outwardness = new float[]{ 0f, 0.10f, 0.08f, 0.05f };
p.children = new int[] { 8, 5, 0, 0 }; p.angle = new float[]{ 0f, 65f, 55f, 40f };
p.start = new float[]{ 0.0f, 0.10f, 0.15f, 0.10f }; p.children = new int[] { 8, 5, 0, 0 };
p.length = new float[]{ 2f, 2f, 1.2f, 0.5f}; p.start = new float[]{ 0.0f, 0.10f, 0.15f, 0.10f };
p.radius = new float[]{ 0.18f, 0.08f, 0.05f, 0.03f }; p.length = new float[]{ 2f, 2f, 1.2f, 0.5f};
p.sections = new int[] { 4, 4, 3, 2 }; p.radius = new float[]{ 0.18f, 0.08f, 0.05f, 0.03f };
p.segments = new int[] { 6, 5, 4, 3 }; p.sections = new int[] { 4, 4, 3, 2 };
p.taper = new float[]{ 0.65f, 0.60f, 0.62f, 0.65f }; p.segments = new int[] { 6, 5, 4, 3 };
p.gnarliness= new float[]{ 0.00f, 0.15f, 0.25f, 0.10f }; p.taper = new float[]{ 0.65f, 0.60f, 0.62f, 0.65f };
p.gnarliness = new float[]{ 0.00f, 0.15f, 0.25f, 0.10f };
p.leafScale = 1.0f; p.leafCount = 5; p.leafAngle = 50f; p.leafBranchings = 2; p.leafScale = 1.0f; p.leafCount = 5; p.leafAngle = 50f; p.leafBranchings = 2;
p.trunkFlexibility = 0.05f; p.branchFlexibility = 0.90f; p.trunkFlexibility = 0.05f; p.branchFlexibility = 0.90f;
p.barkTexture = "Textures/internal/bark/Bark001_Color.jpg"; p.barkTexture = "Textures/internal/bark/Bark001_Color.jpg";
@@ -160,10 +168,11 @@ public class TreeParams {
public TreeParams copy() { public TreeParams copy() {
TreeParams c = new TreeParams(); TreeParams c = new TreeParams();
c.seed = seed; c.seed = seed;
c.levels = levels; c.levels = levels;
c.gravityStrength = gravityStrength; c.trunkUprightness = trunkUprightness;
c.angle = angle.clone(); c.outwardness = outwardness.clone();
c.angle = angle.clone();
c.children = children.clone(); c.children = children.clone();
c.start = start.clone(); c.start = start.clone();
c.length = length.clone(); c.length = length.clone();