Bug behoben bei den Texturen
This commit is contained in:
@@ -6,6 +6,8 @@ MaterialDef BakedTerrain {
|
||||
Texture2D AlphaMap
|
||||
Texture2D AlphaMap_1
|
||||
Texture2D AlphaMap_2
|
||||
Boolean HasSteep
|
||||
Int SteepIndex
|
||||
Vector3 LightDir : 0.6 -0.8 0.4
|
||||
Vector3 SunColor : 0.68 0.65 0.60
|
||||
Vector3 AmbientColor : 0.08 0.10 0.16
|
||||
@@ -25,6 +27,7 @@ MaterialDef BakedTerrain {
|
||||
Defines {
|
||||
HAS_ALPHA_1 : AlphaMap_1
|
||||
HAS_ALPHA_2 : AlphaMap_2
|
||||
HAS_STEEP : HasSteep
|
||||
DEBUG_NO_LIGHT : DebugNoLight
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,10 @@ uniform sampler2D m_AlphaMap_1;
|
||||
uniform sampler2D m_AlphaMap_2;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_STEEP
|
||||
uniform int m_SteepIndex;
|
||||
#endif
|
||||
|
||||
uniform vec3 m_LightDir;
|
||||
uniform vec3 m_SunColor;
|
||||
uniform vec3 m_AmbientColor;
|
||||
@@ -19,6 +23,15 @@ in vec3 vNormal;
|
||||
|
||||
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() {
|
||||
// World-space splatmap UV (identisch zur Painting-Logik in TerrainEditorState)
|
||||
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 lightDir = normalize(m_LightDir);
|
||||
float diff = max(dot(N, lightDir), 0.0);
|
||||
|
||||
@@ -531,6 +531,12 @@ public class SculptedMeshEditorState extends BaseAppState {
|
||||
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);
|
||||
bakedMat = mat;
|
||||
normalMat = mat;
|
||||
|
||||
@@ -938,7 +938,7 @@ public class WorldScene extends BaseAppState {
|
||||
// sofort die Physik für die Spawn-Umgebung aufbaut.
|
||||
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);
|
||||
app.getStateManager().attach(oceanSound);
|
||||
|
||||
@@ -16,13 +16,10 @@ import com.jme3.scene.Mesh;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.VertexBuffer;
|
||||
import com.jme3.texture.Texture;
|
||||
import com.jme3.texture.Texture2D;
|
||||
import com.jme3.texture.image.ColorSpace;
|
||||
import de.blight.common.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -40,13 +37,15 @@ public class SculptedMeshState extends BaseAppState {
|
||||
|
||||
private final BulletAppState bulletState;
|
||||
private final MapData mapData;
|
||||
private final Material terrainMaterial;
|
||||
private SimpleApplication app;
|
||||
private Node sculptRoot;
|
||||
private Material material;
|
||||
|
||||
public SculptedMeshState(BulletAppState bulletState, MapData mapData) {
|
||||
public SculptedMeshState(BulletAppState bulletState, MapData mapData, Material terrainMaterial) {
|
||||
this.bulletState = bulletState;
|
||||
this.mapData = mapData;
|
||||
this.terrainMaterial = terrainMaterial;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -235,75 +234,29 @@ public class SculptedMeshState extends BaseAppState {
|
||||
// ── Material ─────────────────────────────────────────────────────────────
|
||||
|
||||
private Material buildMaterial() {
|
||||
Material mat = new Material(app.getAssetManager(), "MatDefs/Voxel.j3md");
|
||||
mat.setFloat("TexScale", 8f);
|
||||
int[] slots = {
|
||||
mapData != null ? mapData.voxelFlatSlot : -1,
|
||||
mapData != null ? mapData.voxelSteepSlot : -1,
|
||||
};
|
||||
String[] colSlots = {"TexFlat", "TexSteep" };
|
||||
String[] normSlots = {"NormalMapFlat", "NormalMapSteep" };
|
||||
// Fallback-Farben wenn kein Slot konfiguriert: grünlich-grau (flach), felsgrau (steil)
|
||||
int[][] fallbackRgb = {
|
||||
{100, 130, 60},
|
||||
{110, 100, 90},
|
||||
};
|
||||
for (int i = 0; i < 2; i++) {
|
||||
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]);
|
||||
Material mat = new Material(app.getAssetManager(), "MatDefs/BakedTerrain.j3md");
|
||||
|
||||
// DiffuseArray + DiffuseScales + AlphaMaps vom Terrain-Material übernehmen,
|
||||
// damit die gemalten Splatmap-Texturen auch ingame sichtbar sind.
|
||||
if (terrainMaterial != null) {
|
||||
com.jme3.material.MatParam diffArr = terrainMaterial.getParam("DiffuseArray");
|
||||
if (diffArr != null) mat.setParam("DiffuseArray", diffArr.getVarType(), diffArr.getValue());
|
||||
|
||||
com.jme3.material.MatParam scales = terrainMaterial.getParam("DiffuseScales");
|
||||
if (scales != null) mat.setParam("DiffuseScales", scales.getVarType(), scales.getValue());
|
||||
|
||||
for (String key : new String[]{"AlphaMap", "AlphaMap_1", "AlphaMap_2"}) {
|
||||
com.jme3.material.MatParam p = terrainMaterial.getParam(key);
|
||||
if (p != null) mat.setTexture(key, (Texture) p.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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 : ""; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user