VegetationEditor: EZ-Tree Windanimation + Palm-Textur-Rotation fix
EzTreeState: addWindWeights() setzt VertexBuffer.Color (R = Wind-Gewicht) nach der Mesh-Erzeugung. Blätter bekommen 1.0 (volle Animation), Äste werden per Y-Position normiert. Tree.vert liest windW aus inColor.r — ohne diesen Buffer blieb windW=0 und kein Schwingen sichtbar. PalmMeshBuilder/PalmGeneratorState: stemLeft immer true (Stiel entlang U), leafTextureAspect immer h/w. Behebt die 90°-Drehung von palm.png. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -38,6 +38,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@@ -120,10 +121,12 @@ public class EzTreeState extends BaseAppState {
|
|||||||
|
|
||||||
Node hdNode = tryNodeJsGeneration(req);
|
Node hdNode = tryNodeJsGeneration(req);
|
||||||
if (hdNode == null) hdNode = javaFallback(req);
|
if (hdNode == null) hdNode = javaFallback(req);
|
||||||
|
addWindWeights(hdNode);
|
||||||
hdNode.setLocalScale(1f / 3f);
|
hdNode.setLocalScale(1f / 3f);
|
||||||
hdNode.updateGeometricState();
|
hdNode.updateGeometricState();
|
||||||
|
|
||||||
Node ld1Node = buildLod1Node(req);
|
Node ld1Node = buildLod1Node(req);
|
||||||
|
addWindWeights(ld1Node);
|
||||||
ld1Node.setLocalScale(1f / 3f);
|
ld1Node.setLocalScale(1f / 3f);
|
||||||
|
|
||||||
BoundingBox bb = boundsOf(hdNode);
|
BoundingBox bb = boundsOf(hdNode);
|
||||||
@@ -681,6 +684,51 @@ public class EzTreeState extends BaseAppState {
|
|||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setzt Vertex-Farben (R = Wind-Gewicht) für alle Geometrien eines Baum-Knotens.
|
||||||
|
* Blätter bekommen Gewicht 1.0 (volle Animation); Äste werden per Y-Position
|
||||||
|
* normiert (0 = Boden, 1 = Spitze), sodass höhere Äste stärker schwingen.
|
||||||
|
* Tree.vert liest den Wind-Weight aus inColor.r — ohne diesen Buffer bleibt windW=0.
|
||||||
|
*/
|
||||||
|
private static void addWindWeights(Node treeNode) {
|
||||||
|
for (Spatial child : treeNode.getChildren()) {
|
||||||
|
if (!(child instanceof Geometry g)) continue;
|
||||||
|
Mesh mesh = g.getMesh();
|
||||||
|
FloatBuffer pos = mesh.getFloatBuffer(VertexBuffer.Type.Position);
|
||||||
|
if (pos == null) continue;
|
||||||
|
pos.rewind();
|
||||||
|
int vCount = pos.limit() / 3;
|
||||||
|
float[] colors = new float[vCount * 4];
|
||||||
|
boolean isLeaf = g.getName().contains("leav") || g.getName().contains("leaf");
|
||||||
|
|
||||||
|
if (isLeaf) {
|
||||||
|
for (int i = 0; i < vCount; i++) {
|
||||||
|
colors[i * 4] = 1f;
|
||||||
|
colors[i * 4 + 3] = 1f;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
float minY = Float.MAX_VALUE, maxY = -Float.MAX_VALUE;
|
||||||
|
for (int i = 0; i < vCount; i++) {
|
||||||
|
pos.get();
|
||||||
|
float y = pos.get();
|
||||||
|
pos.get();
|
||||||
|
if (y < minY) minY = y;
|
||||||
|
if (y > maxY) maxY = y;
|
||||||
|
}
|
||||||
|
float range = maxY - minY;
|
||||||
|
pos.rewind();
|
||||||
|
for (int i = 0; i < vCount; i++) {
|
||||||
|
pos.get();
|
||||||
|
float y = pos.get();
|
||||||
|
pos.get();
|
||||||
|
colors[i * 4] = range > 0f ? (y - minY) / range : 0f;
|
||||||
|
colors[i * 4 + 3] = 1f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mesh.setBuffer(VertexBuffer.Type.Color, 4, BufferUtils.createFloatBuffer(colors));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void exportTree(Node lodRoot, String fileName, String subPath) {
|
private void exportTree(Node lodRoot, String fileName, String subPath) {
|
||||||
try {
|
try {
|
||||||
Path baseDir = ASSET_ROOT.resolve("Models").resolve("trees").resolve(subPath);
|
Path baseDir = ASSET_ROOT.resolve("Models").resolve("trees").resolve(subPath);
|
||||||
|
|||||||
@@ -113,8 +113,7 @@ public class PalmGeneratorState extends BaseAppState {
|
|||||||
Texture t = assets.loadTexture(opts.leafTexture);
|
Texture t = assets.loadTexture(opts.leafTexture);
|
||||||
int w = t.getImage().getWidth();
|
int w = t.getImage().getWidth();
|
||||||
int h = t.getImage().getHeight();
|
int h = t.getImage().getHeight();
|
||||||
boolean stemLeft = opts.leafTexture.contains("palm2");
|
opts.leafTextureAspect = (float) h / w; // Stiel entlang U → Aspekt = Höhe/Breite
|
||||||
opts.leafTextureAspect = stemLeft ? (float) h / w : (float) w / h;
|
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ public class PalmMeshBuilder {
|
|||||||
float halfW = opts.leafTextureAspect > 0f
|
float halfW = opts.leafTextureAspect > 0f
|
||||||
? scaledLength * opts.leafTextureAspect * 0.5f
|
? scaledLength * opts.leafTextureAspect * 0.5f
|
||||||
: opts.frondWidth * sizeScale * 0.5f;
|
: opts.frondWidth * sizeScale * 0.5f;
|
||||||
boolean stemLeft = opts.leafTexture != null && opts.leafTexture.contains("palm2");
|
boolean stemLeft = true; // Stiel entlang U-Achse für alle Palmen-Texturen
|
||||||
float g = opts.gravity;
|
float g = opts.gravity;
|
||||||
|
|
||||||
int base = acc.vertexCount;
|
int base = acc.vertexCount;
|
||||||
|
|||||||
Reference in New Issue
Block a user