diff --git a/engine/src/terrain/Common/MatDefs/Terrain/HeightBasedTerrain.frag b/engine/src/terrain/Common/MatDefs/Terrain/HeightBasedTerrain.frag new file mode 100644 index 000000000..91dacd2d4 --- /dev/null +++ b/engine/src/terrain/Common/MatDefs/Terrain/HeightBasedTerrain.frag @@ -0,0 +1,76 @@ +uniform vec3 m_region1; +uniform vec3 m_region2; +uniform vec3 m_region3; +uniform vec3 m_region4; + +uniform sampler2D m_region1ColorMap; +uniform sampler2D m_region2ColorMap; +uniform sampler2D m_region3ColorMap; +uniform sampler2D m_region4ColorMap; +uniform sampler2D m_slopeColorMap; + +uniform float m_slopeTileFactor; +uniform float m_terrainSize; + +varying vec3 normal; +varying vec4 position; + +vec4 GenerateTerrainColor() { + float height = position.y; + vec4 p = position / m_terrainSize; + + vec3 blend = abs( normal ); + blend = (blend -0.2) * 0.7; + blend = normalize(max(blend, 0.00001)); // Force weights to sum to 1.0 (very important!) + float b = (blend.x + blend.y + blend.z); + blend /= vec3(b, b, b); + + vec4 terrainColor = vec4(0, 0, 0, 1.0); + + float m_regionMin = 0.0; + float m_regionMax = 0.0; + float m_regionRange = 0.0; + float m_regionWeight = 0.0; + + vec4 slopeCol1 = texture2D(m_slopeColorMap, p.yz * m_slopeTileFactor); + vec4 slopeCol2 = texture2D(m_slopeColorMap, p.xy * m_slopeTileFactor); + + // Terrain m_region 1. + m_regionMin = m_region1.x; + m_regionMax = m_region1.y; + m_regionRange = m_regionMax - m_regionMin; + m_regionWeight = (m_regionRange - abs(height - m_regionMax)) / m_regionRange; + m_regionWeight = max(0.0, m_regionWeight); + terrainColor += m_regionWeight * texture2D(m_region1ColorMap, p.xz * m_region1.z); + + // Terrain m_region 2. + m_regionMin = m_region2.x; + m_regionMax = m_region2.y; + m_regionRange = m_regionMax - m_regionMin; + m_regionWeight = (m_regionRange - abs(height - m_regionMax)) / m_regionRange; + m_regionWeight = max(0.0, m_regionWeight); + terrainColor += m_regionWeight * (texture2D(m_region2ColorMap, p.xz * m_region2.z)); + + // Terrain m_region 3. + m_regionMin = m_region3.x; + m_regionMax = m_region3.y; + m_regionRange = m_regionMax - m_regionMin; + m_regionWeight = (m_regionRange - abs(height - m_regionMax)) / m_regionRange; + m_regionWeight = max(0.0, m_regionWeight); + terrainColor += m_regionWeight * texture2D(m_region3ColorMap, p.xz * m_region3.z); + + // Terrain m_region 4. + m_regionMin = m_region4.x; + m_regionMax = m_region4.y; + m_regionRange = m_regionMax - m_regionMin; + m_regionWeight = (m_regionRange - abs(height - m_regionMax)) / m_regionRange; + m_regionWeight = max(0.0, m_regionWeight); + terrainColor += m_regionWeight * texture2D(m_region4ColorMap, p.xz * m_region4.z); + + return (blend.y * terrainColor + blend.x * slopeCol1 + blend.z * slopeCol2); +} + +void main() { + vec4 color = GenerateTerrainColor(); + gl_FragColor = color; +} diff --git a/engine/src/terrain/Common/MatDefs/Terrain/HeightBasedTerrain.j3md b/engine/src/terrain/Common/MatDefs/Terrain/HeightBasedTerrain.j3md new file mode 100644 index 000000000..856a09e97 --- /dev/null +++ b/engine/src/terrain/Common/MatDefs/Terrain/HeightBasedTerrain.j3md @@ -0,0 +1,41 @@ +MaterialDef Terrain { + + // Parameters to material: + // regionXColorMap: X = 1..4 the texture that should be appliad to state X + // regionX: a Vector3f containing the following information: + // regionX.x: the start height of the region + // regionX.y: the end height of the region + // regionX.z: the texture scale for the region + // it might not be the most elegant way for storing these 3 values, but it packs the data nicely :) + // slopeColorMap: the texture to be used for cliffs, and steep mountain sites + // slopeTileFactor: the texture scale for slopes + // terrainSize: the total size of the terrain (used for scaling the texture) + MaterialParameters { + Texture2D region1ColorMap + Texture2D region2ColorMap + Texture2D region3ColorMap + Texture2D region4ColorMap + Texture2D slopeColorMap + Float slopeTileFactor + Float terrainSize + Vector3 region1 + Vector3 region2 + Vector3 region3 + Vector3 region4 + } + + Technique { + VertexShader GLSL130: Common/MatDefs/Terrain/HeightBasedTerrain.vert + FragmentShader GLSL130: Common/MatDefs/Terrain/HeightBasedTerrain.frag + + WorldParameters { + WorldViewProjectionMatrix + WorldMatrix + NormalMatrix + } + } + + Technique FixedFunc { + } + +} \ No newline at end of file diff --git a/engine/src/terrain/Common/MatDefs/Terrain/HeightBasedTerrain.vert b/engine/src/terrain/Common/MatDefs/Terrain/HeightBasedTerrain.vert new file mode 100644 index 000000000..8260d8f72 --- /dev/null +++ b/engine/src/terrain/Common/MatDefs/Terrain/HeightBasedTerrain.vert @@ -0,0 +1,22 @@ +uniform float m_tilingFactor; +uniform mat4 g_WorldViewProjectionMatrix; +uniform mat4 g_WorldMatrix; +uniform mat3 g_NormalMatrix; + +uniform float m_terrainSize; + +attribute vec4 inTexCoord; +attribute vec3 inNormal; +attribute vec3 inPosition; + +varying vec3 normal; +varying vec4 position; + +void main() +{ + normal = normalize(inNormal); + position = g_WorldMatrix * vec4(inPosition, 0.0); + gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1); +} + + diff --git a/engine/src/test-data/Textures/Terrain/grid/rock.jpg b/engine/src/test-data/Textures/Terrain/grid/rock.jpg new file mode 100644 index 000000000..343dc1cb9 Binary files /dev/null and b/engine/src/test-data/Textures/Terrain/grid/rock.jpg differ diff --git a/engine/src/test/jme3test/terrain/TerrainGridTest.java b/engine/src/test/jme3test/terrain/TerrainGridTest.java index edfca2fc5..352e14ec0 100644 --- a/engine/src/test/jme3test/terrain/TerrainGridTest.java +++ b/engine/src/test/jme3test/terrain/TerrainGridTest.java @@ -60,29 +60,40 @@ public class TerrainGridTest extends SimpleApplication { this.stateManager.attach(state); // TERRAIN TEXTURE material - mat_terrain = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md"); - mat_terrain.setBoolean("useTriPlanarMapping", false); - - // ALPHA map (for splat textures) - mat_terrain.setTexture("Alpha", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png")); - + this.mat_terrain = new Material(this.assetManager, "Common/MatDefs/Terrain/HeightBasedTerrain.j3md"); + + // Parameters to material: + // regionXColorMap: X = 1..4 the texture that should be appliad to state X + // regionX: a Vector3f containing the following information: + // regionX.x: the start height of the region + // regionX.y: the end height of the region + // regionX.z: the texture scale for the region + // it might not be the most elegant way for storing these 3 values, but it packs the data nicely :) + // slopeColorMap: the texture to be used for cliffs, and steep mountain sites + // slopeTileFactor: the texture scale for slopes + // terrainSize: the total size of the terrain (used for scaling the texture) // GRASS texture - Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); + Texture grass = this.assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); grass.setWrap(WrapMode.Repeat); - mat_terrain.setTexture("Tex1", grass); - mat_terrain.setFloat("Tex1Scale", grassScale); + this.mat_terrain.setTexture("region1ColorMap", grass); + this.mat_terrain.setVector3("region1", new Vector3f(88, 200, this.grassScale)); // DIRT texture - Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); + Texture dirt = this.assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); dirt.setWrap(WrapMode.Repeat); - mat_terrain.setTexture("Tex2", dirt); - mat_terrain.setFloat("Tex2Scale", dirtScale); + this.mat_terrain.setTexture("region2ColorMap", dirt); + this.mat_terrain.setVector3("region2", new Vector3f(0, 90, this.dirtScale)); // ROCK texture - Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg"); + Texture rock = this.assetManager.loadTexture("Textures/Terrain/grid/rock.jpg"); rock.setWrap(WrapMode.Repeat); - mat_terrain.setTexture("Tex3", rock); - mat_terrain.setFloat("Tex3Scale", rockScale); + this.mat_terrain.setTexture("region3ColorMap", rock); + this.mat_terrain.setVector3("region3", new Vector3f(198, 260, this.rockScale)); + + this.mat_terrain.setTexture("slopeColorMap", rock); + this.mat_terrain.setFloat("slopeTileFactor", 32); + + this.mat_terrain.setFloat("terrainSize", 513); this.base = new FractalSum(); this.base.setRoughness(0.7f);