diff --git a/blight-assets/src/main/resources/Shaders/Tree.vert b/blight-assets/src/main/resources/Shaders/Tree.vert index 47b4280..b6b3b80 100644 --- a/blight-assets/src/main/resources/Shaders/Tree.vert +++ b/blight-assets/src/main/resources/Shaders/Tree.vert @@ -16,7 +16,8 @@ out vec2 texCoord; out vec3 worldNormal; 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; 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])); 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 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 float sway2 = mainSway * mainSway + crossSway * crossSway; vec3 animPos = inPosition + vec3( - windN.x * mainSway + perpN.x * crossSway, + windN.x * mainSway + perpN.x * crossSway + perpN.x * flutter, -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); diff --git a/blight-editor/src/main/java/de/blight/editor/EditorApp.java b/blight-editor/src/main/java/de/blight/editor/EditorApp.java index 1c7a4b7..5489185 100644 --- a/blight-editor/src/main/java/de/blight/editor/EditorApp.java +++ b/blight-editor/src/main/java/de/blight/editor/EditorApp.java @@ -1939,9 +1939,9 @@ public class EditorApp extends Application { levelSpinner.valueProperty().addListener((o, a, b) -> treeParams.levels = b); inner.getChildren().add(levelSpinner); - // Gravitation - inner.getChildren().add(paramSlider("Gravitation:", -0.15, 0.20, treeParams.gravityStrength, - v -> treeParams.gravityStrength = v)); + // Stamm-Aufrichtung + inner.getChildren().add(paramSlider("Stamm-Aufrichtung:", 0.0, 0.40, treeParams.trunkUprightness, + v -> treeParams.trunkUprightness = v)); inner.getChildren().add(new Separator()); diff --git a/blight-editor/src/main/java/de/blight/editor/tree/TreeMeshBuilder.java b/blight-editor/src/main/java/de/blight/editor/tree/TreeMeshBuilder.java index af9bd81..d7d5fb4 100644 --- a/blight-editor/src/main/java/de/blight/editor/tree/TreeMeshBuilder.java +++ b/blight-editor/src/main/java/de/blight/editor/tree/TreeMeshBuilder.java @@ -39,12 +39,14 @@ public class TreeMeshBuilder { VertexCollector barkCol = 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) {} Deque stack = new ArrayDeque<>(); 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()) { BranchTask t = stack.pop(); @@ -75,28 +77,78 @@ public class TreeMeshBuilder { Vector3f dir = t.dir().clone(); List sectionPts = new ArrayList<>(numSec); - for (int s = 0; s < numSec; s++) { - float rBot = baseRad * lerp(1f, tapFactor, (float) s / numSec); - float rTop = baseRad * lerp(1f, tapFactor, (float)(s + 1) / numSec); - float wBot = lerp(t.windBase(), windEnd, (float) s / numSec); - float wTop = lerp(t.windBase(), windEnd, (float)(s + 1) / numSec); + // Alle Sektionspunkte sammeln, danach als nahtlose Röhre (Bisektor-Ringe, + // kein Parallel-Transport-Twisting, keine Lücken an Richtungswechseln). + Vector3f[] tubePts = new Vector3f[numSec + 1]; + float[] tubeRad = new float[numSec + 1]; + 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) - if (lv > 0 && gnarl > 1e-4f) { - float g = gnarl / (float) Math.sqrt(Math.max(0.01f, rBot)); + for (int s = 0; s < numSec; s++) { + float t0 = (float) s / numSec; + 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.z += rng.range(-g, g); dir.normalizeLocal(); } - // Gravitation: Richtung graduell zur Gravitations-Richtung drehen - applyGravity(dir, rBot, p.gravityStrength); + // Wachstumstendenz per Level + 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)); - 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; } + buildTube(barkCol, tubePts, tubeRad, tubeWind, segs); if (lv < maxLevel - 1) { // Kind-Äste stratifiziert entlang des Eltern-Astes verteilen @@ -114,7 +166,7 @@ public class TreeMeshBuilder { float nextAngle = TreeParams.lv(p.angle, lv + 1); stack.push(new BranchTask( sp.pos(), branchDir(sp.dir(), yRot, nextAngle), - lv + 1, sp.wind())); + sp.dir().clone(), lv + 1, sp.wind())); } } else if (p.generateLeaves) { // Blätter entlang des gesamten letzten Astes (jede Sektion) @@ -137,9 +189,11 @@ public class TreeMeshBuilder { + rng.range(-0.5f, 0.5f); Vector3f twigDir = branchDir(sp.dir(), yRot, twigAngle); Vector3f twigEnd = sp.pos().add(twigDir.mult(twigLen)); - addCylinder(barkCol, sp.pos(), twigEnd, - twigRad, twigRad * 0.35f, - sp.wind(), windEnd, Math.max(3, segs - 1)); + buildTube(barkCol, + new Vector3f[]{sp.pos(), twigEnd}, + new float[]{twigRad, twigRad * 0.35f}, + new float[]{sp.wind(), windEnd}, + Math.max(3, segs - 1)); addLeafCluster(leafCol, twigEnd, windEnd, p.leafScale, p.leafCount, p.leafAngle, rng); } @@ -151,20 +205,18 @@ public class TreeMeshBuilder { 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) { - if (Math.abs(strength) < 1e-5f) return; - // strength > 0 → nach unten ziehen; strength < 0 → nach oben ziehen - Vector3f target = new Vector3f(0, strength > 0 ? -1f : 1f, 0); - Vector3f axis = dir.cross(target); - float sinFull = axis.length(); - if (sinFull < 1e-6f) return; - axis.divideLocal(sinFull); - float fullAngle = FastMath.atan2(sinFull, dir.dot(target)); - 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); + private static void applyTendency(Vector3f dir, Vector3f ideal, float strength) { + if (strength < 1e-5f) return; + Vector3f axis = dir.cross(ideal); + float sinA = axis.length(); + if (sinA < 1e-6f) return; + axis.divideLocal(sinA); + float angle = FastMath.atan2(sinA, dir.dot(ideal)); + float step = FastMath.clamp(strength, 0f, angle); + new Quaternion().fromAngleAxis(step, axis).multLocal(dir); dir.normalizeLocal(); } @@ -172,48 +224,73 @@ public class TreeMeshBuilder { 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, - Vector3f start, Vector3f end, - float rBot, float rTop, - float windBot, float windTop, - int N) { - Vector3f axis = end.subtract(start); - if (axis.lengthSquared() < 1e-8f) return; - axis.normalizeLocal(); + private static void buildTube(VertexCollector col, + Vector3f[] pts, float[] radii, float[] winds, int N) { + int nPts = pts.length; + if (nPts < 2) return; - Vector3f perp1 = (Math.abs(axis.y) < 0.9f) - ? axis.cross(Vector3f.UNIT_Y).normalizeLocal() - : axis.cross(Vector3f.UNIT_X).normalizeLocal(); - Vector3f perp2 = axis.cross(perp1).normalizeLocal(); - - 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); - } + Vector3f[] segDir = new Vector3f[nPts - 1]; + for (int i = 0; i < nPts - 1; i++) { + segDir[i] = pts[i + 1].subtract(pts[i]); + float len = segDir[i].length(); + if (len > 1e-6f) segDir[i].divideLocal(len); else segDir[i].set(0, 1, 0); } - for (int i = 0; i < N; i++) { - int b0 = base + i, b1 = base + i + 1; - int t0 = base + N1 + i, t1 = base + N1 + i + 1; - col.tri(b0, b1, t1); - col.tri(b0, t1, t0); + Vector3f[] ringAxis = new Vector3f[nPts]; + ringAxis[0] = segDir[0].clone(); + ringAxis[nPts - 1] = segDir[nPts - 2].clone(); + for (int i = 1; i < nPts - 1; i++) { + 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 nz = rx * gy - ry * gx; - float windTip = Math.min(1.0f, wind + 0.25f); 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, - nx, ny, nz, 0f, 0f, wind); + nx, ny, nz, 0f, 0f, wind, 0f); col.add(cx + rx * hw, cy + ry * hw, cz + rz * hw, - nx, ny, nz, 1f, 0f, wind); - // Obere Kante frei (schwingt im Wind) + nx, ny, nz, 1f, 0f, wind, 0f); + // Obere Kante: flattert zusätzlich (flutter=1) 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, - nx, ny, nz, 0f, 1f, windTip); + nx, ny, nz, 0f, 1f, wind, 1f); col.tri(base, base + 1, base + 2); col.tri(base, base + 2, base + 3); @@ -343,10 +419,16 @@ public class TreeMeshBuilder { void add(float x, float y, float z, float nx, float ny, float nz, 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); norm.add(nx); norm.add(ny); norm.add(nz); 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++; } diff --git a/blight-editor/src/main/java/de/blight/editor/tree/TreeParams.java b/blight-editor/src/main/java/de/blight/editor/tree/TreeParams.java index 18c02e9..d100bcf 100644 --- a/blight-editor/src/main/java/de/blight/editor/tree/TreeParams.java +++ b/blight-editor/src/main/java/de/blight/editor/tree/TreeParams.java @@ -9,9 +9,12 @@ package de.blight.editor.tree; public class TreeParams { // ── Global ──────────────────────────────────────────────────────────────── - public int seed = 42; - public int levels = 3; // Rekursionstiefe (1–4) - public float gravityStrength = 0.03f; // >0 = Äste hängen, <0 = aufwärts (Tanne) + public int seed = 42; + public int levels = 3; // Rekursionstiefe (1–4) + /** 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) ────────────────────────────────────── /** Astwinkel zur Eltern-Richtung in Grad (Level 0 = Stamm, ignoriert). */ @@ -53,18 +56,19 @@ public class TreeParams { public static TreeParams oak() { TreeParams p = new TreeParams(); - p.seed = 35729; - p.levels = 3; - p.gravityStrength = 0.04f; - p.angle = new float[]{ 0f, 54f, 58f, 32f }; - p.children = new int[] { 6, 4, 3, 0 }; - p.start = new float[]{ 0.0f, 0.35f, 0.20f, 0.10f }; - p.length = new float[]{ 14f, 11f, 8f, 1.5f}; - p.radius = new float[]{ 0.45f, 0.20f, 0.11f, 0.06f }; - p.sections = new int[] { 8, 6, 4, 2 }; - p.segments = new int[] { 8, 6, 4, 3 }; - p.taper = new float[]{ 0.73f, 0.65f, 0.69f, 0.75f }; - p.gnarliness= new float[]{ 0.00f, 0.10f, 0.15f, 0.09f }; + p.seed = 35729; + p.levels = 3; + p.trunkUprightness = 0.14f; + p.outwardness = new float[]{ 0f, 0.09f, 0.07f, 0.05f }; + p.angle = new float[]{ 0f, 54f, 58f, 32f }; + p.children = new int[] { 6, 4, 3, 0 }; + p.start = new float[]{ 0.0f, 0.35f, 0.20f, 0.10f }; + p.length = new float[]{ 14f, 11f, 8f, 1.5f}; + p.radius = new float[]{ 0.45f, 0.20f, 0.11f, 0.06f }; + p.sections = new int[] { 8, 6, 4, 2 }; + p.segments = new int[] { 8, 6, 4, 3 }; + 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.trunkFlexibility = 0.04f; p.branchFlexibility = 0.85f; p.barkTexture = "Textures/internal/bark/Bark001_Color.jpg"; @@ -74,18 +78,19 @@ public class TreeParams { public static TreeParams birch() { TreeParams p = new TreeParams(); - p.seed = 11204; - p.levels = 3; - p.gravityStrength = 0.01f; - p.angle = new float[]{ 0f, 45f, 40f, 25f }; - p.children = new int[] { 4, 3, 3, 0 }; - p.start = new float[]{ 0.0f, 0.45f, 0.30f, 0.10f }; - p.length = new float[]{ 18f, 12f, 6f, 1.2f}; - p.radius = new float[]{ 0.30f, 0.12f, 0.07f, 0.04f }; - p.sections = new int[] { 10, 7, 4, 2 }; - p.segments = new int[] { 7, 5, 4, 3 }; - p.taper = new float[]{ 0.68f, 0.60f, 0.62f, 0.70f }; - p.gnarliness= new float[]{ 0.00f, 0.05f, 0.10f, 0.04f }; + p.seed = 11204; + p.levels = 3; + p.trunkUprightness = 0.18f; // Birke wächst besonders gerade + p.outwardness = new float[]{ 0f, 0.07f, 0.06f, 0.04f }; + p.angle = new float[]{ 0f, 45f, 40f, 25f }; + p.children = new int[] { 4, 3, 3, 0 }; + p.start = new float[]{ 0.0f, 0.45f, 0.30f, 0.10f }; + p.length = new float[]{ 18f, 12f, 6f, 1.2f}; + p.radius = new float[]{ 0.30f, 0.12f, 0.07f, 0.04f }; + p.sections = new int[] { 10, 7, 4, 2 }; + p.segments = new int[] { 7, 5, 4, 3 }; + 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.trunkFlexibility = 0.03f; p.branchFlexibility = 0.95f; p.barkTexture = "Textures/internal/bark/Bark002_Color.jpg"; @@ -95,18 +100,19 @@ public class TreeParams { public static TreeParams pine() { TreeParams p = new TreeParams(); - p.seed = 72831; - p.levels = 3; - p.gravityStrength = -0.015f; - p.angle = new float[]{ 0f, 75f, 60f, 40f }; - p.children = new int[] { 7, 5, 4, 0 }; - p.start = new float[]{ 0.0f, 0.15f, 0.20f, 0.10f }; - p.length = new float[]{ 12f, 7f, 4f, 0.8f}; - p.radius = new float[]{ 0.35f, 0.12f, 0.07f, 0.04f }; - p.sections = new int[] { 8, 5, 3, 2 }; - p.segments = new int[] { 7, 5, 4, 3 }; - p.taper = new float[]{ 0.65f, 0.58f, 0.60f, 0.65f }; - p.gnarliness= new float[]{ 0.00f, 0.03f, 0.08f, 0.02f }; + p.seed = 72831; + p.levels = 3; + p.trunkUprightness = 0.20f; // Kiefer sehr aufrecht + p.outwardness = new float[]{ 0f, 0.10f, 0.08f, 0.05f }; + p.angle = new float[]{ 0f, 75f, 60f, 40f }; + p.children = new int[] { 7, 5, 4, 0 }; + p.start = new float[]{ 0.0f, 0.15f, 0.20f, 0.10f }; + p.length = new float[]{ 12f, 7f, 4f, 0.8f}; + p.radius = new float[]{ 0.35f, 0.12f, 0.07f, 0.04f }; + p.sections = new int[] { 8, 5, 3, 2 }; + p.segments = new int[] { 7, 5, 4, 3 }; + 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.trunkFlexibility = 0.03f; p.branchFlexibility = 0.70f; p.barkTexture = "Textures/internal/bark/Bark003_Color.jpg"; @@ -116,18 +122,19 @@ public class TreeParams { public static TreeParams willow() { TreeParams p = new TreeParams(); - p.seed = 54321; - p.levels = 3; - p.gravityStrength = 0.12f; - p.angle = new float[]{ 0f, 60f, 50f, 35f }; - p.children = new int[] { 5, 4, 3, 0 }; - p.start = new float[]{ 0.0f, 0.30f, 0.20f, 0.10f }; - p.length = new float[]{ 10f, 12f, 8f, 2.0f}; - p.radius = new float[]{ 0.38f, 0.16f, 0.09f, 0.05f }; - p.sections = new int[] { 8, 8, 5, 3 }; - p.segments = new int[] { 7, 5, 4, 3 }; - p.taper = new float[]{ 0.72f, 0.68f, 0.65f, 0.72f }; - p.gnarliness= new float[]{ 0.00f, 0.25f, 0.35f, 0.15f }; + p.seed = 54321; + p.levels = 3; + p.trunkUprightness = 0.12f; + p.outwardness = new float[]{ 0f, 0.08f, 0.07f, 0.05f }; + p.angle = new float[]{ 0f, 60f, 50f, 35f }; + p.children = new int[] { 5, 4, 3, 0 }; + p.start = new float[]{ 0.0f, 0.30f, 0.20f, 0.10f }; + p.length = new float[]{ 10f, 12f, 8f, 2.0f}; + p.radius = new float[]{ 0.38f, 0.16f, 0.09f, 0.05f }; + p.sections = new int[] { 8, 8, 5, 3 }; + p.segments = new int[] { 7, 5, 4, 3 }; + 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.trunkFlexibility = 0.06f; p.branchFlexibility = 0.98f; p.barkTexture = "Textures/internal/bark/Bark001_Color.jpg"; @@ -137,18 +144,19 @@ public class TreeParams { public static TreeParams bush() { TreeParams p = new TreeParams(); - p.seed = 9876; - p.levels = 2; - p.gravityStrength = 0.02f; - p.angle = new float[]{ 0f, 65f, 55f, 40f }; - p.children = new int[] { 8, 5, 0, 0 }; - p.start = new float[]{ 0.0f, 0.10f, 0.15f, 0.10f }; - p.length = new float[]{ 2f, 2f, 1.2f, 0.5f}; - p.radius = new float[]{ 0.18f, 0.08f, 0.05f, 0.03f }; - p.sections = new int[] { 4, 4, 3, 2 }; - p.segments = new int[] { 6, 5, 4, 3 }; - 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.seed = 9876; + p.levels = 2; + p.trunkUprightness = 0.08f; + p.outwardness = new float[]{ 0f, 0.10f, 0.08f, 0.05f }; + p.angle = new float[]{ 0f, 65f, 55f, 40f }; + p.children = new int[] { 8, 5, 0, 0 }; + p.start = new float[]{ 0.0f, 0.10f, 0.15f, 0.10f }; + p.length = new float[]{ 2f, 2f, 1.2f, 0.5f}; + p.radius = new float[]{ 0.18f, 0.08f, 0.05f, 0.03f }; + p.sections = new int[] { 4, 4, 3, 2 }; + p.segments = new int[] { 6, 5, 4, 3 }; + 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.trunkFlexibility = 0.05f; p.branchFlexibility = 0.90f; p.barkTexture = "Textures/internal/bark/Bark001_Color.jpg"; @@ -160,10 +168,11 @@ public class TreeParams { public TreeParams copy() { TreeParams c = new TreeParams(); - c.seed = seed; - c.levels = levels; - c.gravityStrength = gravityStrength; - c.angle = angle.clone(); + c.seed = seed; + c.levels = levels; + c.trunkUprightness = trunkUprightness; + c.outwardness = outwardness.clone(); + c.angle = angle.clone(); c.children = children.clone(); c.start = start.clone(); c.length = length.clone();