Texturierung von Voxel Terrain angepasst
This commit is contained in:
@@ -530,9 +530,9 @@ public class SculptedMeshEditorState extends BaseAppState {
|
||||
}
|
||||
}
|
||||
|
||||
com.jme3.texture.Texture2D a0 = tes.getSplatTex();
|
||||
com.jme3.texture.Texture2D a1 = tes.getUpperSplatTex();
|
||||
com.jme3.texture.Texture2D a2 = tes.getThirdSplatTex();
|
||||
com.jme3.texture.Texture2D a0 = tes.getVoxelSplatTex();
|
||||
com.jme3.texture.Texture2D a1 = tes.getVoxelUpperSplatTex();
|
||||
com.jme3.texture.Texture2D a2 = tes.getVoxelThirdSplatTex();
|
||||
if (a0 != null) { mat.setTexture("AlphaMap", a0); }
|
||||
if (a1 != null) { mat.setTexture("AlphaMap_1", a1); }
|
||||
if (a2 != null) { mat.setTexture("AlphaMap_2", a2); }
|
||||
|
||||
@@ -142,6 +142,22 @@ public class TerrainEditorState extends BaseAppState {
|
||||
private Image thirdSplatImage;
|
||||
private Texture2D thirdSplatTex;
|
||||
|
||||
// ── Voxel-Splatmaps (Sculpted-Mesh, unabhängig vom Basis-Terrain) ─────────
|
||||
private byte[] voxelSplatR, voxelSplatG, voxelSplatB, voxelSplatA;
|
||||
private ByteBuffer voxelSplatBuf;
|
||||
private Image voxelSplatImage;
|
||||
private Texture2D voxelSplatTex;
|
||||
|
||||
private byte[] voxelUpperSplatR, voxelUpperSplatG, voxelUpperSplatB, voxelUpperSplatA;
|
||||
private ByteBuffer voxelUpperSplatBuf;
|
||||
private Image voxelUpperSplatImage;
|
||||
private Texture2D voxelUpperSplatTex;
|
||||
|
||||
private byte[] voxelThirdSplatR, voxelThirdSplatG, voxelThirdSplatB, voxelThirdSplatA;
|
||||
private ByteBuffer voxelThirdSplatBuf;
|
||||
private Image voxelThirdSplatImage;
|
||||
private Texture2D voxelThirdSplatTex;
|
||||
|
||||
// ── Kameraposition ────────────────────────────────────────────────────────
|
||||
private static final float DEFAULT_CAM_Y = 50f;
|
||||
private static final float DEFAULT_PITCH = (float) (Math.PI / 4); // intern +45° → Kamera schaut 45° nach unten (JME 3.9: dir.y = -sin(pitch))
|
||||
@@ -476,6 +492,19 @@ public class TerrainEditorState extends BaseAppState {
|
||||
input.thirdTexturePaths, 0, MapData.TEXTURE_SLOTS);
|
||||
System.arraycopy(loadedMapData.thirdNormalMaps, 0,
|
||||
input.thirdNormalMapPaths, 0, MapData.TEXTURE_SLOTS);
|
||||
// Voxel-Splatmaps (Sculpted-Meshes, seit Version 17)
|
||||
voxelSplatR = loadedMapData.voxelSplatR.clone();
|
||||
voxelSplatG = loadedMapData.voxelSplatG.clone();
|
||||
voxelSplatB = loadedMapData.voxelSplatB.clone();
|
||||
voxelSplatA = loadedMapData.voxelSplatA.clone();
|
||||
voxelUpperSplatR = loadedMapData.voxelUpperSplatR.clone();
|
||||
voxelUpperSplatG = loadedMapData.voxelUpperSplatG.clone();
|
||||
voxelUpperSplatB = loadedMapData.voxelUpperSplatB.clone();
|
||||
voxelUpperSplatA = loadedMapData.voxelUpperSplatA.clone();
|
||||
voxelThirdSplatR = loadedMapData.voxelThirdSplatR.clone();
|
||||
voxelThirdSplatG = loadedMapData.voxelThirdSplatG.clone();
|
||||
voxelThirdSplatB = loadedMapData.voxelThirdSplatB.clone();
|
||||
voxelThirdSplatA = loadedMapData.voxelThirdSplatA.clone();
|
||||
if (loadedMapData.normalMapOrder != null && loadedMapData.normalMapOrder.length == 12)
|
||||
input.normalMapOrder = loadedMapData.normalMapOrder.clone();
|
||||
if (loadedMapData.diffuseScales != null && loadedMapData.diffuseScales.length == 12)
|
||||
@@ -507,6 +536,18 @@ public class TerrainEditorState extends BaseAppState {
|
||||
thirdSplatG = new byte[SPLAT_SIZE * SPLAT_SIZE];
|
||||
thirdSplatB = new byte[SPLAT_SIZE * SPLAT_SIZE];
|
||||
thirdSplatA = new byte[SPLAT_SIZE * SPLAT_SIZE];
|
||||
voxelSplatR = new byte[SPLAT_SIZE * SPLAT_SIZE];
|
||||
voxelSplatG = new byte[SPLAT_SIZE * SPLAT_SIZE];
|
||||
voxelSplatB = new byte[SPLAT_SIZE * SPLAT_SIZE];
|
||||
voxelSplatA = new byte[SPLAT_SIZE * SPLAT_SIZE];
|
||||
voxelUpperSplatR = new byte[SPLAT_SIZE * SPLAT_SIZE];
|
||||
voxelUpperSplatG = new byte[SPLAT_SIZE * SPLAT_SIZE];
|
||||
voxelUpperSplatB = new byte[SPLAT_SIZE * SPLAT_SIZE];
|
||||
voxelUpperSplatA = new byte[SPLAT_SIZE * SPLAT_SIZE];
|
||||
voxelThirdSplatR = new byte[SPLAT_SIZE * SPLAT_SIZE];
|
||||
voxelThirdSplatG = new byte[SPLAT_SIZE * SPLAT_SIZE];
|
||||
voxelThirdSplatB = new byte[SPLAT_SIZE * SPLAT_SIZE];
|
||||
voxelThirdSplatA = new byte[SPLAT_SIZE * SPLAT_SIZE];
|
||||
}
|
||||
|
||||
// A-Kanal aus alten Saves bereinigen (war für Fluss-Textur; nicht mehr verwendet)
|
||||
@@ -545,6 +586,39 @@ public class TerrainEditorState extends BaseAppState {
|
||||
thirdSplatTex.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
|
||||
thirdSplatTex.setMagFilter(Texture.MagFilter.Bilinear);
|
||||
|
||||
voxelSplatBuf = BufferUtils.createByteBuffer(SPLAT_SIZE * SPLAT_SIZE * 4);
|
||||
for (int i = 0; i < SPLAT_SIZE * SPLAT_SIZE; i++) {
|
||||
voxelSplatBuf.put(voxelSplatR[i]).put(voxelSplatG[i]).put(voxelSplatB[i]).put(voxelSplatA[i]);
|
||||
}
|
||||
voxelSplatBuf.flip();
|
||||
voxelSplatImage = new Image(Image.Format.RGBA8, SPLAT_SIZE, SPLAT_SIZE, voxelSplatBuf, ColorSpace.Linear);
|
||||
voxelSplatTex = new Texture2D(voxelSplatImage);
|
||||
voxelSplatTex.setWrap(Texture.WrapMode.EdgeClamp);
|
||||
voxelSplatTex.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
|
||||
voxelSplatTex.setMagFilter(Texture.MagFilter.Bilinear);
|
||||
|
||||
voxelUpperSplatBuf = BufferUtils.createByteBuffer(SPLAT_SIZE * SPLAT_SIZE * 4);
|
||||
for (int i = 0; i < SPLAT_SIZE * SPLAT_SIZE; i++) {
|
||||
voxelUpperSplatBuf.put(voxelUpperSplatR[i]).put(voxelUpperSplatG[i]).put(voxelUpperSplatB[i]).put(voxelUpperSplatA[i]);
|
||||
}
|
||||
voxelUpperSplatBuf.flip();
|
||||
voxelUpperSplatImage = new Image(Image.Format.RGBA8, SPLAT_SIZE, SPLAT_SIZE, voxelUpperSplatBuf, ColorSpace.Linear);
|
||||
voxelUpperSplatTex = new Texture2D(voxelUpperSplatImage);
|
||||
voxelUpperSplatTex.setWrap(Texture.WrapMode.EdgeClamp);
|
||||
voxelUpperSplatTex.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
|
||||
voxelUpperSplatTex.setMagFilter(Texture.MagFilter.Bilinear);
|
||||
|
||||
voxelThirdSplatBuf = BufferUtils.createByteBuffer(SPLAT_SIZE * SPLAT_SIZE * 4);
|
||||
for (int i = 0; i < SPLAT_SIZE * SPLAT_SIZE; i++) {
|
||||
voxelThirdSplatBuf.put(voxelThirdSplatR[i]).put(voxelThirdSplatG[i]).put(voxelThirdSplatB[i]).put(voxelThirdSplatA[i]);
|
||||
}
|
||||
voxelThirdSplatBuf.flip();
|
||||
voxelThirdSplatImage = new Image(Image.Format.RGBA8, SPLAT_SIZE, SPLAT_SIZE, voxelThirdSplatBuf, ColorSpace.Linear);
|
||||
voxelThirdSplatTex = new Texture2D(voxelThirdSplatImage);
|
||||
voxelThirdSplatTex.setWrap(Texture.WrapMode.EdgeClamp);
|
||||
voxelThirdSplatTex.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
|
||||
voxelThirdSplatTex.setMagFilter(Texture.MagFilter.Bilinear);
|
||||
|
||||
// loadedMapData wird ab hier nicht mehr gebraucht (letzter Verbraucher war
|
||||
// dieser Merge). Freigeben, weil terrainHeight allein ~1 GB (16385² floats)
|
||||
// belegt und sonst die ganze Session über unnötig im Heap hängt.
|
||||
@@ -954,6 +1028,139 @@ public class TerrainEditorState extends BaseAppState {
|
||||
}
|
||||
}
|
||||
|
||||
/** Malt Voxel-Basis-Texturen (Slots 1-4) auf die Voxel-Splatmap. */
|
||||
private void applyVoxelTexturePaint(Vector3f contact, float strength, int textureIndex) {
|
||||
float radius = (float) input.textureTool.brushRadius.getValue();
|
||||
float softEdge = radius + Math.min(radius * 0.5f, 2f * SPLAT_WE_PER_PX);
|
||||
int centerPX = Math.round((contact.x + WORLD_HALF) / SPLAT_WE_PER_PX);
|
||||
int centerPZ = (SPLAT_SIZE - 1) - Math.round((contact.z + WORLD_HALF) / SPLAT_WE_PER_PX);
|
||||
int pixR = (int) Math.ceil(softEdge / SPLAT_WE_PER_PX);
|
||||
boolean changed = false;
|
||||
for (int dz = -pixR; dz <= pixR; dz++) {
|
||||
int pz = centerPZ + dz;
|
||||
if (pz < 0 || pz >= SPLAT_SIZE) continue;
|
||||
for (int dx = -pixR; dx <= pixR; dx++) {
|
||||
int px = centerPX + dx;
|
||||
if (px < 0 || px >= SPLAT_SIZE) continue;
|
||||
float distWE = FastMath.sqrt(dx * dx + dz * dz) * SPLAT_WE_PER_PX;
|
||||
if (distWE >= softEdge) continue;
|
||||
float t = distWE / softEdge;
|
||||
float falloff = (1f + FastMath.cos(FastMath.PI * t)) * 0.5f;
|
||||
float blend = (textureIndex == 0) ? falloff : strength * falloff;
|
||||
int idx = pz * SPLAT_SIZE + px;
|
||||
float curG = (voxelSplatG[idx] & 0xFF) / 255f;
|
||||
float curB = (voxelSplatB[idx] & 0xFF) / 255f;
|
||||
float curA = (voxelSplatA[idx] & 0xFF) / 255f;
|
||||
float tgG = (textureIndex == 1) ? 1f : 0f;
|
||||
float tgB = (textureIndex == 2) ? 1f : 0f;
|
||||
float tgA = (textureIndex == 3) ? 1f : 0f;
|
||||
voxelSplatR[idx] = (byte) 255;
|
||||
voxelSplatG[idx] = (byte) Math.round((curG + (tgG - curG) * blend) * 255f);
|
||||
voxelSplatB[idx] = (byte) Math.round((curB + (tgB - curB) * blend) * 255f);
|
||||
voxelSplatA[idx] = (byte) Math.round((curA + (tgA - curA) * blend) * 255f);
|
||||
int bi = idx * 4;
|
||||
voxelSplatBuf.put(bi, voxelSplatR[idx]);
|
||||
voxelSplatBuf.put(bi + 1, voxelSplatG[idx]);
|
||||
voxelSplatBuf.put(bi + 2, voxelSplatB[idx]);
|
||||
voxelSplatBuf.put(bi + 3, voxelSplatA[idx]);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) { voxelSplatBuf.rewind(); voxelSplatImage.setUpdateNeeded(); }
|
||||
}
|
||||
|
||||
/** Malt Voxel-Slots 5-8 auf die Voxel-Upper-Splatmap. */
|
||||
private void applyVoxelUpperTexturePaint(Vector3f contact, float strength, int textureIndex) {
|
||||
float radius = (float) input.textureTool.brushRadius.getValue();
|
||||
float softEdge = radius + Math.min(radius * 0.5f, 2f * SPLAT_WE_PER_PX);
|
||||
int centerPX = Math.round((contact.x + WORLD_HALF) / SPLAT_WE_PER_PX);
|
||||
int centerPZ = (SPLAT_SIZE - 1) - Math.round((contact.z + WORLD_HALF) / SPLAT_WE_PER_PX);
|
||||
int pixR = (int) Math.ceil(softEdge / SPLAT_WE_PER_PX);
|
||||
boolean changed = false;
|
||||
for (int dz = -pixR; dz <= pixR; dz++) {
|
||||
int pz = centerPZ + dz;
|
||||
if (pz < 0 || pz >= SPLAT_SIZE) continue;
|
||||
for (int dx = -pixR; dx <= pixR; dx++) {
|
||||
int px = centerPX + dx;
|
||||
if (px < 0 || px >= SPLAT_SIZE) continue;
|
||||
float distWE = FastMath.sqrt(dx * dx + dz * dz) * SPLAT_WE_PER_PX;
|
||||
if (distWE >= softEdge) continue;
|
||||
float t = distWE / softEdge;
|
||||
float falloff = (1f + FastMath.cos(FastMath.PI * t)) * 0.5f;
|
||||
int idx = pz * SPLAT_SIZE + px;
|
||||
if (textureIndex < 0) {
|
||||
voxelUpperSplatR[idx] = (byte) Math.round((voxelUpperSplatR[idx] & 0xFF) / 255f * (1f - falloff) * 255f);
|
||||
voxelUpperSplatG[idx] = (byte) Math.round((voxelUpperSplatG[idx] & 0xFF) / 255f * (1f - falloff) * 255f);
|
||||
voxelUpperSplatB[idx] = (byte) Math.round((voxelUpperSplatB[idx] & 0xFF) / 255f * (1f - falloff) * 255f);
|
||||
voxelUpperSplatA[idx] = (byte) Math.round((voxelUpperSplatA[idx] & 0xFF) / 255f * (1f - falloff) * 255f);
|
||||
} else {
|
||||
float blend = strength * falloff;
|
||||
float curR = (voxelUpperSplatR[idx] & 0xFF) / 255f;
|
||||
float curG = (voxelUpperSplatG[idx] & 0xFF) / 255f;
|
||||
float curB = (voxelUpperSplatB[idx] & 0xFF) / 255f;
|
||||
float curA = (voxelUpperSplatA[idx] & 0xFF) / 255f;
|
||||
voxelUpperSplatR[idx] = (byte) Math.round((curR + ((textureIndex == 0 ? 1f : 0f) - curR) * blend) * 255f);
|
||||
voxelUpperSplatG[idx] = (byte) Math.round((curG + ((textureIndex == 1 ? 1f : 0f) - curG) * blend) * 255f);
|
||||
voxelUpperSplatB[idx] = (byte) Math.round((curB + ((textureIndex == 2 ? 1f : 0f) - curB) * blend) * 255f);
|
||||
voxelUpperSplatA[idx] = (byte) Math.round((curA + ((textureIndex == 3 ? 1f : 0f) - curA) * blend) * 255f);
|
||||
}
|
||||
int bi = idx * 4;
|
||||
voxelUpperSplatBuf.put(bi, voxelUpperSplatR[idx]);
|
||||
voxelUpperSplatBuf.put(bi + 1, voxelUpperSplatG[idx]);
|
||||
voxelUpperSplatBuf.put(bi + 2, voxelUpperSplatB[idx]);
|
||||
voxelUpperSplatBuf.put(bi + 3, voxelUpperSplatA[idx]);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) { voxelUpperSplatBuf.rewind(); voxelUpperSplatImage.setUpdateNeeded(); }
|
||||
}
|
||||
|
||||
/** Malt Voxel-Slots 9-12 auf die Voxel-Third-Splatmap. */
|
||||
private void applyVoxelThirdTexturePaint(Vector3f contact, float strength, int textureIndex) {
|
||||
float radius = (float) input.textureTool.brushRadius.getValue();
|
||||
float softEdge = radius + Math.min(radius * 0.5f, 2f * SPLAT_WE_PER_PX);
|
||||
int centerPX = Math.round((contact.x + WORLD_HALF) / SPLAT_WE_PER_PX);
|
||||
int centerPZ = (SPLAT_SIZE - 1) - Math.round((contact.z + WORLD_HALF) / SPLAT_WE_PER_PX);
|
||||
int pixR = (int) Math.ceil(softEdge / SPLAT_WE_PER_PX);
|
||||
boolean changed = false;
|
||||
for (int dz = -pixR; dz <= pixR; dz++) {
|
||||
int pz = centerPZ + dz;
|
||||
if (pz < 0 || pz >= SPLAT_SIZE) continue;
|
||||
for (int dx = -pixR; dx <= pixR; dx++) {
|
||||
int px = centerPX + dx;
|
||||
if (px < 0 || px >= SPLAT_SIZE) continue;
|
||||
float distWE = FastMath.sqrt(dx * dx + dz * dz) * SPLAT_WE_PER_PX;
|
||||
if (distWE >= softEdge) continue;
|
||||
float t = distWE / softEdge;
|
||||
float falloff = (1f + FastMath.cos(FastMath.PI * t)) * 0.5f;
|
||||
int idx = pz * SPLAT_SIZE + px;
|
||||
if (textureIndex < 0) {
|
||||
voxelThirdSplatR[idx] = (byte) Math.round((voxelThirdSplatR[idx] & 0xFF) / 255f * (1f - falloff) * 255f);
|
||||
voxelThirdSplatG[idx] = (byte) Math.round((voxelThirdSplatG[idx] & 0xFF) / 255f * (1f - falloff) * 255f);
|
||||
voxelThirdSplatB[idx] = (byte) Math.round((voxelThirdSplatB[idx] & 0xFF) / 255f * (1f - falloff) * 255f);
|
||||
voxelThirdSplatA[idx] = (byte) Math.round((voxelThirdSplatA[idx] & 0xFF) / 255f * (1f - falloff) * 255f);
|
||||
} else {
|
||||
float blend = strength * falloff;
|
||||
float curR = (voxelThirdSplatR[idx] & 0xFF) / 255f;
|
||||
float curG = (voxelThirdSplatG[idx] & 0xFF) / 255f;
|
||||
float curB = (voxelThirdSplatB[idx] & 0xFF) / 255f;
|
||||
float curA = (voxelThirdSplatA[idx] & 0xFF) / 255f;
|
||||
voxelThirdSplatR[idx] = (byte) Math.round((curR + ((textureIndex == 0 ? 1f : 0f) - curR) * blend) * 255f);
|
||||
voxelThirdSplatG[idx] = (byte) Math.round((curG + ((textureIndex == 1 ? 1f : 0f) - curG) * blend) * 255f);
|
||||
voxelThirdSplatB[idx] = (byte) Math.round((curB + ((textureIndex == 2 ? 1f : 0f) - curB) * blend) * 255f);
|
||||
voxelThirdSplatA[idx] = (byte) Math.round((curA + ((textureIndex == 3 ? 1f : 0f) - curA) * blend) * 255f);
|
||||
}
|
||||
int bi = idx * 4;
|
||||
voxelThirdSplatBuf.put(bi, voxelThirdSplatR[idx]);
|
||||
voxelThirdSplatBuf.put(bi + 1, voxelThirdSplatG[idx]);
|
||||
voxelThirdSplatBuf.put(bi + 2, voxelThirdSplatB[idx]);
|
||||
voxelThirdSplatBuf.put(bi + 3, voxelThirdSplatA[idx]);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) { voxelThirdSplatBuf.rewind(); voxelThirdSplatImage.setUpdateNeeded(); }
|
||||
}
|
||||
|
||||
// ── Update-Schleife ───────────────────────────────────────────────────────
|
||||
|
||||
@Override
|
||||
@@ -1159,27 +1366,44 @@ public class TerrainEditorState extends BaseAppState {
|
||||
Vector3f far = cam.getWorldCoordinates(new Vector2f(jmeX, jmeY), 1f);
|
||||
com.jme3.math.Ray ray = new com.jme3.math.Ray(near, far.subtract(near).normalizeLocal());
|
||||
|
||||
Vector3f contact = raycastSurface(ray);
|
||||
if (contact == null) continue;
|
||||
if (ves != null && ves.terrainTypeAt(contact.x, contact.z) == VoxelEditorState.TerrainType.VOXEL_UNBAKED) continue;
|
||||
SurfaceHit hit = raycastSurfaceWithType(ray);
|
||||
if (hit == null) continue;
|
||||
Vector3f contact = hit.point;
|
||||
if (!hit.voxelMesh && ves != null && ves.terrainTypeAt(contact.x, contact.z) == VoxelEditorState.TerrainType.VOXEL_UNBAKED) continue;
|
||||
|
||||
int selIdx = input.textureTool.textureIndex.getSelectedIndex();
|
||||
float str = (float) input.textureTool.brushStrength.getValue();
|
||||
|
||||
if (edit.action() > 0) {
|
||||
// Linksklick: Slot malen
|
||||
if (selIdx >= 8) {
|
||||
applyThirdTexturePaint(contact, str, selIdx - 8); // 0=R(Slot9),1=G(Slot10),...
|
||||
} else if (selIdx >= 4) {
|
||||
applyUpperTexturePaint(contact, str, selIdx - 4); // 0=R(Slot5),1=G(Slot6),...
|
||||
if (hit.voxelMesh) {
|
||||
// Sculpted-Mesh-Treffer → Voxel-Splatmaps
|
||||
if (edit.action() > 0) {
|
||||
if (selIdx >= 8) {
|
||||
applyVoxelThirdTexturePaint(contact, str, selIdx - 8);
|
||||
} else if (selIdx >= 4) {
|
||||
applyVoxelUpperTexturePaint(contact, str, selIdx - 4);
|
||||
} else {
|
||||
applyVoxelTexturePaint(contact, str, selIdx);
|
||||
}
|
||||
} else {
|
||||
applyTexturePaint(contact, str, selIdx);
|
||||
applyVoxelTexturePaint(contact, str, 0);
|
||||
applyVoxelUpperTexturePaint(contact, str, -1);
|
||||
applyVoxelThirdTexturePaint(contact, str, -1);
|
||||
}
|
||||
} else {
|
||||
// Rechtsklick: immer auf Basis (Slot 1) zurücksetzen
|
||||
applyTexturePaint(contact, str, 0); // Base → Slot 1 (Gras)
|
||||
applyUpperTexturePaint(contact, str, -1); // Upper-Kanäle → 0
|
||||
applyThirdTexturePaint(contact, str, -1); // Third-Kanäle → 0
|
||||
// Basis-Terrain-Treffer → normale Splatmaps
|
||||
if (edit.action() > 0) {
|
||||
if (selIdx >= 8) {
|
||||
applyThirdTexturePaint(contact, str, selIdx - 8);
|
||||
} else if (selIdx >= 4) {
|
||||
applyUpperTexturePaint(contact, str, selIdx - 4);
|
||||
} else {
|
||||
applyTexturePaint(contact, str, selIdx);
|
||||
}
|
||||
} else {
|
||||
applyTexturePaint(contact, str, 0);
|
||||
applyUpperTexturePaint(contact, str, -1);
|
||||
applyThirdTexturePaint(contact, str, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1194,22 +1418,38 @@ public class TerrainEditorState extends BaseAppState {
|
||||
public com.jme3.texture.Texture2D getUpperSplatTex() { return upperSplatTex; }
|
||||
public com.jme3.texture.Texture2D getThirdSplatTex() { return thirdSplatTex; }
|
||||
|
||||
public com.jme3.texture.Texture2D getVoxelSplatTex() { return voxelSplatTex; }
|
||||
public com.jme3.texture.Texture2D getVoxelUpperSplatTex() { return voxelUpperSplatTex; }
|
||||
public com.jme3.texture.Texture2D getVoxelThirdSplatTex() { return voxelThirdSplatTex; }
|
||||
|
||||
private static final class SurfaceHit {
|
||||
final Vector3f point;
|
||||
final boolean voxelMesh;
|
||||
SurfaceHit(Vector3f p, boolean v) { point = p; voxelMesh = v; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Raycast gegen Basis-Terrain, ungebackenes Voxel-Terrain und gebackene Sculpted-Meshes.
|
||||
* Gibt den zur Kamera nächstgelegenen Treffer zurück, oder null wenn keines getroffen wurde.
|
||||
*/
|
||||
private Vector3f raycastSurface(com.jme3.math.Ray ray) {
|
||||
SurfaceHit h = raycastSurfaceWithType(ray);
|
||||
return h != null ? h.point : null;
|
||||
}
|
||||
|
||||
private SurfaceHit raycastSurfaceWithType(com.jme3.math.Ray ray) {
|
||||
CollisionResults hits = new CollisionResults();
|
||||
terrain.collideWith(ray, hits);
|
||||
Vector3f best = hits.size() > 0 ? hits.getClosestCollision().getContactPoint() : null;
|
||||
float bestDistSq = best != null ? ray.getOrigin().distanceSquared(best) : Float.MAX_VALUE;
|
||||
boolean bestIsVoxelMesh = false;
|
||||
|
||||
VoxelEditorState ves = getStateManager().getState(VoxelEditorState.class);
|
||||
if (ves != null) {
|
||||
Vector3f vp = ves.raycastVoxelGeometry(ray);
|
||||
if (vp != null) {
|
||||
float d = ray.getOrigin().distanceSquared(vp);
|
||||
if (d < bestDistSq) { best = vp; bestDistSq = d; }
|
||||
if (d < bestDistSq) { best = vp; bestDistSq = d; bestIsVoxelMesh = false; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1218,10 +1458,10 @@ public class TerrainEditorState extends BaseAppState {
|
||||
Vector3f sp = smes.raycastGeometry(ray);
|
||||
if (sp != null) {
|
||||
float d = ray.getOrigin().distanceSquared(sp);
|
||||
if (d < bestDistSq) { best = sp; }
|
||||
if (d < bestDistSq) { best = sp; bestIsVoxelMesh = true; }
|
||||
}
|
||||
}
|
||||
return best;
|
||||
return best != null ? new SurfaceHit(best, bestIsVoxelMesh) : null;
|
||||
}
|
||||
|
||||
/** Gibt die Terrain-Höhe (Welt-Y) an der angegebenen Welt-XZ-Position zurück. */
|
||||
@@ -1268,6 +1508,18 @@ public class TerrainEditorState extends BaseAppState {
|
||||
final byte[] thG = thirdSplatG != null ? thirdSplatG.clone() : null;
|
||||
final byte[] thB = thirdSplatB != null ? thirdSplatB.clone() : null;
|
||||
final byte[] thA = thirdSplatA != null ? thirdSplatA.clone() : null;
|
||||
final byte[] vxR = voxelSplatR != null ? voxelSplatR.clone() : null;
|
||||
final byte[] vxG = voxelSplatG != null ? voxelSplatG.clone() : null;
|
||||
final byte[] vxB = voxelSplatB != null ? voxelSplatB.clone() : null;
|
||||
final byte[] vxA = voxelSplatA != null ? voxelSplatA.clone() : null;
|
||||
final byte[] vxUR = voxelUpperSplatR != null ? voxelUpperSplatR.clone() : null;
|
||||
final byte[] vxUG = voxelUpperSplatG != null ? voxelUpperSplatG.clone() : null;
|
||||
final byte[] vxUB = voxelUpperSplatB != null ? voxelUpperSplatB.clone() : null;
|
||||
final byte[] vxUA = voxelUpperSplatA != null ? voxelUpperSplatA.clone() : null;
|
||||
final byte[] vxTR = voxelThirdSplatR != null ? voxelThirdSplatR.clone() : null;
|
||||
final byte[] vxTG = voxelThirdSplatG != null ? voxelThirdSplatG.clone() : null;
|
||||
final byte[] vxTB = voxelThirdSplatB != null ? voxelThirdSplatB.clone() : null;
|
||||
final byte[] vxTA = voxelThirdSplatA != null ? voxelThirdSplatA.clone() : null;
|
||||
final String[] texPaths = input.terrainTexturePaths.clone();
|
||||
final String[] normalPaths = input.terrainNormalMapPaths.clone();
|
||||
final String[] upperPaths = input.upperTexturePaths.clone();
|
||||
@@ -1345,6 +1597,20 @@ public class TerrainEditorState extends BaseAppState {
|
||||
System.arraycopy(thirdPaths, 0, data.thirdTextures, 0, MapData.TEXTURE_SLOTS);
|
||||
System.arraycopy(thirdNormPaths, 0, data.thirdNormalMaps, 0, MapData.TEXTURE_SLOTS);
|
||||
}
|
||||
if (vxR != null) {
|
||||
System.arraycopy(vxR, 0, data.voxelSplatR, 0, data.voxelSplatR.length);
|
||||
System.arraycopy(vxG, 0, data.voxelSplatG, 0, data.voxelSplatG.length);
|
||||
System.arraycopy(vxB, 0, data.voxelSplatB, 0, data.voxelSplatB.length);
|
||||
System.arraycopy(vxA, 0, data.voxelSplatA, 0, data.voxelSplatA.length);
|
||||
System.arraycopy(vxUR, 0, data.voxelUpperSplatR, 0, data.voxelUpperSplatR.length);
|
||||
System.arraycopy(vxUG, 0, data.voxelUpperSplatG, 0, data.voxelUpperSplatG.length);
|
||||
System.arraycopy(vxUB, 0, data.voxelUpperSplatB, 0, data.voxelUpperSplatB.length);
|
||||
System.arraycopy(vxUA, 0, data.voxelUpperSplatA, 0, data.voxelUpperSplatA.length);
|
||||
System.arraycopy(vxTR, 0, data.voxelThirdSplatR, 0, data.voxelThirdSplatR.length);
|
||||
System.arraycopy(vxTG, 0, data.voxelThirdSplatG, 0, data.voxelThirdSplatG.length);
|
||||
System.arraycopy(vxTB, 0, data.voxelThirdSplatB, 0, data.voxelThirdSplatB.length);
|
||||
System.arraycopy(vxTA, 0, data.voxelThirdSplatA, 0, data.voxelThirdSplatA.length);
|
||||
}
|
||||
data.normalMapOrder = input.normalMapOrder.clone();
|
||||
data.diffuseScales = diffScaleSnap.clone();
|
||||
data.voxelFlatSlot = voxelFlatSlot;
|
||||
|
||||
Reference in New Issue
Block a user