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;
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);

View File

@@ -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());

View File

@@ -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<BranchTask> 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<SectionPt> 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++;
}

View File

@@ -9,9 +9,12 @@ package de.blight.editor.tree;
public class TreeParams {
// ── Global ────────────────────────────────────────────────────────────────
public int seed = 42;
public int levels = 3; // Rekursionstiefe (14)
public float gravityStrength = 0.03f; // >0 = Äste hängen, <0 = aufwärts (Tanne)
public int seed = 42;
public int levels = 3; // Rekursionstiefe (14)
/** 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();