Forked from wojtekpil/hterrain_detail_enhanced.shader
Created
August 5, 2021 10:58
-
-
Save BransonGitomeh/8c2fddae1cc1cd3195f1a7ccd248db8d to your computer and use it in GitHub Desktop.
Hterrain enhanced shader for detail layers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
shader_type spatial; | |
render_mode cull_disabled, blend_mix,diffuse_burley, specular_schlick_ggx; | |
uniform sampler2D u_terrain_heightmap; | |
uniform sampler2D u_terrain_detailmap; | |
uniform sampler2D u_terrain_normalmap; | |
uniform sampler2D u_terrain_globalmap : hint_albedo; | |
uniform mat4 u_terrain_inverse_transform; | |
uniform mat3 u_terrain_normal_basis; | |
uniform sampler2D u_albedo_alpha : hint_albedo; | |
uniform sampler2D u_normalmap: hint_normal; | |
uniform float u_view_distance = 100.0; | |
uniform float u_globalmap_tint_bottom : hint_range(0.0, 1.0); | |
uniform float u_globalmap_tint_top : hint_range(0.0, 1.0); | |
uniform float u_bottom_ao : hint_range(0.0, 1.0); | |
uniform vec2 u_ambient_wind; // x: amplitude, y: time | |
uniform vec3 u_instance_scale = vec3(1.0, 1.0, 1.0); | |
uniform vec4 u_transmission: hint_color; | |
uniform sampler2D u_albedo_gradient_color: hint_albedo; | |
uniform float u_gradient_influence = 0.0; | |
uniform float u_alpha_scissor = 0.5; | |
uniform float u_base_roughness = 1.0; | |
uniform float u_camera_bend_strength = 0.05; | |
varying vec3 v_normal; | |
varying vec2 v_map_uv; | |
float get_hash(vec2 c) { | |
return fract(sin(dot(c.xy, vec2(12.9898,78.233))) * 43758.5453); | |
} | |
vec3 unpack_normal(vec4 rgba) { | |
vec3 n = rgba.xzy * 2.0 - vec3(1.0); | |
n.z *= -1.0; | |
return n; | |
} | |
vec3 get_ambient_wind_displacement(vec2 uv, float hash) { | |
// TODO This is an initial basic implementation. It may be improved in the future, especially for strong wind. | |
float t = u_ambient_wind.y; | |
float amp = u_ambient_wind.x * (1.0 - uv.y); | |
// Main displacement | |
vec3 disp = amp * vec3(cos(t), 0, sin(t * 1.2)); | |
// Fine displacement | |
float fine_disp_frequency = 2.0; | |
disp += 0.2 * amp * vec3(cos(t * (fine_disp_frequency + hash)), 0, sin(t * (fine_disp_frequency + hash) * 1.2)); | |
return disp; | |
} | |
void vertex() { | |
vec4 obj_pos = WORLD_MATRIX * vec4(0, 1, 0, 1); | |
vec3 cell_coords = (u_terrain_inverse_transform * obj_pos).xyz; | |
// Must add a half-offset so that we sample the center of pixels, | |
// otherwise bilinear filtering of the textures will give us mixed results (#183) | |
cell_coords.xz += vec2(0.5); | |
vec2 map_uv = cell_coords.xz / vec2(textureSize(u_terrain_heightmap, 0)); | |
v_map_uv = map_uv; | |
//float density = 0.5 + 0.5 * sin(4.0*TIME); // test | |
float density = texture(u_terrain_detailmap, map_uv).r; | |
float hash = get_hash(obj_pos.xz); | |
if (density > hash) { | |
// Snap model to the terrain | |
// Assuming VERTEX is in local model space | |
float height_v = VERTEX.y; | |
float height = texture(u_terrain_heightmap, map_uv).r / cell_coords.y; | |
VERTEX *= u_instance_scale; | |
VERTEX.y += height; | |
VERTEX += get_ambient_wind_displacement(UV, hash); | |
// Fade alpha with distance | |
vec3 wpos = (WORLD_MATRIX * vec4(VERTEX, 1)).xyz; | |
float dr = distance(wpos, CAMERA_MATRIX[3].xyz) / u_view_distance; | |
COLOR.a = clamp(1.0 - dr * dr * dr, 0.0, 1.0); | |
// The important part | |
float ndotv = 1.0 - dot(vec3(0.0, 1.0, 0.0), normalize(CAMERA_MATRIX[1].xyz)); | |
wpos.xz += CAMERA_MATRIX[1].xz * ndotv * u_camera_bend_strength * height_v; | |
// Converting the world pos back to local pos | |
VERTEX = (inverse(WORLD_MATRIX) * vec4(wpos,1.0)).xyz; | |
// When using billboards, the normal is the same as the terrain regardless of face orientation | |
v_normal = normalize(u_terrain_normal_basis * unpack_normal(texture(u_terrain_normalmap, map_uv))); | |
} else { | |
// Discard, output degenerate triangles | |
VERTEX = vec3(0, 0, 0); | |
} | |
} | |
void fragment() { | |
NORMAL = (INV_CAMERA_MATRIX * (WORLD_MATRIX * vec4(v_normal, 0.0))).xyz; | |
NORMAL = mix(NORMAL, normalize(vec3(0.33,0.33,0.33)), 0.5); | |
ALPHA_SCISSOR = u_alpha_scissor; | |
vec4 col = texture(u_albedo_alpha, UV); | |
vec4 norm = texture(u_normalmap, UV); | |
vec4 col2 = texture(u_albedo_gradient_color, vec2(1.0 - UV.y, 0)); | |
ALPHA = col.a * COLOR.a;// - clamp(1.4 - UV.y, 0.0, 1.0);//* 0.5 + 0.5*cos(2.0*TIME); | |
ALBEDO = mix(COLOR.rgb * col.rgb, COLOR.rgb * col2.rgb, u_gradient_influence); | |
// Blend with ground color | |
float nh = sqrt(1.0 - UV.y); | |
ALBEDO = mix(ALBEDO, texture(u_terrain_globalmap, v_map_uv).rgb, mix(u_globalmap_tint_bottom, u_globalmap_tint_top, nh)); | |
// Fake bottom AO | |
ALBEDO = ALBEDO * mix(1.0, 1.0 - u_bottom_ao, UV.y * UV.y); | |
TRANSMISSION = u_transmission.rgb; | |
ROUGHNESS = mix(0.5, u_base_roughness , pow(UV.y, 0.5)); | |
NORMALMAP = norm.rgb; | |
NORMALMAP_DEPTH = 1.0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment