LumixEngine/data/pipelines/terrain.shd
2022-12-15 18:55:52 +01:00

254 lines
No EOL
7.6 KiB
Text

include "pipelines/common.glsl"
texture_slot {
name = "Heightmap",
default_texture = "textures/common/white.tga"
}
texture_slot {
name = "Detail albedo",
default_texture = "textures/common/white.tga"
}
texture_slot {
name = "Detail normal",
default_texture = "textures/common/white.tga"
}
texture_slot {
name = "Splatmap",
default_texture = "textures/common/white.tga"
}
texture_slot {
name = "Satellite",
default_texture = "textures/common/white.tga"
}
texture_slot {
name = "Noise",
default_texture = "textures/common/blue_noise.tga"
}
uniform("Roughness", "normalized_float", 1)
uniform("Metallic", "normalized_float", 0)
uniform("Emission", "float", 0)
uniform("Detail distance", "float")
uniform("Detail scale", "float")
uniform("Noise UV scale", "float")
uniform("Detail diffusion", "float")
uniform("Detail power", "float")
common [[
layout(binding=0) uniform sampler2D u_hm;
layout(binding=1) uniform sampler2DArray t_albedo;
layout(binding=2) uniform sampler2DArray t_normal;
layout(binding=3) uniform sampler2D t_splatmap;
layout(binding=4) uniform sampler2D t_satellite;
layout(binding=5) uniform sampler2D t_noise;
layout(std140, binding = 4) uniform Drawcall {
ivec4 u_from_to;
ivec4 u_from_to_sup;
vec4 u_position;
vec4 u_rel_camera_pos;
vec4 u_terrain_scale;
vec2 u_hm_size;
float u_cell_size;
};
]]
vertex_shader [[
#ifndef DEPTH
layout (location = 0) out vec2 v_uv;
layout (location = 1) out float v_dist2;
#endif
void main() {
ivec2 ij = u_from_to.xy + ivec2((gl_VertexID >> 1), gl_InstanceID + (gl_VertexID & 1));
vec3 v = vec3(0);
v.xz = vec2(ij) * u_cell_size;
int mask = ~1;
vec3 npos = vec3(0);
npos.xz = vec2(ij & mask) * u_cell_size;
vec2 size = vec2(u_from_to_sup.zw - u_from_to_sup.xy);
vec2 rel = (ij - u_from_to_sup.xy) / size;
rel = saturate(abs(rel - vec2(0.5)) * 10 - 4);
v.xz = mix(v.xz, npos.xz, rel.yx);
v.xz = clamp(v.xz, vec2(0), u_hm_size);
vec2 hm_uv = (v.xz + vec2(0.5 * u_terrain_scale.x)) / (u_hm_size + u_terrain_scale.x);
#ifndef DEPTH
v_uv = v.xz / u_hm_size;
float h = texture(u_hm, hm_uv).x * u_terrain_scale.y;
#else
float h = texture(u_hm, hm_uv).x * u_terrain_scale.y;
#endif
vec4 p = Pass.view * vec4(u_position.xyz + v + vec3(0, h, 0), 1);
#ifndef DEPTH
v_dist2 = dot(p.xyz, p.xyz);
#endif
gl_Position = Pass.projection * p;
}
]]
fragment_shader [[
#ifdef DEFERRED
layout(location = 0) out vec4 o_gbuffer0;
layout(location = 1) out vec4 o_gbuffer1;
layout(location = 2) out vec4 o_gbuffer2;
#elif !defined DEPTH
layout(location = 0) out vec4 o_color;
#endif
#ifndef DEPTH
layout (location = 0) in vec2 v_uv;
layout (location = 1) in float v_dist2;
float rgbSum(vec4 v) { return dot(v, vec4(1, 1, 1, 0)); }
mat3 getTBN(vec2 uv)
{
float hscale = u_terrain_scale.y / u_terrain_scale.x;
float s01 = textureLodOffset(u_hm, uv, 0, ivec2(-1, 0)).x;
float s21 = textureLodOffset(u_hm, uv, 0, ivec2(1, 0)).x;
float s10 = textureLodOffset(u_hm, uv, 0, ivec2(0, -1)).x;
float s12 = textureLodOffset(u_hm, uv, 0, ivec2(0, 1)).x;
vec3 va = normalize(vec3(1.0, (s21-s01) * hscale, 0.0));
vec3 vb = normalize(vec3(0.0, (s12-s10) * hscale, 1.0));
vec3 N = normalize(cross(vb,va));
vec3 T = normalize(cross(N, vb));
return mat3(
T,
N,
normalize(cross(T, N))
);
}
struct Detail {
vec4 albedo;
vec3 normal;
};
Detail textureNoTile(float dist2, vec2 x, int layer, vec2 dPdx, vec2 dPdy) {
Detail detail;
detail.normal.xy = textureGrad(t_normal, vec3(x, layer), dPdx, dPdy).xy * 2 - 1;
detail.albedo = textureGrad(t_albedo, vec3(x, layer), dPdx, dPdy);
const float blend_start_sqr = 10 * 10;
if (dist2 > blend_start_sqr) {
vec2 N;
vec3 uv = vec3(x * 0.1, layer);
dPdx *= 0.1;
dPdy *= 0.1;
vec4 albedo = textureGrad(t_albedo, uv, dPdx, dPdy);
N = textureGrad(t_normal, uv, dPdx, dPdy).xy * 2 - 1;
float t = saturate((dist2 - blend_start_sqr) / 10000);
detail.normal.xy = mix(detail.normal.xy, N, t);
detail.albedo = mix(detail.albedo, albedo, t);
}
detail.normal.z = sqrt(saturate(1 - dot(detail.normal.xy, detail.normal.xy)));
return detail;
}
vec2 power(vec2 v, vec2 a) {
vec2 t = pow(v, a);
return t / (t + pow(vec2(1.0) - v, a));
}
Surface getSurface()
{
Surface surface;
if(v_dist2 < u_detail_distance * u_detail_distance) {
vec2 uv_norm = v_uv; // [0 - 1]
vec2 grid_size = u_hm_size / u_terrain_scale.xz;
vec2 resolution = grid_size + 1;
vec2 r = vec2(texture(t_noise, uv_norm * u_noise_uv_scale * grid_size).x,
texture(t_noise, uv_norm.yx * u_noise_uv_scale * grid_size).x);
r = r * u_detail_diffusion * 2 - u_detail_diffusion;
uv_norm += r / u_hm_size;
vec2 uv = uv_norm * grid_size;
vec2 uv_ratio = power(fract(uv), vec2(u_detail_power));
vec2 uv_opposite = 1.0 - uv_ratio;
vec4 bicoef = vec4(
uv_opposite.x * uv_opposite.y,
uv_opposite.x * uv_ratio.y,
uv_ratio.x * uv_opposite.y,
uv_ratio.x * uv_ratio.y
);
vec2 uv_grid = uv / resolution;
// todo textureGather
vec4 splat00 = textureLodOffset(t_splatmap, uv_grid, 0, ivec2(0, 0));
vec4 splat10 = textureLodOffset(t_splatmap, uv_grid, 0, ivec2(1, 0));
vec4 splat01 = textureLodOffset(t_splatmap, uv_grid, 0, ivec2(0, 1));
vec4 splat11 = textureLodOffset(t_splatmap, uv_grid, 0, ivec2(1, 1));
vec2 uv_detail = u_detail_scale * v_uv * u_hm_size;
ivec4 indices = ivec4(vec4(splat00.x, splat01.x, splat10.x, splat11.x) * 255.0 + 0.5);
vec2 dPdx = dFdx(uv_detail);
vec2 dPdy = dFdy(uv_detail);
Detail c00 = textureNoTile(v_dist2, uv_detail, indices.x, dPdx, dPdy);
Detail c01 = indices.x == indices.y ? c00 : textureNoTile(v_dist2, uv_detail, indices.y, dPdx, dPdy);
Detail c10 = indices.x == indices.z ? c00 : indices.y == indices.z ? c01 : textureNoTile(v_dist2, uv_detail, indices.z, dPdx, dPdy);
Detail c11 = indices.x == indices.w ? c00 : indices.y == indices.w ? c01 : indices.z == indices.w ? c10 : textureNoTile(v_dist2, uv_detail, indices.w, dPdx, dPdy);
surface.albedo = (c00.albedo * bicoef.x + c01.albedo * bicoef.y + c10.albedo * bicoef.z + c11.albedo * bicoef.w).rgb;
vec3 n = (c00.normal * bicoef.x + c01.normal * bicoef.y + c10.normal * bicoef.z + c11.normal * bicoef.w).xzy;
surface.N = normalize(getTBN(v_uv) * n);
surface.alpha = 1;
// blend between detail and satellite
float sat_blend_start = u_detail_distance * 0.05;
float sat_blend_start_sqr = sat_blend_start * sat_blend_start;
if (v_dist2 > sat_blend_start_sqr) {
float m = (v_dist2 - sat_blend_start_sqr) / (u_detail_distance * u_detail_distance);
m = saturate((m - 0.8) * 5);
vec3 sat_color = texture(t_satellite, vec3(v_uv, 0).xy).rgb;
sat_color *= saturate(0.5 + texture(t_noise, v_uv * 10, -2).r * texture(t_noise, v_uv*29, -2).r * 0.5);
surface.albedo = mix(surface.albedo, sat_color, m);
}
}
else {
surface.N = getTBN(v_uv)[1];
surface.albedo = texture(t_satellite, vec3(v_uv, 0).xy).rgb;
surface.albedo *= saturate(0.5 + texture(t_noise, v_uv * 10, -2).r * texture(t_noise, v_uv*29, -2).r * 0.5);
surface.alpha = 1;
}
surface.wpos = vec3(0);
surface.roughness = u_roughness;
surface.metallic = u_metallic;
surface.emission = u_emission;
surface.translucency = 0;
surface.ao = 0.9;
surface.shadow = saturate(Global.light_dir.y * 3) * 0.9;
return surface;
}
#endif
void main()
{
#if defined DEFERRED
Surface surface = getSurface();
packSurface(surface, o_gbuffer0, o_gbuffer1, o_gbuffer2);
#elif !defined DEPTH
o_color.rgb = vec3(1, 0, 1);
o_color.w = 1;
#endif
}
]]