254 lines
No EOL
7.6 KiB
Text
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
|
|
}
|
|
]] |