forked from Rowland/EG
143 lines
5.0 KiB
YAML
143 lines
5.0 KiB
YAML
|
|
# Terrain effect
|
|
# This effect uses prodecural shader splatting, you most likely want to modify
|
|
# it with your own texture-map generation code.
|
|
|
|
vertex:
|
|
inout: |
|
|
uniform struct {
|
|
sampler2D data_texture;
|
|
sampler2D heightfield;
|
|
int view_index;
|
|
int terrain_size;
|
|
int chunk_size;
|
|
} ShaderTerrainMesh;
|
|
out vec2 terrain_uv;
|
|
|
|
transform: |
|
|
// Terrain data has the layout:
|
|
// x: x-pos, y: y-pos, z: size, w: clod
|
|
vec4 terrain_data = texelFetch(ShaderTerrainMesh.data_texture,
|
|
ivec2(gl_InstanceID, ShaderTerrainMesh.view_index), 0);
|
|
|
|
// Get initial chunk position in the (0, 0, 0), (1, 1, 0) range
|
|
vec3 chunk_position = p3d_Vertex.xyz;
|
|
|
|
// CLOD implementation
|
|
float clod_factor = smoothstep(0, 1, terrain_data.w);
|
|
chunk_position.xy -= clod_factor * fract(chunk_position.xy * ShaderTerrainMesh.chunk_size / 2.0)
|
|
* 2.0 / ShaderTerrainMesh.chunk_size;
|
|
|
|
// Scale the chunk
|
|
chunk_position *= terrain_data.z * float(ShaderTerrainMesh.chunk_size)
|
|
/ float(ShaderTerrainMesh.terrain_size);
|
|
chunk_position.z *= ShaderTerrainMesh.chunk_size;
|
|
|
|
// Offset the chunk, it is important that this happens after the scale
|
|
chunk_position.xy += terrain_data.xy / float(ShaderTerrainMesh.terrain_size);
|
|
|
|
// Compute the terrain UV coordinates
|
|
terrain_uv = chunk_position.xy;
|
|
|
|
// Sample the heightfield and offset the terrain - we do not need to multiply
|
|
// the height with anything since the terrain transform is included in the
|
|
// model view projection matrix.
|
|
chunk_position.z += texture(ShaderTerrainMesh.heightfield, terrain_uv).x;
|
|
|
|
// Lower the terrain on the borders - this ensures the shadow map is generated
|
|
// correctly.
|
|
if ( min(terrain_uv.x, terrain_uv.y) < 8.0 / ShaderTerrainMesh.terrain_size ||
|
|
max(terrain_uv.x, terrain_uv.y) > 1 - 9.0 / ShaderTerrainMesh.terrain_size) {
|
|
chunk_position.z = 0;
|
|
}
|
|
|
|
vOutput.position = (p3d_ModelMatrix * vec4(chunk_position, 1)).xyz;
|
|
|
|
fragment:
|
|
defines: |
|
|
#define DONT_FETCH_DEFAULT_TEXTURES 1
|
|
#define DONT_SET_MATERIAL_PROPERTIES 1
|
|
|
|
inout: |
|
|
layout(location=4) in vec2 terrain_uv;
|
|
layout(location=5) uniform struct {
|
|
sampler2D data_texture;
|
|
sampler2D heightfield;
|
|
int view_index;
|
|
int terrain_size;
|
|
int chunk_size;
|
|
} ShaderTerrainMesh;
|
|
|
|
material: |
|
|
|
|
// Compute terrain normal
|
|
const float terrain_height = 1000.0;
|
|
vec3 pixel_size = vec3(1.0, -1.0, 0) / textureSize(ShaderTerrainMesh.heightfield, 0).xxx;
|
|
float h_u0 = texture(ShaderTerrainMesh.heightfield, terrain_uv + pixel_size.yz).x * terrain_height;
|
|
float h_u1 = texture(ShaderTerrainMesh.heightfield, terrain_uv + pixel_size.xz).x * terrain_height;
|
|
float h_v0 = texture(ShaderTerrainMesh.heightfield, terrain_uv + pixel_size.zy).x * terrain_height;
|
|
float h_v1 = texture(ShaderTerrainMesh.heightfield, terrain_uv + pixel_size.zx).x * terrain_height;
|
|
vec3 tangent = normalize(vec3(1, 0, h_u1 - h_u0));
|
|
vec3 binormal = normalize(vec3(0, 1, h_v1 - h_v0));
|
|
vec3 normal = normalize(cross(tangent, binormal));
|
|
|
|
normal.x *= -1;
|
|
// normal.y *= -1;
|
|
|
|
// Material splatting
|
|
float height = (h_u0 + h_u1 + h_v0 + h_v1) / (4.0 * terrain_height); // xxx
|
|
float slope = 1.0 - normal.z;
|
|
float grass = 0.0;
|
|
float rock = 0.0;
|
|
float snow = 0.0;
|
|
|
|
{ // Snow
|
|
snow = saturate(4.0 * (height-0.49));
|
|
snow *= saturate(pow(saturate(1.0 - slope), 2.0)) * 12.0;
|
|
|
|
//snow -= 0.6;
|
|
//snow *= 0.5;
|
|
snow = saturate(snow);
|
|
snow = pow(snow, 2.0);
|
|
}
|
|
|
|
{ // Rock
|
|
rock = saturate((pow(slope, 1.2) * 12.0 - 0.02) * 4.5);
|
|
}
|
|
|
|
{ // Grass
|
|
grass = 1.0 - saturate(rock + snow);
|
|
}
|
|
|
|
|
|
// Material definitions
|
|
|
|
MaterialShaderOutput grass_mat = make_default_material_output();
|
|
grass_mat.basecolor = vec3(0.1, 0.2, 0.1);
|
|
grass_mat.roughness = 0.8;
|
|
|
|
MaterialShaderOutput rock_mat = make_default_material_output();
|
|
rock_mat.basecolor = vec3(0.13);
|
|
rock_mat.roughness = 0.8;
|
|
rock_mat.specular_ior = 1.4;
|
|
|
|
MaterialShaderOutput snow_mat = make_default_material_output();
|
|
snow_mat.basecolor = vec3(0.6, 0.6, 0.9);
|
|
snow_mat.roughness = 0.5;
|
|
snow_mat.specular_ior = 1.7;
|
|
|
|
m.basecolor = vec3(0);
|
|
m.shading_model = SHADING_MODEL_DEFAULT;
|
|
m.specular_ior = 0.0;
|
|
m.metallic = 0.0;
|
|
m.roughness = 0.0;
|
|
m.shading_model_param0 = 0.0;
|
|
m.normal = vec3(0);
|
|
|
|
merge_material_output(m, grass_mat, grass);
|
|
merge_material_output(m, rock_mat, rock);
|
|
merge_material_output(m, snow_mat, snow);
|
|
|
|
m.normal = normal;
|
|
|