Texturierung von Voxel Popoxel ermöglicht
This commit is contained in:
35
blight-assets/src/main/resources/MatDefs/BakedTerrain.j3md
Normal file
35
blight-assets/src/main/resources/MatDefs/BakedTerrain.j3md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
MaterialDef BakedTerrain {
|
||||||
|
|
||||||
|
MaterialParameters {
|
||||||
|
TextureArray DiffuseArray
|
||||||
|
FloatArray DiffuseScales
|
||||||
|
Texture2D AlphaMap
|
||||||
|
Texture2D AlphaMap_1
|
||||||
|
Texture2D AlphaMap_2
|
||||||
|
Vector3 LightDir : 0.6 -0.8 0.4
|
||||||
|
Vector3 SunColor : 0.68 0.65 0.60
|
||||||
|
Vector3 AmbientColor : 0.08 0.10 0.16
|
||||||
|
Boolean DebugNoLight
|
||||||
|
}
|
||||||
|
|
||||||
|
Technique {
|
||||||
|
VertexShader GLSL150 : Shaders/BakedTerrain.vert
|
||||||
|
FragmentShader GLSL150 : Shaders/BakedTerrain.frag
|
||||||
|
|
||||||
|
WorldParameters {
|
||||||
|
WorldViewProjectionMatrix
|
||||||
|
WorldMatrix
|
||||||
|
CameraPosition
|
||||||
|
}
|
||||||
|
|
||||||
|
Defines {
|
||||||
|
HAS_ALPHA_1 : AlphaMap_1
|
||||||
|
HAS_ALPHA_2 : AlphaMap_2
|
||||||
|
DEBUG_NO_LIGHT : DebugNoLight
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderState {
|
||||||
|
FaceCull Off
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
65
blight-assets/src/main/resources/Shaders/BakedTerrain.frag
Normal file
65
blight-assets/src/main/resources/Shaders/BakedTerrain.frag
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
uniform sampler2DArray m_DiffuseArray;
|
||||||
|
uniform float m_DiffuseScales[12];
|
||||||
|
uniform sampler2D m_AlphaMap;
|
||||||
|
|
||||||
|
#ifdef HAS_ALPHA_1
|
||||||
|
uniform sampler2D m_AlphaMap_1;
|
||||||
|
#endif
|
||||||
|
#ifdef HAS_ALPHA_2
|
||||||
|
uniform sampler2D m_AlphaMap_2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uniform vec3 m_LightDir;
|
||||||
|
uniform vec3 m_SunColor;
|
||||||
|
uniform vec3 m_AmbientColor;
|
||||||
|
uniform vec3 g_CameraPosition;
|
||||||
|
|
||||||
|
in vec3 vWorldPos;
|
||||||
|
in vec3 vNormal;
|
||||||
|
|
||||||
|
out vec4 outColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// World-space splatmap UV (identisch zur Painting-Logik in TerrainEditorState)
|
||||||
|
vec2 splatUV = vec2(
|
||||||
|
(vWorldPos.x + 2048.0) / 4096.0,
|
||||||
|
1.0 - (vWorldPos.z + 2048.0) / 4096.0
|
||||||
|
);
|
||||||
|
|
||||||
|
vec4 a0 = texture(m_AlphaMap, splatUV);
|
||||||
|
vec4 a1 = vec4(0.0);
|
||||||
|
vec4 a2 = vec4(0.0);
|
||||||
|
#ifdef HAS_ALPHA_1
|
||||||
|
a1 = texture(m_AlphaMap_1, splatUV);
|
||||||
|
#endif
|
||||||
|
#ifdef HAS_ALPHA_2
|
||||||
|
a2 = texture(m_AlphaMap_2, splatUV);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float overlays[11] = float[](a0.g, a0.b, a0.a,
|
||||||
|
a1.r, a1.g, a1.b, a1.a,
|
||||||
|
a2.r, a2.g, a2.b, a2.a);
|
||||||
|
|
||||||
|
// Basis (Slot 1)
|
||||||
|
vec4 col = texture(m_DiffuseArray, vec3(vWorldPos.xz / m_DiffuseScales[0], 0.0));
|
||||||
|
|
||||||
|
// Overlays (Slots 2-12) sequentiell darüber mischen
|
||||||
|
for (int i = 0; i < 11; i++) {
|
||||||
|
if (overlays[i] > 0.001) {
|
||||||
|
vec2 uv = vWorldPos.xz / m_DiffuseScales[i + 1];
|
||||||
|
col = mix(col, texture(m_DiffuseArray, vec3(uv, float(i + 1))), overlays[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 N = normalize(vNormal);
|
||||||
|
vec3 lightDir = normalize(m_LightDir);
|
||||||
|
float diff = max(dot(N, lightDir), 0.0);
|
||||||
|
vec3 light = m_AmbientColor + m_SunColor * diff;
|
||||||
|
|
||||||
|
const float BRIGHTNESS = 0.80;
|
||||||
|
#ifdef DEBUG_NO_LIGHT
|
||||||
|
outColor = vec4(col.rgb * BRIGHTNESS, col.a);
|
||||||
|
#else
|
||||||
|
outColor = vec4(col.rgb * light * BRIGHTNESS, col.a);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
16
blight-assets/src/main/resources/Shaders/BakedTerrain.vert
Normal file
16
blight-assets/src/main/resources/Shaders/BakedTerrain.vert
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
uniform mat4 g_WorldViewProjectionMatrix;
|
||||||
|
uniform mat4 g_WorldMatrix;
|
||||||
|
|
||||||
|
in vec3 inPosition;
|
||||||
|
in vec3 inNormal;
|
||||||
|
|
||||||
|
out vec3 vWorldPos;
|
||||||
|
out vec3 vNormal;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 worldPos4 = g_WorldMatrix * vec4(inPosition, 1.0);
|
||||||
|
mat3 worldMat3 = mat3(g_WorldMatrix);
|
||||||
|
vWorldPos = worldPos4.xyz;
|
||||||
|
vNormal = normalize(worldMat3 * inNormal);
|
||||||
|
gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1.0);
|
||||||
|
}
|
||||||
@@ -68,6 +68,7 @@ public class SculptedMeshEditorState extends BaseAppState {
|
|||||||
|
|
||||||
private long selectedKey = -1L;
|
private long selectedKey = -1L;
|
||||||
private Material normalMat = null;
|
private Material normalMat = null;
|
||||||
|
private Material bakedMat = null;
|
||||||
private Material highlightMat = null;
|
private Material highlightMat = null;
|
||||||
private Material selectionWireframeMat = null;
|
private Material selectionWireframeMat = null;
|
||||||
private final Set<Long> appliedSelectionKeys = new HashSet<>();
|
private final Set<Long> appliedSelectionKeys = new HashSet<>();
|
||||||
@@ -345,14 +346,11 @@ public class SculptedMeshEditorState extends BaseAppState {
|
|||||||
if (m.getBuffer(VertexBuffer.Type.Normal) != null)
|
if (m.getBuffer(VertexBuffer.Type.Normal) != null)
|
||||||
m.getBuffer(VertexBuffer.Type.Normal).setUsage(VertexBuffer.Usage.Dynamic);
|
m.getBuffer(VertexBuffer.Type.Normal).setUsage(VertexBuffer.Usage.Dynamic);
|
||||||
|
|
||||||
// Material von VoxelEditorState wiederverwenden
|
if (bakedMat == null) buildBakedMat();
|
||||||
VoxelEditorState ves = app.getStateManager().getState(VoxelEditorState.class);
|
if (normalMat == null) normalMat = bakedMat;
|
||||||
Material mat = (ves != null) ? ves.getVoxelMaterial() : null;
|
|
||||||
if (mat == null) mat = new Material(app.getAssetManager(), "MatDefs/Voxel.j3md");
|
|
||||||
if (normalMat == null) normalMat = mat;
|
|
||||||
|
|
||||||
Geometry geo = new Geometry("sculpt_" + cx + "_" + cy + "_" + cz, m);
|
Geometry geo = new Geometry("sculpt_" + cx + "_" + cy + "_" + cz, m);
|
||||||
geo.setMaterial(mat);
|
geo.setMaterial(bakedMat);
|
||||||
|
|
||||||
float ox = cx * VoxelChunk.CELLS - 2048f;
|
float ox = cx * VoxelChunk.CELLS - 2048f;
|
||||||
float oy = cy * (float) VoxelChunk.CELLS;
|
float oy = cy * (float) VoxelChunk.CELLS;
|
||||||
@@ -505,6 +503,46 @@ public class SculptedMeshEditorState extends BaseAppState {
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── BakedTerrain-Material ─────────────────────────────────────────────────
|
||||||
|
|
||||||
|
private void buildBakedMat() {
|
||||||
|
Material mat = new Material(app.getAssetManager(), "MatDefs/BakedTerrain.j3md");
|
||||||
|
|
||||||
|
TerrainEditorState tes = app.getStateManager().getState(TerrainEditorState.class);
|
||||||
|
if (tes != null) {
|
||||||
|
com.jme3.material.Material terrMat = tes.getTerrainMaterial();
|
||||||
|
if (terrMat != null) {
|
||||||
|
com.jme3.material.MatParam diffArr = terrMat.getParam("DiffuseArray");
|
||||||
|
if (diffArr != null) {
|
||||||
|
mat.setParam("DiffuseArray", diffArr.getVarType(), diffArr.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
com.jme3.material.MatParam scales = terrMat.getParam("DiffuseScales");
|
||||||
|
if (scales != null) {
|
||||||
|
mat.setParam("DiffuseScales", scales.getVarType(), scales.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
com.jme3.texture.Texture2D a0 = tes.getSplatTex();
|
||||||
|
com.jme3.texture.Texture2D a1 = tes.getUpperSplatTex();
|
||||||
|
com.jme3.texture.Texture2D a2 = tes.getThirdSplatTex();
|
||||||
|
if (a0 != null) { mat.setTexture("AlphaMap", a0); }
|
||||||
|
if (a1 != null) { mat.setTexture("AlphaMap_1", a1); }
|
||||||
|
if (a2 != null) { mat.setTexture("AlphaMap_2", a2); }
|
||||||
|
}
|
||||||
|
|
||||||
|
mat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
|
||||||
|
bakedMat = mat;
|
||||||
|
normalMat = mat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateBakedMatLighting(Vector3f lightDir, Vector3f sunColor, Vector3f ambientColor) {
|
||||||
|
if (bakedMat == null) return;
|
||||||
|
bakedMat.setVector3("LightDir", lightDir);
|
||||||
|
bakedMat.setVector3("SunColor", sunColor);
|
||||||
|
bakedMat.setVector3("AmbientColor", ambientColor);
|
||||||
|
}
|
||||||
|
|
||||||
// ── Normalen & Mesh-Update ────────────────────────────────────────────────
|
// ── Normalen & Mesh-Update ────────────────────────────────────────────────
|
||||||
|
|
||||||
private static void recomputeNormals(float[] positions, float[] normals,
|
private static void recomputeNormals(float[] positions, float[] normals,
|
||||||
|
|||||||
@@ -769,12 +769,13 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
* @param textureIndex 0=Slot1/Reset, 1=Slot2(G→1), 2=Slot3(B→1), 3=Slot4(A→1)
|
* @param textureIndex 0=Slot1/Reset, 1=Slot2(G→1), 2=Slot3(B→1), 3=Slot4(A→1)
|
||||||
*/
|
*/
|
||||||
private void applyTexturePaint(Vector3f contact, float strength, int textureIndex) {
|
private void applyTexturePaint(Vector3f contact, float strength, int textureIndex) {
|
||||||
float radius = (float) input.textureTool.brushRadius.getValue();
|
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 centerPX = Math.round((contact.x + WORLD_HALF) / SPLAT_WE_PER_PX);
|
||||||
// JME3-Terrain UV: V=0 → worldZ=+2048, V=1 → worldZ=-2048 (Z-Achse gespiegelt)
|
// JME3-Terrain UV: V=0 → worldZ=+2048, V=1 → worldZ=-2048 (Z-Achse gespiegelt)
|
||||||
int centerPZ = (SPLAT_SIZE - 1) - Math.round((contact.z + 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(radius / SPLAT_WE_PER_PX);
|
int pixR = (int) Math.ceil(softEdge / SPLAT_WE_PER_PX);
|
||||||
|
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
for (int dz = -pixR; dz <= pixR; dz++) {
|
for (int dz = -pixR; dz <= pixR; dz++) {
|
||||||
@@ -785,9 +786,9 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
if (px < 0 || px >= SPLAT_SIZE) continue;
|
if (px < 0 || px >= SPLAT_SIZE) continue;
|
||||||
|
|
||||||
float distWE = FastMath.sqrt(dx * dx + dz * dz) * SPLAT_WE_PER_PX;
|
float distWE = FastMath.sqrt(dx * dx + dz * dz) * SPLAT_WE_PER_PX;
|
||||||
if (distWE >= radius) continue;
|
if (distWE >= softEdge) continue;
|
||||||
|
|
||||||
float t = distWE / radius;
|
float t = distWE / softEdge;
|
||||||
float falloff = (1f + FastMath.cos(FastMath.PI * t)) * 0.5f;
|
float falloff = (1f + FastMath.cos(FastMath.PI * t)) * 0.5f;
|
||||||
// Slot 1 (textureIndex==0) = Zurücksetzen: volle Stärke damit ein Strich reicht
|
// Slot 1 (textureIndex==0) = Zurücksetzen: volle Stärke damit ein Strich reicht
|
||||||
float blend = (textureIndex == 0) ? falloff : strength * falloff;
|
float blend = (textureIndex == 0) ? falloff : strength * falloff;
|
||||||
@@ -826,11 +827,12 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
* @param textureIndex 0=Slot5(R), 1=Slot6(G), 2=Slot7(B), 3=Slot8(A), -1=Löschen(alle→0)
|
* @param textureIndex 0=Slot5(R), 1=Slot6(G), 2=Slot7(B), 3=Slot8(A), -1=Löschen(alle→0)
|
||||||
*/
|
*/
|
||||||
private void applyUpperTexturePaint(Vector3f contact, float strength, int textureIndex) {
|
private void applyUpperTexturePaint(Vector3f contact, float strength, int textureIndex) {
|
||||||
float radius = (float) input.textureTool.brushRadius.getValue();
|
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 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 centerPZ = (SPLAT_SIZE - 1) - Math.round((contact.z + WORLD_HALF) / SPLAT_WE_PER_PX);
|
||||||
int pixR = (int) Math.ceil(radius / SPLAT_WE_PER_PX);
|
int pixR = (int) Math.ceil(softEdge / SPLAT_WE_PER_PX);
|
||||||
|
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
for (int dz = -pixR; dz <= pixR; dz++) {
|
for (int dz = -pixR; dz <= pixR; dz++) {
|
||||||
@@ -841,9 +843,9 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
if (px < 0 || px >= SPLAT_SIZE) continue;
|
if (px < 0 || px >= SPLAT_SIZE) continue;
|
||||||
|
|
||||||
float distWE = FastMath.sqrt(dx * dx + dz * dz) * SPLAT_WE_PER_PX;
|
float distWE = FastMath.sqrt(dx * dx + dz * dz) * SPLAT_WE_PER_PX;
|
||||||
if (distWE >= radius) continue;
|
if (distWE >= softEdge) continue;
|
||||||
|
|
||||||
float t = distWE / radius;
|
float t = distWE / softEdge;
|
||||||
float falloff = (1f + FastMath.cos(FastMath.PI * t)) * 0.5f;
|
float falloff = (1f + FastMath.cos(FastMath.PI * t)) * 0.5f;
|
||||||
int idx = pz * SPLAT_SIZE + px;
|
int idx = pz * SPLAT_SIZE + px;
|
||||||
|
|
||||||
@@ -893,11 +895,12 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
* @param textureIndex 0=Slot9(R), 1=Slot10(G), 2=Slot11(B), 3=Slot12(A), -1=Löschen(alle→0)
|
* @param textureIndex 0=Slot9(R), 1=Slot10(G), 2=Slot11(B), 3=Slot12(A), -1=Löschen(alle→0)
|
||||||
*/
|
*/
|
||||||
private void applyThirdTexturePaint(Vector3f contact, float strength, int textureIndex) {
|
private void applyThirdTexturePaint(Vector3f contact, float strength, int textureIndex) {
|
||||||
float radius = (float) input.textureTool.brushRadius.getValue();
|
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 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 centerPZ = (SPLAT_SIZE - 1) - Math.round((contact.z + WORLD_HALF) / SPLAT_WE_PER_PX);
|
||||||
int pixR = (int) Math.ceil(radius / SPLAT_WE_PER_PX);
|
int pixR = (int) Math.ceil(softEdge / SPLAT_WE_PER_PX);
|
||||||
|
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
for (int dz = -pixR; dz <= pixR; dz++) {
|
for (int dz = -pixR; dz <= pixR; dz++) {
|
||||||
@@ -908,9 +911,9 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
if (px < 0 || px >= SPLAT_SIZE) continue;
|
if (px < 0 || px >= SPLAT_SIZE) continue;
|
||||||
|
|
||||||
float distWE = FastMath.sqrt(dx * dx + dz * dz) * SPLAT_WE_PER_PX;
|
float distWE = FastMath.sqrt(dx * dx + dz * dz) * SPLAT_WE_PER_PX;
|
||||||
if (distWE >= radius) continue;
|
if (distWE >= softEdge) continue;
|
||||||
|
|
||||||
float t = distWE / radius;
|
float t = distWE / softEdge;
|
||||||
float falloff = (1f + FastMath.cos(FastMath.PI * t)) * 0.5f;
|
float falloff = (1f + FastMath.cos(FastMath.PI * t)) * 0.5f;
|
||||||
int idx = pz * SPLAT_SIZE + px;
|
int idx = pz * SPLAT_SIZE + px;
|
||||||
float blend = strength * falloff;
|
float blend = strength * falloff;
|
||||||
@@ -974,11 +977,16 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
|
|
||||||
// Terrain-Shader mit DayNightState synchronisieren (reagiert auf Zeit-Menü-Änderungen)
|
// Terrain-Shader mit DayNightState synchronisieren (reagiert auf Zeit-Menü-Änderungen)
|
||||||
if (terrainMat != null && dayNightState != null && dayNightState.getSunLight() != null) {
|
if (terrainMat != null && dayNightState != null && dayNightState.getSunLight() != null) {
|
||||||
terrainMat.setVector3("LightDir", dayNightState.getSunDirection().negate());
|
com.jme3.math.Vector3f lightDir = dayNightState.getSunDirection().negate();
|
||||||
com.jme3.math.ColorRGBA sc = dayNightState.getSunLight().getColor();
|
com.jme3.math.ColorRGBA sc = dayNightState.getSunLight().getColor();
|
||||||
com.jme3.math.ColorRGBA ac = dayNightState.getCustomAmbient();
|
com.jme3.math.ColorRGBA ac = dayNightState.getCustomAmbient();
|
||||||
terrainMat.setVector3("SunColor", new com.jme3.math.Vector3f(sc.r, sc.g, sc.b));
|
com.jme3.math.Vector3f sunColor = new com.jme3.math.Vector3f(sc.r, sc.g, sc.b);
|
||||||
terrainMat.setVector3("AmbientColor", new com.jme3.math.Vector3f(ac.r, ac.g, ac.b));
|
com.jme3.math.Vector3f ambColor = new com.jme3.math.Vector3f(ac.r, ac.g, ac.b);
|
||||||
|
terrainMat.setVector3("LightDir", lightDir);
|
||||||
|
terrainMat.setVector3("SunColor", sunColor);
|
||||||
|
terrainMat.setVector3("AmbientColor", ambColor);
|
||||||
|
SculptedMeshEditorState smes = getStateManager().getState(SculptedMeshEditorState.class);
|
||||||
|
if (smes != null) smes.updateBakedMatLighting(lightDir, sunColor, ambColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
float pgx = input.pendingGotoX;
|
float pgx = input.pendingGotoX;
|
||||||
@@ -1113,6 +1121,7 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
private void processTextureEdits() {
|
private void processTextureEdits() {
|
||||||
SharedInput.TextureEdit edit;
|
SharedInput.TextureEdit edit;
|
||||||
int processed = 0;
|
int processed = 0;
|
||||||
|
VoxelEditorState ves = getStateManager().getState(VoxelEditorState.class);
|
||||||
while ((edit = input.textureEditQueue.poll()) != null && processed < MAX_EDITS_PER_FRAME) {
|
while ((edit = input.textureEditQueue.poll()) != null && processed < MAX_EDITS_PER_FRAME) {
|
||||||
processed++;
|
processed++;
|
||||||
float jmeX = (float)(edit.screenX() * input.viewportScaleX);
|
float jmeX = (float)(edit.screenX() * input.viewportScaleX);
|
||||||
@@ -1122,10 +1131,9 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
Vector3f far = cam.getWorldCoordinates(new Vector2f(jmeX, jmeY), 1f);
|
Vector3f far = cam.getWorldCoordinates(new Vector2f(jmeX, jmeY), 1f);
|
||||||
com.jme3.math.Ray ray = new com.jme3.math.Ray(near, far.subtract(near).normalizeLocal());
|
com.jme3.math.Ray ray = new com.jme3.math.Ray(near, far.subtract(near).normalizeLocal());
|
||||||
|
|
||||||
CollisionResults texHits = new CollisionResults();
|
Vector3f contact = raycastSurface(ray);
|
||||||
terrain.collideWith(ray, texHits);
|
if (contact == null) continue;
|
||||||
if (texHits.size() == 0) continue;
|
if (ves != null && ves.terrainTypeAt(contact.x, contact.z) == VoxelEditorState.TerrainType.VOXEL_UNBAKED) continue;
|
||||||
Vector3f contact = texHits.getClosestCollision().getContactPoint();
|
|
||||||
|
|
||||||
int selIdx = input.textureTool.textureIndex.getSelectedIndex();
|
int selIdx = input.textureTool.textureIndex.getSelectedIndex();
|
||||||
float str = (float) input.textureTool.brushStrength.getValue();
|
float str = (float) input.textureTool.brushStrength.getValue();
|
||||||
@@ -1151,6 +1159,13 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
/** Gibt den TerrainQuad-Node zurück (z.B. für Voxel-Raycasts). */
|
/** Gibt den TerrainQuad-Node zurück (z.B. für Voxel-Raycasts). */
|
||||||
public TerrainQuad getTerrainNode() { return terrain; }
|
public TerrainQuad getTerrainNode() { return terrain; }
|
||||||
|
|
||||||
|
/** Gibt das Terrain-Material zurück (für BakedTerrain-Material-Aufbau in anderen States). */
|
||||||
|
public com.jme3.material.Material getTerrainMaterial() { return terrainMat; }
|
||||||
|
|
||||||
|
public com.jme3.texture.Texture2D getSplatTex() { return splatTex; }
|
||||||
|
public com.jme3.texture.Texture2D getUpperSplatTex() { return upperSplatTex; }
|
||||||
|
public com.jme3.texture.Texture2D getThirdSplatTex() { return thirdSplatTex; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raycast gegen Basis-Terrain, ungebackenes Voxel-Terrain und gebackene Sculpted-Meshes.
|
* 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.
|
* Gibt den zur Kamera nächstgelegenen Treffer zurück, oder null wenn keines getroffen wurde.
|
||||||
@@ -1387,6 +1402,10 @@ public class TerrainEditorState extends BaseAppState {
|
|||||||
brushRadius = (layer == 0)
|
brushRadius = (layer == 0)
|
||||||
? (float) input.heightTool.brushRadius.getValue()
|
? (float) input.heightTool.brushRadius.getValue()
|
||||||
: (float) input.textureTool.brushRadius.getValue();
|
: (float) input.textureTool.brushRadius.getValue();
|
||||||
|
VoxelEditorState ves = getStateManager().getState(VoxelEditorState.class);
|
||||||
|
if (ves != null && ves.terrainTypeAt(contactPoint.x, contactPoint.z) == VoxelEditorState.TerrainType.VOXEL_UNBAKED) {
|
||||||
|
contactPoint = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (layer == 3) {
|
} else if (layer == 3) {
|
||||||
contactPoint = raycastSurface(ray);
|
contactPoint = raycastSurface(ray);
|
||||||
|
|||||||
@@ -3283,15 +3283,12 @@ public class VoxelEditorState extends BaseAppState {
|
|||||||
|
|
||||||
private void updateBrushIndicator() {
|
private void updateBrushIndicator() {
|
||||||
if (brushIndicator == null) return;
|
if (brushIndicator == null) return;
|
||||||
boolean isVoxelOrTex = input.activeLayer == SharedInput.LAYER_VOXEL
|
if (input.activeLayer != SharedInput.LAYER_VOXEL) {
|
||||||
|| input.activeLayer == 4;
|
|
||||||
if (!isVoxelOrTex) {
|
|
||||||
brushIndicator.setCullHint(Spatial.CullHint.Always);
|
brushIndicator.setCullHint(Spatial.CullHint.Always);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Im Selektierungs-Modus nur Mauszeiger, kein Brush-Indikator
|
// Im Selektierungs-Modus nur Mauszeiger, kein Brush-Indikator
|
||||||
if (input.activeLayer == SharedInput.LAYER_VOXEL
|
if (input.voxelTool.mode.getSelectedIndex() == de.blight.editor.tool.VoxelTool.MODE_DELETE_BAKED) {
|
||||||
&& input.voxelTool.mode.getSelectedIndex() == de.blight.editor.tool.VoxelTool.MODE_DELETE_BAKED) {
|
|
||||||
brushIndicator.setCullHint(Spatial.CullHint.Always);
|
brushIndicator.setCullHint(Spatial.CullHint.Always);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -3305,9 +3302,7 @@ public class VoxelEditorState extends BaseAppState {
|
|||||||
float jmeY = cam.getHeight() - my * (float) input.viewportScaleY;
|
float jmeY = cam.getHeight() - my * (float) input.viewportScaleY;
|
||||||
Hit hit = raycastHit(jmeX, jmeY);
|
Hit hit = raycastHit(jmeX, jmeY);
|
||||||
if (hit != null) {
|
if (hit != null) {
|
||||||
float r = (input.activeLayer == 4)
|
float r = (float) input.voxelTool.brushRadius.getValue();
|
||||||
? (float) input.textureTool.brushRadius.getValue()
|
|
||||||
: (float) input.voxelTool.brushRadius.getValue();
|
|
||||||
|
|
||||||
// Leicht entlang der Flächen-Normalen versetzt, um Z-Fighting zu vermeiden
|
// Leicht entlang der Flächen-Normalen versetzt, um Z-Fighting zu vermeiden
|
||||||
brushIndicator.setLocalTranslation(hit.pos.add(hit.normal().mult(0.05f)));
|
brushIndicator.setLocalTranslation(hit.pos.add(hit.normal().mult(0.05f)));
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ public class TextureTool extends EditorTool {
|
|||||||
"Textur", TEXTURE_NAMES, 0
|
"Textur", TEXTURE_NAMES, 0
|
||||||
);
|
);
|
||||||
|
|
||||||
public final ToolParameter brushRadius = new ToolParameter("Pinselradius", 50.0, 1.0, 500.0);
|
public final ToolParameter brushRadius = new ToolParameter("Pinselradius", 5.0, 1.0, 500.0);
|
||||||
public final ToolParameter brushStrength = new ToolParameter("Pinselstärke", 0.05, 0.005, 0.5);
|
public final ToolParameter brushStrength = new ToolParameter("Pinselstärke", 0.25, 0.005, 0.5);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() { return "Textur"; }
|
public String getName() { return "Textur"; }
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user