# 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;