Bug behoben bei den Texturen

This commit is contained in:
2026-08-10 12:33:10 +02:00
parent 9561966071
commit 294a080a3c
5 changed files with 62 additions and 74 deletions

View File

@@ -6,6 +6,8 @@ MaterialDef BakedTerrain {
Texture2D AlphaMap Texture2D AlphaMap
Texture2D AlphaMap_1 Texture2D AlphaMap_1
Texture2D AlphaMap_2 Texture2D AlphaMap_2
Boolean HasSteep
Int SteepIndex
Vector3 LightDir : 0.6 -0.8 0.4 Vector3 LightDir : 0.6 -0.8 0.4
Vector3 SunColor : 0.68 0.65 0.60 Vector3 SunColor : 0.68 0.65 0.60
Vector3 AmbientColor : 0.08 0.10 0.16 Vector3 AmbientColor : 0.08 0.10 0.16
@@ -25,6 +27,7 @@ MaterialDef BakedTerrain {
Defines { Defines {
HAS_ALPHA_1 : AlphaMap_1 HAS_ALPHA_1 : AlphaMap_1
HAS_ALPHA_2 : AlphaMap_2 HAS_ALPHA_2 : AlphaMap_2
HAS_STEEP : HasSteep
DEBUG_NO_LIGHT : DebugNoLight DEBUG_NO_LIGHT : DebugNoLight
} }

View File

@@ -9,6 +9,10 @@ uniform sampler2D m_AlphaMap_1;
uniform sampler2D m_AlphaMap_2; uniform sampler2D m_AlphaMap_2;
#endif #endif
#ifdef HAS_STEEP
uniform int m_SteepIndex;
#endif
uniform vec3 m_LightDir; uniform vec3 m_LightDir;
uniform vec3 m_SunColor; uniform vec3 m_SunColor;
uniform vec3 m_AmbientColor; uniform vec3 m_AmbientColor;
@@ -19,6 +23,15 @@ in vec3 vNormal;
out vec4 outColor; out vec4 outColor;
#ifdef HAS_STEEP
// Triplanare Textur-Abfrage aus einem Sampler2DArray-Layer
vec4 triplanarArray(vec2 uvX, vec2 uvY, vec2 uvZ, vec3 bw, int idx) {
return texture(m_DiffuseArray, vec3(uvX, float(idx))) * bw.x
+ texture(m_DiffuseArray, vec3(uvY, float(idx))) * bw.y
+ texture(m_DiffuseArray, vec3(uvZ, float(idx))) * bw.z;
}
#endif
void main() { void main() {
// World-space splatmap UV (identisch zur Painting-Logik in TerrainEditorState) // World-space splatmap UV (identisch zur Painting-Logik in TerrainEditorState)
vec2 splatUV = vec2( vec2 splatUV = vec2(
@@ -51,6 +64,19 @@ void main() {
} }
} }
#ifdef HAS_STEEP
// Klippen-Textur: Triplanar auf steilen Flächen (identisch zu Voxel.frag)
vec3 bw = pow(abs(vNormal), vec3(4.0));
bw /= (bw.x + bw.y + bw.z + 0.001);
float steepScale = m_DiffuseScales[m_SteepIndex];
vec2 uvX = vWorldPos.yz / steepScale;
vec2 uvZ = vWorldPos.xy / steepScale;
float flatBlend = smoothstep(0.70, 0.90, vNormal.y);
float steepBlend = 1.0 - flatBlend;
vec4 steepCol = triplanarArray(uvX, vWorldPos.xz / steepScale, uvZ, bw, m_SteepIndex);
col = col * flatBlend + steepCol * steepBlend;
#endif
vec3 N = normalize(vNormal); vec3 N = normalize(vNormal);
vec3 lightDir = normalize(m_LightDir); vec3 lightDir = normalize(m_LightDir);
float diff = max(dot(N, lightDir), 0.0); float diff = max(dot(N, lightDir), 0.0);

View File

@@ -531,6 +531,12 @@ public class SculptedMeshEditorState extends BaseAppState {
if (a2 != null) { mat.setTexture("AlphaMap_2", a2); } if (a2 != null) { mat.setTexture("AlphaMap_2", a2); }
} }
// Klippen-Textur
if (input.voxelSteepSlot >= 0) {
mat.setBoolean("HasSteep", true);
mat.setInt("SteepIndex", input.voxelSteepSlot);
}
mat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off); mat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
bakedMat = mat; bakedMat = mat;
normalMat = mat; normalMat = mat;

View File

@@ -938,7 +938,7 @@ public class WorldScene extends BaseAppState {
// sofort die Physik für die Spawn-Umgebung aufbaut. // sofort die Physik für die Spawn-Umgebung aufbaut.
terrainChunkState.setSpawnHint(spawnX, spawnZ); terrainChunkState.setSpawnHint(spawnX, spawnZ);
app.getStateManager().attach(new SculptedMeshState(bulletAppState, loadedMapData)); app.getStateManager().attach(new SculptedMeshState(bulletAppState, loadedMapData, terrainMaterial));
oceanSound = new de.blight.game.state.OceanSoundState(terrainChunkState); oceanSound = new de.blight.game.state.OceanSoundState(terrainChunkState);
app.getStateManager().attach(oceanSound); app.getStateManager().attach(oceanSound);

View File

@@ -16,13 +16,10 @@ import com.jme3.scene.Mesh;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.scene.VertexBuffer; import com.jme3.scene.VertexBuffer;
import com.jme3.texture.Texture; import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
import com.jme3.texture.image.ColorSpace;
import de.blight.common.*; import de.blight.common.*;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@@ -40,13 +37,15 @@ public class SculptedMeshState extends BaseAppState {
private final BulletAppState bulletState; private final BulletAppState bulletState;
private final MapData mapData; private final MapData mapData;
private final Material terrainMaterial;
private SimpleApplication app; private SimpleApplication app;
private Node sculptRoot; private Node sculptRoot;
private Material material; private Material material;
public SculptedMeshState(BulletAppState bulletState, MapData mapData) { public SculptedMeshState(BulletAppState bulletState, MapData mapData, Material terrainMaterial) {
this.bulletState = bulletState; this.bulletState = bulletState;
this.mapData = mapData; this.mapData = mapData;
this.terrainMaterial = terrainMaterial;
} }
@Override @Override
@@ -235,75 +234,29 @@ public class SculptedMeshState extends BaseAppState {
// ── Material ───────────────────────────────────────────────────────────── // ── Material ─────────────────────────────────────────────────────────────
private Material buildMaterial() { private Material buildMaterial() {
Material mat = new Material(app.getAssetManager(), "MatDefs/Voxel.j3md"); Material mat = new Material(app.getAssetManager(), "MatDefs/BakedTerrain.j3md");
mat.setFloat("TexScale", 8f);
int[] slots = { // DiffuseArray + DiffuseScales + AlphaMaps vom Terrain-Material übernehmen,
mapData != null ? mapData.voxelFlatSlot : -1, // damit die gemalten Splatmap-Texturen auch ingame sichtbar sind.
mapData != null ? mapData.voxelSteepSlot : -1, if (terrainMaterial != null) {
}; com.jme3.material.MatParam diffArr = terrainMaterial.getParam("DiffuseArray");
String[] colSlots = {"TexFlat", "TexSteep" }; if (diffArr != null) mat.setParam("DiffuseArray", diffArr.getVarType(), diffArr.getValue());
String[] normSlots = {"NormalMapFlat", "NormalMapSteep" };
// Fallback-Farben wenn kein Slot konfiguriert: grünlich-grau (flach), felsgrau (steil) com.jme3.material.MatParam scales = terrainMaterial.getParam("DiffuseScales");
int[][] fallbackRgb = { if (scales != null) mat.setParam("DiffuseScales", scales.getVarType(), scales.getValue());
{100, 130, 60},
{110, 100, 90}, for (String key : new String[]{"AlphaMap", "AlphaMap_1", "AlphaMap_2"}) {
}; com.jme3.material.MatParam p = terrainMaterial.getParam(key);
for (int i = 0; i < 2; i++) { if (p != null) mat.setTexture(key, (Texture) p.getValue());
String tex = resolveSlotTex(slots[i]);
String norm = resolveSlotNorm(slots[i]);
if (!tex.isEmpty()) {
try {
Texture t = app.getAssetManager().loadTexture(tex);
t.getImage().setColorSpace(ColorSpace.Linear);
t.setWrap(Texture.WrapMode.Repeat);
mat.setTexture(colSlots[i], t);
} catch (Exception e) {
log.warn("Textur {} nicht ladbar: {}", tex, e.getMessage());
mat.setTexture(colSlots[i], solidColorTexture(fallbackRgb[i]));
}
} else {
mat.setTexture(colSlots[i], solidColorTexture(fallbackRgb[i]));
}
if (!norm.isEmpty()) {
try {
Texture n = app.getAssetManager().loadTexture(norm);
n.setWrap(Texture.WrapMode.Repeat);
mat.setTexture(normSlots[i], n);
} catch (Exception e) {
mat.clearParam(normSlots[i]);
}
} else {
mat.clearParam(normSlots[i]);
} }
} }
// Klippen-Textur: steiler Slot aus MapData für Flat/Steep-Blending
if (mapData != null && mapData.voxelSteepSlot >= 0) {
mat.setBoolean("HasSteep", true);
mat.setInt("SteepIndex", mapData.voxelSteepSlot);
}
return mat; return mat;
} }
private Texture solidColorTexture(int[] rgb) {
ByteBuffer buf = ByteBuffer.allocate(4);
buf.put((byte) rgb[0]).put((byte) rgb[1]).put((byte) rgb[2]).put((byte) 255);
buf.flip();
Texture2D tex = new Texture2D(
new com.jme3.texture.Image(com.jme3.texture.Image.Format.RGBA8, 1, 1, buf, ColorSpace.Linear));
tex.setWrap(Texture.WrapMode.Repeat);
return tex;
}
private String resolveSlotTex(int slot) {
if (slot < 0 || mapData == null) return "";
if (slot < 4) return s(mapData.terrainTextures[slot]);
if (slot < 8) return s(mapData.upperTextures[slot-4]);
if (slot < 12) return s(mapData.thirdTextures[slot-8]);
return "";
}
private String resolveSlotNorm(int slot) {
if (slot < 0 || mapData == null) return "";
if (slot < 4) return s(mapData.terrainNormalMaps[slot]);
if (slot < 8) return s(mapData.upperNormalMaps[slot-4]);
if (slot < 12) return s(mapData.thirdNormalMaps[slot-8]);
return "";
}
private static String s(String v) { return v != null ? v : ""; }
} }