mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-06-21 18:17:03 +08:00
feat: water effects (#19)
* feat(shaders): add lighting to block accumulation OIT shaders * feat(renderer): add water rendering with OIT and new shaders * feat(water): implement screen-space reflection and refraction for water with depth fade and perturbation * refactor(shader): replace glUniform calls with generic set_loc and remove cached locations * feat(water): add noise-based caustics and configurable fog density * fix(water shader): update depth fade and remove underwater check - Increase DEPTH_FADE_DISTANCE from 8 to 10 - Remove conditional so depth fade always applies - Darken deepColor from (0, 0.08, 0.15) to (0, 0.015, 0.045) * feat(underwater): add volume scattering and shadow mapping for light shafts
This commit is contained in:
@@ -4,10 +4,21 @@ layout (location = 0) out vec4 accum;
|
||||
layout (location = 1) out float reveal;
|
||||
|
||||
in vec2 tc;
|
||||
in vec3 normal;
|
||||
in vec3 vert_pos;
|
||||
in float roughness;
|
||||
flat in int tex_layer;
|
||||
in float v_depth;
|
||||
layout (binding = 0) uniform sampler2DArray samp;
|
||||
|
||||
uniform float ambientStrength;
|
||||
uniform vec3 sunlightColor;
|
||||
uniform vec3 ambientColor;
|
||||
uniform vec3 sunlightDir;
|
||||
uniform vec3 cameraPos;
|
||||
uniform bool shader_on;
|
||||
uniform float specularStrength;
|
||||
|
||||
float weight(float z, float a) {
|
||||
float intermediate = 0.03 / (1e-5 + pow(z / 200.0, 4.0));
|
||||
|
||||
@@ -15,7 +26,71 @@ float weight(float z, float a) {
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 color = texture(samp, vec3(tc, tex_layer));
|
||||
|
||||
vec4 objectColor = texture(samp, vec3(tc, tex_layer));
|
||||
|
||||
if (!shader_on) {
|
||||
vec4 color = objectColor;
|
||||
float alpha = color.a;
|
||||
if (alpha < 1e-4) discard;
|
||||
|
||||
|
||||
float w = weight(v_depth, alpha);
|
||||
|
||||
accum = vec4(color.rgb * alpha * w, alpha * w);
|
||||
|
||||
reveal = alpha;
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 lightDir = normalize(-sunlightDir);
|
||||
|
||||
vec3 norm = normalize(normal);
|
||||
|
||||
vec3 V =
|
||||
normalize(cameraPos - vert_pos);
|
||||
|
||||
vec3 H =
|
||||
normalize(lightDir + V);
|
||||
|
||||
vec3 ambient = ambientStrength * ambientColor;
|
||||
|
||||
float diff = max(dot(norm, lightDir), 0.0);
|
||||
|
||||
vec3 diffuse = diff * sunlightColor;
|
||||
|
||||
float r =
|
||||
clamp(roughness, 0.0, 1.0);
|
||||
|
||||
float shininess =
|
||||
mix(
|
||||
512.0,
|
||||
4.0,
|
||||
r
|
||||
);
|
||||
float ks =
|
||||
mix(
|
||||
0.8,
|
||||
0.02,
|
||||
r
|
||||
);
|
||||
|
||||
float spec = 0.0;
|
||||
|
||||
if(diff > 0.0)
|
||||
{
|
||||
spec =
|
||||
ks *
|
||||
pow(
|
||||
max(dot(norm,H),0.0),
|
||||
shininess
|
||||
);
|
||||
}
|
||||
|
||||
vec3 specular = spec * sunlightColor * specularStrength;
|
||||
|
||||
vec4 color = vec4((ambient + diffuse) * objectColor.rgb + specular, objectColor.a);
|
||||
|
||||
float alpha = color.a;
|
||||
if (alpha < 1e-4) discard;
|
||||
|
||||
|
||||
@@ -3,19 +3,28 @@
|
||||
layout (location = 0) in vec3 pos;
|
||||
layout (location = 1) in vec2 texCoord;
|
||||
layout (location = 2) in float layer;
|
||||
layout (location = 3) in vec3 aNormal;
|
||||
layout (location = 4) in float Roughness;
|
||||
|
||||
out vec2 tc;
|
||||
out vec3 normal;
|
||||
out vec3 vert_pos;
|
||||
flat out int tex_layer;
|
||||
out float roughness;
|
||||
out float v_depth;
|
||||
|
||||
uniform mat4 mv_matrix;
|
||||
uniform mat4 proj_matrix;
|
||||
|
||||
uniform mat4 norm_matrix;
|
||||
|
||||
|
||||
void main(void) {
|
||||
vec4 view_pos = mv_matrix * vec4(pos, 1.0);
|
||||
gl_Position = proj_matrix * view_pos;
|
||||
vert_pos = pos;
|
||||
roughness = Roughness;
|
||||
tc = texCoord;
|
||||
tex_layer = int(layer);
|
||||
v_depth = -view_pos.z;
|
||||
normal = mat3(norm_matrix) * aNormal;
|
||||
gl_Position = proj_matrix * view_pos;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ float fbm(vec2 p) {
|
||||
return v;
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
vec3 computeSkyColor(vec3 dir) {
|
||||
vec3 sund = normalize(sunDir);
|
||||
|
||||
float t =
|
||||
@@ -88,6 +88,13 @@ void main(void) {
|
||||
|
||||
sky += glow * sunColor;
|
||||
|
||||
return sky;
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
|
||||
vec3 sky = computeSkyColor(dir);
|
||||
|
||||
frag_color = vec4(sky, 1.0);
|
||||
//frag_color = vec4(vec3(sunAmount), 1.0);
|
||||
//frag_color = vec4(t,0,0,1);
|
||||
|
||||
@@ -1,35 +1,137 @@
|
||||
#version 460
|
||||
|
||||
in vec2 TexCoord;
|
||||
in vec3 rayDir;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
uniform sampler2D u_sceneTexture;
|
||||
layout (binding = 0) uniform sampler2D u_sceneTexture;
|
||||
layout (binding = 1) uniform sampler2D u_depthTexture;
|
||||
layout (binding = 2) uniform sampler2D u_shadowMap;
|
||||
uniform mat4 u_lightSpaceMatrix;
|
||||
uniform float u_time;
|
||||
uniform bool u_underwater;
|
||||
uniform vec3 u_waterColor;
|
||||
uniform float u_fogDensity;
|
||||
uniform mat4 InverseViewProjection;
|
||||
uniform vec3 cameraPos;
|
||||
uniform vec3 sunDir;
|
||||
uniform vec3 sunColor;
|
||||
uniform float waterDensity;
|
||||
|
||||
float hash(vec2 p) {
|
||||
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
|
||||
}
|
||||
|
||||
float noise(vec2 p) {
|
||||
vec2 i = floor(p);
|
||||
vec2 f = fract(p);
|
||||
f = f * f * (3.0 - 2.0 * f);
|
||||
|
||||
return mix(
|
||||
mix(hash(i), hash(i + vec2(1.0, 0.0)), f.x),
|
||||
mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), f.x),
|
||||
f.y
|
||||
);
|
||||
}
|
||||
|
||||
float fbm(vec2 p) {
|
||||
float value = 0.0;
|
||||
float amp = 0.5;
|
||||
float freq = 1.0;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
value += amp * noise(p * freq);
|
||||
freq *= 2.0;
|
||||
amp *= 0.5;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
float getCausticValue(float x, float y, float z) {
|
||||
float w = 8.0;
|
||||
float strength = 4.0;
|
||||
vec2 coord = vec2(x, y) * w + z * 0.5;
|
||||
|
||||
float n = fbm(coord);
|
||||
|
||||
float caustic = pow(n, 3.0) * strength;
|
||||
return caustic;
|
||||
}
|
||||
|
||||
float getShadow(vec3 worldPos) {
|
||||
vec4 posLightSpace = u_lightSpaceMatrix * vec4(worldPos, 1.0);
|
||||
vec3 projCoords = posLightSpace.xyz / posLightSpace.w;
|
||||
projCoords = projCoords * 0.5 + 0.5;
|
||||
|
||||
if (projCoords.z > 1.0) return 1.0;
|
||||
|
||||
float closestDepth = texture(u_shadowMap, projCoords.xy).r;
|
||||
float currentDepth = projCoords.z;
|
||||
|
||||
return currentDepth - 0.005 > closestDepth ? 0.0 : 1.0;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 original = texture(u_sceneTexture, TexCoord);
|
||||
|
||||
|
||||
if (!u_underwater) {
|
||||
FragColor = original;
|
||||
return;
|
||||
}
|
||||
|
||||
float rawDepth = texture(u_depthTexture, TexCoord).r;
|
||||
vec3 ndc = vec3(TexCoord * 2.0 - 1.0, rawDepth * 2.0 - 1.0);
|
||||
vec4 worldPosH = InverseViewProjection * vec4(ndc, 1.0);
|
||||
vec3 worldPos = worldPosH.xyz / worldPosH.w;
|
||||
float sceneDistance = distance(cameraPos, worldPos);
|
||||
|
||||
vec2 distoredUV = TexCoord;
|
||||
float strength = 0.003;
|
||||
distoredUV.x += sin(TexCoord.y * 15.0 + u_time * 5.0) * strength;
|
||||
distoredUV.y += cos(TexCoord.x * 15.0 + u_time * 4.3) * strength;
|
||||
distoredUV = clamp(distoredUV, 0.001, 0.999);
|
||||
vec4 distorted = texture(u_sceneTexture, distoredUV);
|
||||
vec4 distorted = texture(u_sceneTexture, distoredUV);
|
||||
|
||||
float rawCaustic = getCausticValue(TexCoord.x, TexCoord.y, u_time * 0.3);
|
||||
float caustic = 0.5 + rawCaustic * 0.5;
|
||||
vec3 causticLight = vec3(caustic * 0.9, caustic, caustic * 0.7);
|
||||
|
||||
float caustic = 0.9 + 0.1 * sin(TexCoord.x * 20.0 + u_time) * cos(TexCoord.y * 20.0 + u_time * 1.2);
|
||||
vec3 causticLight = vec3(caustic, caustic * 0.95, caustic * 0.9);
|
||||
//vec3 causticLight = vec3(1.0);
|
||||
float fogFactor = clamp(1.0 - (TexCoord.y * u_fogDensity * 10.0), 0.0, 1.0);
|
||||
vec3 mixed = mix(u_waterColor, distorted.rgb * causticLight, fogFactor);
|
||||
// Volume Scattering
|
||||
vec3 rayOrigin = cameraPos;
|
||||
vec3 rayDirection = normalize(rayDir);
|
||||
|
||||
FragColor = vec4(mixed, 1.0);
|
||||
float maxDist = 10.0; // Maximum visible distance
|
||||
float stepSize = 0.4;
|
||||
float phasePower = 8.0; // Beam Sharpness
|
||||
|
||||
vec3 scattering = vec3(0.0);
|
||||
float transmittance = 1.0;
|
||||
|
||||
float cosTheta = dot(rayDirection, sunDir);
|
||||
float phase = pow(max(cosTheta, 0.0), phasePower);
|
||||
|
||||
for (float t = 0.0; t < maxDist; t += stepSize) {
|
||||
|
||||
if (t > sceneDistance) break;
|
||||
vec3 pos = rayOrigin + rayDirection * t;
|
||||
|
||||
float shadow = getShadow(pos);
|
||||
|
||||
float density = waterDensity;
|
||||
|
||||
|
||||
vec3 absorption = vec3(0.3, 0.08, 0.02); // Absorption coefficient per meter
|
||||
vec3 sunLightAtPos = sunColor * exp(-absorption * t);
|
||||
|
||||
scattering += density * phase * sunLightAtPos * transmittance * stepSize * shadow;
|
||||
|
||||
float extinction = waterDensity * 1.5; // Extinction coefficient, tunable
|
||||
transmittance *= exp(-extinction * stepSize);
|
||||
if (transmittance < 0.01) break;
|
||||
}
|
||||
|
||||
FragColor.rgb = mixed + scattering;
|
||||
FragColor.a = 1.0;
|
||||
}
|
||||
@@ -3,9 +3,18 @@
|
||||
layout (location = 0) in vec2 pos;
|
||||
layout (location = 1) in vec2 texCoord;
|
||||
|
||||
out vec2 TexCoord;
|
||||
uniform mat4 InverseViewProjection;
|
||||
uniform vec3 cameraPos;
|
||||
|
||||
out vec2 TexCoord;
|
||||
out vec3 rayDir;
|
||||
void main() {
|
||||
gl_Position = vec4(pos.x, pos.y, 0.0, 1.0);
|
||||
TexCoord = texCoord;
|
||||
vec4 clipPos = vec4(pos, 1.0, 1.0);
|
||||
vec4 worldPosH = InverseViewProjection * clipPos;
|
||||
vec3 worldPos = worldPosH.xyz / worldPosH.w;
|
||||
vec3 RayDir = worldPos - cameraPos;
|
||||
rayDir = normalize(RayDir);
|
||||
gl_Position = clipPos;
|
||||
|
||||
}
|
||||
316
assets/shaders/water_f_shader.glsl
Normal file
316
assets/shaders/water_f_shader.glsl
Normal file
@@ -0,0 +1,316 @@
|
||||
#version 460
|
||||
|
||||
layout (location = 0) out vec4 accum;
|
||||
layout (location = 1) out float reveal;
|
||||
|
||||
in vec2 tc;
|
||||
in vec3 normal;
|
||||
in vec3 vert_pos;
|
||||
in vec3 world_pos;
|
||||
in float roughness;
|
||||
flat in int tex_layer;
|
||||
in float v_depth;
|
||||
layout (binding = 0) uniform sampler2DArray samp;
|
||||
uniform sampler2D sceneColorTex; // binding 1
|
||||
uniform sampler2D sceneDepthTex; // binding 2
|
||||
|
||||
uniform mat4 proj_matrix;
|
||||
uniform mat4 inv_proj_matrix;
|
||||
uniform mat4 inv_view_matrix;
|
||||
|
||||
uniform float ambientStrength;
|
||||
uniform vec3 sunlightColor;
|
||||
uniform vec3 ambientColor;
|
||||
uniform vec3 sunlightDir;
|
||||
uniform vec3 cameraPos;
|
||||
uniform bool shader_on;
|
||||
uniform float specularStrength;
|
||||
|
||||
uniform vec3 skyTop;
|
||||
uniform vec3 skyBottom;
|
||||
uniform vec3 sunColor;
|
||||
uniform float horizonSharpness;
|
||||
uniform float cloudWhiteMix;
|
||||
uniform float cloudThresholdLow;
|
||||
uniform float cloudThresholdHigh;
|
||||
uniform float time;
|
||||
|
||||
uniform vec3 sunDir; // world!
|
||||
|
||||
uniform bool underwater;
|
||||
|
||||
uniform float refractStrength;
|
||||
|
||||
uniform bool enablePerturb;
|
||||
uniform bool enableDepthFade;
|
||||
float weight(float z, float a) {
|
||||
float intermediate = 0.03 / (1e-5 + pow(z / 200.0, 4.0));
|
||||
|
||||
return a * clamp(intermediate, 1e-2, 3e2);
|
||||
}
|
||||
|
||||
float hash(vec2 p) {
|
||||
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
|
||||
}
|
||||
|
||||
float noise(vec2 p) {
|
||||
vec2 i = floor(p);
|
||||
vec2 f = fract(p);
|
||||
f = f * f * (3.0 - 2.0 * f);
|
||||
float a = hash(i);
|
||||
float b = hash(i + vec2(1.0, 0.0));
|
||||
float c = hash(i + vec2(0.0, 1.0));
|
||||
float d = hash(i + vec2(1.0, 1.0));
|
||||
return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
|
||||
}
|
||||
|
||||
float fbm(vec2 p) {
|
||||
float v = 0.0;
|
||||
float amp = 0.5;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
v += amp * noise(p);
|
||||
p *= 2.0;
|
||||
amp *= 0.5;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
vec3 computeSkyColor(vec3 dir) {
|
||||
vec3 sund = normalize(sunDir);
|
||||
|
||||
float t =
|
||||
clamp(
|
||||
dir.y * 0.5 + 0.5,
|
||||
0.0,
|
||||
1.0
|
||||
);
|
||||
|
||||
|
||||
vec3 sky =
|
||||
mix(
|
||||
skyBottom,
|
||||
skyTop,
|
||||
pow(t, horizonSharpness)
|
||||
);
|
||||
|
||||
// cloud
|
||||
if (dir.y > 0.0) {
|
||||
vec2 cloud_uv = dir.xz / (dir.y + 0.15) * 0.5 + vec2(time * 0.005, time * 0.002);
|
||||
float cloud_density = fbm(cloud_uv * 2.0);
|
||||
float safeLow = cloudThresholdLow;
|
||||
float safeHigh = max(cloudThresholdHigh, cloudThresholdLow + 0.001);
|
||||
cloud_density = smoothstep(safeLow,safeHigh, cloud_density);
|
||||
|
||||
|
||||
float fade = smoothstep(0.0, 0.3, dir.y) * (1.0 - smoothstep(0.85, 1.0, dir.y));
|
||||
cloud_density *= fade;
|
||||
|
||||
vec3 cloud_color = mix(skyBottom, vec3(1.0), cloudWhiteMix);
|
||||
sky = mix(sky, cloud_color, cloud_density * 0.6);
|
||||
}
|
||||
|
||||
float sunAmount = max(dot(dir, sund), 0.0);
|
||||
|
||||
//float glow = pow(sunAmount, 8.0) * 0.15;
|
||||
|
||||
float glow = pow(sunAmount, 8.0) * 0.15 + pow(sunAmount, 32.0) * 0.3;
|
||||
|
||||
sky += glow * sunColor;
|
||||
|
||||
return sky;
|
||||
}
|
||||
|
||||
// Reconstruct eye-space coordinates from screen UV and depth buffer value
|
||||
vec3 reconstructViewPos(vec2 uv, float depth) {
|
||||
vec4 clip = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
|
||||
vec4 view = inv_proj_matrix * clip;
|
||||
return view.xyz / view.w;
|
||||
}
|
||||
// Screen-space ray marching, origin/dir are in eye space
|
||||
bool traceSSR(vec3 origin, vec3 dir, out vec2 hitUV) {
|
||||
const int COARSE_STEPS = 32;
|
||||
const float COARSE_STEP = 0.6;
|
||||
const int REFINE_STEPS = 8;
|
||||
const float THICKNESS = 0.3;
|
||||
|
||||
vec3 pos = origin;
|
||||
vec3 prevPos = origin;
|
||||
bool foundCoarse = false;
|
||||
|
||||
|
||||
for (int i = 0; i < COARSE_STEPS; ++i) {
|
||||
prevPos = pos;
|
||||
pos += dir * COARSE_STEP;
|
||||
|
||||
vec4 clip = proj_matrix * vec4(pos, 1.0);
|
||||
if (clip.w <= 0.0) return false;
|
||||
vec3 ndc = clip.xyz / clip.w;
|
||||
if (abs(ndc.x) > 1.0 || abs(ndc.y) > 1.0) return false;
|
||||
|
||||
vec2 uv = ndc.xy * 0.5 + 0.5;
|
||||
float sceneDepth = texture(sceneDepthTex, uv).r;
|
||||
vec3 scenePos = reconstructViewPos(uv, sceneDepth);
|
||||
|
||||
if (pos.z - scenePos.z < 0.0) {
|
||||
foundCoarse = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundCoarse) return false;
|
||||
|
||||
|
||||
vec3 lo = prevPos;
|
||||
vec3 hi = pos;
|
||||
|
||||
for (int i = 0; i < REFINE_STEPS; ++i) {
|
||||
vec3 mid = (lo + hi) * 0.5;
|
||||
|
||||
vec4 clip = proj_matrix * vec4(mid, 1.0);
|
||||
vec3 ndc = clip.xyz / clip.w;
|
||||
vec2 uv = ndc.xy * 0.5 + 0.5;
|
||||
float sceneDepth = texture(sceneDepthTex, uv).r;
|
||||
vec3 scenePos = reconstructViewPos(uv, sceneDepth);
|
||||
|
||||
if (mid.z - scenePos.z < 0.0) {
|
||||
hi = mid;
|
||||
} else {
|
||||
lo = mid;
|
||||
}
|
||||
}
|
||||
|
||||
vec4 finalClip = proj_matrix * vec4(hi, 1.0);
|
||||
vec3 finalNdc = finalClip.xyz / finalClip.w;
|
||||
vec2 finalUV = finalNdc.xy * 0.5 + 0.5;
|
||||
|
||||
float finalDepth = texture(sceneDepthTex, finalUV).r;
|
||||
vec3 finalScenePos = reconstructViewPos(finalUV, finalDepth);
|
||||
|
||||
if (abs(hi.z - finalScenePos.z) > THICKNESS) return false;
|
||||
|
||||
hitUV = finalUV;
|
||||
return true;
|
||||
}
|
||||
void main() {
|
||||
|
||||
vec4 objectColor = texture(samp, vec3(tc, tex_layer));
|
||||
|
||||
if (!shader_on) {
|
||||
vec4 color = objectColor;
|
||||
float alpha = color.a;
|
||||
if (alpha < 1e-4) discard;
|
||||
|
||||
|
||||
float w = weight(v_depth, alpha);
|
||||
|
||||
accum = vec4(color.rgb * alpha * w, alpha * w);
|
||||
|
||||
reveal = alpha;
|
||||
return;
|
||||
}
|
||||
// Normal perturbation
|
||||
vec3 N;
|
||||
if (enablePerturb) {
|
||||
const float wave_speed_scale = 40.0;
|
||||
vec2 waveUV1 = world_pos.xz * 8.0 + vec2(time * 0.05 * wave_speed_scale, time * 0.03 * wave_speed_scale);
|
||||
vec2 waveUV2 = world_pos.xz * 13.0 + vec2(-time * 0.04 * wave_speed_scale, time * 0.06 * wave_speed_scale);
|
||||
|
||||
float wave1 = noise(waveUV1);
|
||||
float wave2 = noise(waveUV2);
|
||||
|
||||
vec2 normalPerturb = vec2(wave1 - 0.5, wave2 - 0.5) * 0.1;
|
||||
N = normalize(normal + vec3(normalPerturb.x, 0.0, normalPerturb.y));
|
||||
} else {
|
||||
N = normalize(normal);
|
||||
}
|
||||
|
||||
vec3 V = normalize(-vert_pos);
|
||||
|
||||
vec3 reflectColor;
|
||||
vec3 refractColor;
|
||||
float fresnel;
|
||||
|
||||
vec2 screenUV = gl_FragCoord.xy / vec2(textureSize(sceneDepthTex, 0));
|
||||
|
||||
// water depth
|
||||
float sceneDepthRaw = texture(sceneDepthTex, screenUV).r;
|
||||
vec3 sceneViewPos = reconstructViewPos(screenUV, sceneDepthRaw);
|
||||
float waterDepth = vert_pos.z - sceneViewPos.z;
|
||||
waterDepth = max(waterDepth, 0.0);
|
||||
|
||||
const float DEPTH_FADE_DISTANCE = 10;
|
||||
float depthFactor = clamp(waterDepth / DEPTH_FADE_DISTANCE, 0.0, 1.0);
|
||||
|
||||
if (underwater) {
|
||||
reflectColor = vec3(0.0);
|
||||
refractColor = objectColor.rgb;
|
||||
fresnel = 0.0;
|
||||
} else {
|
||||
vec3 R = reflect(-V, N);
|
||||
vec3 origin = vert_pos + N * 0.05;
|
||||
vec2 hitUV;
|
||||
|
||||
if (traceSSR(origin, R, hitUV)) {
|
||||
reflectColor = texture(sceneColorTex, hitUV).rgb;
|
||||
} else {
|
||||
vec3 worldR = mat3(inv_view_matrix) * R;
|
||||
reflectColor = computeSkyColor(worldR);
|
||||
}
|
||||
|
||||
float effectiveRefractStrength = refractStrength * (1.0 - depthFactor * 0.5);
|
||||
vec2 refractOffset = N.xz * effectiveRefractStrength;
|
||||
vec2 refractUV = clamp(screenUV + refractOffset, vec2(0.001), vec2(0.999));
|
||||
|
||||
refractColor = texture(sceneColorTex, refractUV).rgb;
|
||||
|
||||
fresnel = pow(1.0 - max(dot(N, V), 0.0), 5.0);
|
||||
fresnel = mix(0.02, 1.0, fresnel);
|
||||
}
|
||||
|
||||
vec3 lightDir = normalize(-sunlightDir);
|
||||
vec3 H = normalize(lightDir + V);
|
||||
vec3 ambient = ambientStrength * ambientColor;
|
||||
float diff = max(dot(N, lightDir), 0.0);
|
||||
vec3 diffuse = diff * sunlightColor;
|
||||
|
||||
float r = clamp(roughness, 0.0, 1.0);
|
||||
float shininess = mix(512.0, 4.0, r);
|
||||
float ks = mix(0.8, 0.02, r);
|
||||
|
||||
float spec = 0.0;
|
||||
if (diff > 0.0) {
|
||||
spec = ks * pow(max(dot(N, H), 0.0), shininess);
|
||||
}
|
||||
vec3 specular = spec * sunlightColor * specularStrength;
|
||||
|
||||
vec3 tintedRefract;
|
||||
|
||||
if (enableDepthFade) {
|
||||
vec3 shallowColor = vec3(0.4, 0.75, 0.7);
|
||||
vec3 deepColor = vec3(0.0, 0.015, 0.045);
|
||||
|
||||
vec3 waterTint = mix(shallowColor, deepColor, depthFactor);
|
||||
|
||||
tintedRefract = mix(refractColor, refractColor * waterTint, depthFactor);
|
||||
tintedRefract = mix(tintedRefract, objectColor.rgb, 0.4); // Forcefully blend 40% texture color, independent of depth
|
||||
} else {
|
||||
tintedRefract = mix(refractColor, objectColor.rgb, 0.4);
|
||||
}
|
||||
|
||||
//vec3 baseWaterColor = (ambient + diffuse) * objectColor.rgb + specular;
|
||||
vec3 baseWaterColor = (ambient + diffuse) * tintedRefract + specular;
|
||||
|
||||
vec3 finalColor = mix(baseWaterColor, reflectColor, fresnel);
|
||||
|
||||
float alpha = objectColor.a;
|
||||
if (alpha < 1e-4) discard;
|
||||
|
||||
|
||||
float w = weight(v_depth, alpha);
|
||||
|
||||
accum = vec4(finalColor * alpha * w, alpha * w);
|
||||
|
||||
reveal = alpha;
|
||||
|
||||
return;
|
||||
}
|
||||
32
assets/shaders/water_v_shader.glsl
Normal file
32
assets/shaders/water_v_shader.glsl
Normal file
@@ -0,0 +1,32 @@
|
||||
#version 460
|
||||
|
||||
layout (location = 0) in vec3 pos;
|
||||
layout (location = 1) in vec2 texCoord;
|
||||
layout (location = 2) in float layer;
|
||||
layout (location = 3) in vec3 aNormal;
|
||||
layout (location = 4) in float Roughness;
|
||||
|
||||
out vec2 tc;
|
||||
out vec3 normal;
|
||||
out vec3 vert_pos;
|
||||
out vec3 world_pos;
|
||||
flat out int tex_layer;
|
||||
out float roughness;
|
||||
out float v_depth;
|
||||
|
||||
uniform mat4 mv_matrix;
|
||||
uniform mat4 proj_matrix;
|
||||
uniform mat4 norm_matrix;
|
||||
|
||||
|
||||
void main(void) {
|
||||
vec4 view_pos = mv_matrix * vec4(pos, 1.0);
|
||||
world_pos = pos;
|
||||
vert_pos = view_pos.xyz;
|
||||
normal = mat3(norm_matrix) * aNormal;
|
||||
roughness = Roughness;
|
||||
tc = texCoord;
|
||||
tex_layer = int(layer);
|
||||
v_depth = -view_pos.z;
|
||||
gl_Position = proj_matrix * view_pos;
|
||||
}
|
||||
Reference in New Issue
Block a user