VulkanShader_1.21.10-0.0.4-alpha.jar
Download file
#version 450
#include "fog.glsl"
layout(binding = 1) uniform UBO {
vec4 FogColor;
float FogEnvironmentalStart;
float FogEnvironmentalEnd;
float FogRenderDistanceStart;
float FogRenderDistanceEnd;
float FogSkyEnd;
float FogCloudsEnd;
float AlphaCutout;
float Time;
vec4 Light0_Direction;
mat4 ModelViewMat;
mat4 ProjMat;
vec2 ScreenSize;
mat4 LightSpaceMat;
};
layout(binding = 2) uniform sampler2D Sampler0;
layout(binding = 3) uniform sampler2D SceneColor;
layout(binding = 4) uniform sampler2D SceneDepth;
layout(binding = 6) uniform sampler2D ShadowSampler;
layout(location = 0) in vec4 vertexColor;
layout(location = 1) in vec2 texCoord0;
layout(location = 2) in float sphericalVertexDistance;
layout(location = 3) in float cylindricalVertexDistance;
layout(location = 4) in vec3 worldPos;
layout(location = 5) in vec2 worldXZ;
layout(location = 0) out vec4 fragColor;
float depth_delta(float sceneDepth, float waterDepth) {
return max(sceneDepth - waterDepth, 0.0);
}
float projected_depth(vec4 clipPos) {
return clipPos.z / clipPos.w * 0.5 + 0.5;
}
float computeShadow(vec3 pos, vec3 normal, vec3 lightDir) {
float biasMultiplier = sqrt(1.0 - clamp(dot(normal, lightDir), 0.0, 1.0));
vec3 biasedPos = pos + normal * 0.05 * biasMultiplier + lightDir * 0.008;
vec4 lightSpacePos = LightSpaceMat * vec4(biasedPos, 1.0);
vec3 projCoords = lightSpacePos.xyz / lightSpacePos.w;
vec2 shadowCoords = projCoords.xy * 0.5 + 0.5;
float currentDepth = projCoords.z;
if (shadowCoords.x < 0.0 || shadowCoords.x > 1.0 ||
shadowCoords.y < 0.0 || shadowCoords.y > 1.0 ||
currentDepth < 0.0 || currentDepth > 1.0) return 0.0;
vec2 texelSize = vec2(1.0 / 2048.0);
float s0 = currentDepth > texture(ShadowSampler, shadowCoords + vec2( texelSize.x, texelSize.y)).r ? 1.0 : 0.0;
float s1 = currentDepth > texture(ShadowSampler, shadowCoords + vec2(-texelSize.x, texelSize.y)).r ? 1.0 : 0.0;
float s2 = currentDepth > texture(ShadowSampler, shadowCoords + vec2( texelSize.x, -texelSize.y)).r ? 1.0 : 0.0;
float s3 = currentDepth > texture(ShadowSampler, shadowCoords + vec2(-texelSize.x, -texelSize.y)).r ? 1.0 : 0.0;
return (s0 + s1 + s2 + s3) * 0.25;
}
void main() {
vec4 waterSample = texture(Sampler0, texCoord0);
if (waterSample.a * vertexColor.a < AlphaCutout) discard;
float nearField = 1.0 - smoothstep(FogRenderDistanceStart * 0.20, FogRenderDistanceEnd * 0.85, cylindricalVertexDistance);
float mediumField = 1.0 - smoothstep(FogRenderDistanceStart * 0.10, FogRenderDistanceEnd * 0.55, cylindricalVertexDistance);
// --- Wave normals: 3 layers for organic motion ---
// FIX 5: increased amplitudes so fresnel/normal actually varies
vec2 wave1 = vec2(sin(worldXZ.x * 2.4 + Time * 0.8), cos(worldXZ.y * 2.0 + Time * 0.6)) * 0.032;
vec2 wave2 = vec2(sin(worldXZ.y * 3.1 - Time * 0.5), cos(worldXZ.x * 2.7 + Time * 0.7)) * 0.020;
vec2 wave3 = vec2(sin(worldXZ.x * 1.1 + Time * 0.25), cos(worldXZ.y * 0.9 - Time * 0.2)) * 0.012;
vec2 waveDist = (wave1 + wave2 + wave3) * mix(0.35, 1.0, nearField);
vec3 normal = normalize(vec3(waveDist.x, 1.0, waveDist.y));
vec3 lightDir = normalize(Light0_Direction.xyz);
float shadow = computeShadow(worldPos, normal, lightDir);
float waterShadow = 1.0 - shadow * 0.42;
float daylight = clamp(lightDir.y * 0.85 + 0.15, 0.0, 1.0);
float skyAmbient = clamp(dot(FogColor.rgb, vec3(0.2126, 0.7152, 0.0722)) * 1.35, 0.08, 0.75);
float nightFactor = 1.0 - daylight;
// FIX 1: viewDir points FROM surface TOWARD camera (negate worldPos which is cam-relative)
vec3 viewDir = normalize(-worldPos);
vec3 reflectDir = reflect(-viewDir, normal);
// FIX 1 (cont): dot product now correct — viewDir and normal both point "up/toward cam"
float NdotV = max(dot(viewDir, normal), 0.0);
float fresnel = mix(0.08, 0.90, pow(1.0 - NdotV, 4.2));
// --- Screen-space reflection ---
// FIX 2: project a world-space offset point, not a direction vector
// We march a small step along reflectDir from the surface and project that point
vec3 reflSamplePoint = worldPos + reflectDir * 3.5;
vec4 reflClip = ProjMat * ModelViewMat * vec4(reflSamplePoint, 1.0); // w=1, valid point
vec2 reflUV = (reflClip.xy / reflClip.w) * vec2(0.5, -0.5) + 0.5;
reflUV += waveDist * (0.10 + 0.12 * mediumField); // calmer in the distance
vec2 edgeFade = smoothstep(0.0, 0.06, min(reflUV, 1.0 - reflUV));
float edgeMask = edgeFade.x * edgeFade.y;
float reflectedDepth = projected_depth(reflClip);
float sceneReflDepth = texture(SceneDepth, clamp(reflUV, 0.0, 1.0)).r;
float reflectionDelta = abs(sceneReflDepth - reflectedDepth);
float reflectionHit = 1.0 - smoothstep(0.0, 0.080, reflectionDelta);
float reflectionMask = edgeMask * mix(0.45, 1.0, reflectionHit) * float(reflClip.w > 0.0);
vec3 fallbackRefl = mix(vec3(0.04, 0.06, 0.10), vec3(0.22, 0.42, 0.72), daylight);
vec3 reflectionSample = texture(SceneColor, clamp(reflUV, 0.0, 1.0)).rgb;
vec3 reflection = mix(fallbackRefl, reflectionSample * mix(0.78, 1.16, daylight), reflectionMask);
// --- Refraction: sample SceneColor slightly distorted for underbody look ---
vec2 screenUV = gl_FragCoord.xy / ScreenSize;
vec2 refractUV = screenUV + waveDist * (0.008 + 0.020 * nearField);
vec3 refraction = texture(SceneColor, clamp(refractUV, 0.0, 1.0)).rgb;
float sceneDepth = texture(SceneDepth, clamp(refractUV, 0.0, 1.0)).r;
float waterDepth = gl_FragCoord.z;
float thickness = depth_delta(sceneDepth, waterDepth);
float thicknessCue = clamp(thickness * 120.0, 0.0, 1.0);
float shallowEdge = 1.0 - smoothstep(0.010, 0.070, thickness);
float contactFade = 1.0 - smoothstep(0.030, 0.160, thickness);
// --- Sun specular (Blinn-Phong) ---
// FIX 6: added specular highlight, missing from original
vec3 sunDir = normalize(vec3(0.4, 0.9, 0.3)); // tunable sun direction
vec3 halfVec = normalize(viewDir + sunDir);
float spec = pow(max(dot(normal, halfVec), 0.0), 72.0);
vec3 specColor = vec3(1.0, 0.98, 0.92) * spec * mix(0.06, 0.50, fresnel) * mix(0.18, 1.0, daylight);
// --- Water base color ---
vec3 shallowColor = vec3(0.20, 0.50, 0.78);
vec3 midColor = vec3(0.10, 0.32, 0.60);
vec3 deepColor = vec3(0.04, 0.16, 0.36);
vec3 waterBase = mix(shallowColor, midColor, thicknessCue);
waterBase = mix(waterBase, deepColor, thicknessCue * thicknessCue);
waterBase += vec3(0.05, 0.10, 0.12) * shallowEdge;
waterBase *= mix(vec3(1.0), vertexColor.rgb, 0.45);
waterBase *= mix(0.55 + skyAmbient * 0.35, 1.0, daylight);
vec3 absorption = mix(vec3(0.92, 0.97, 1.0), vec3(0.68, 0.82, 0.94), thicknessCue);
vec3 transmitted = refraction * absorption;
vec3 waterColor = mix(transmitted * 0.40 + waterBase * 0.60, waterBase, fresnel);
waterColor = mix(waterColor, waterBase, contactFade * 0.20);
waterColor *= waterShadow;
waterColor *= mix(0.72 + skyAmbient * 0.28, 1.0, daylight);
float sparkle = pow(clamp(dot(normal, normalize(vec3(0.25, 0.95, 0.18))), 0.0, 1.0), 18.0);
waterColor += vec3(0.05, 0.08, 0.10) * sparkle * nearField * mix(0.10, 1.0, daylight);
// Use SSR only as a grazing-angle enhancement. Overhead views should stay dominated
// by water body color/refraction; otherwise the current screen sample looks like a duplicate world.
float grazing = smoothstep(0.22, 0.82, 1.0 - NdotV);
float reflectionStrength = clamp(fresnel * 1.12 + 0.08, 0.0, 1.0) * grazing * mix(0.88, 1.0, reflectionHit) * mix(0.55, 1.0, mediumField);
vec3 finalColor = mix(waterColor, reflection, reflectionStrength);
finalColor = mix(finalColor, finalColor * waterShadow, 0.55);
finalColor = mix(finalColor, finalColor * (0.78 + skyAmbient * 0.22), nightFactor * 0.65);
// Add specular on top
finalColor += specColor * mix(0.35, 1.0, nearField) * mix(0.82, 1.0, 1.0 - shadow);
float shoreFoam = smoothstep(0.008, 0.030, thickness) * (1.0 - smoothstep(0.030, 0.080, thickness));
finalColor += vec3(0.16, 0.18, 0.18) * shoreFoam * (0.30 + 0.70 * fresnel) * nearField;
finalColor -= waterBase * (contactFade * 0.10);
float alpha = mix(0.62, 0.94, fresnel);
alpha = mix(alpha, 0.86, thicknessCue * 0.65);
alpha = clamp(alpha, 0.58, 0.96);
fragColor = apply_fog(
vec4(finalColor, alpha),
sphericalVertexDistance,
cylindricalVertexDistance,
FogEnvironmentalStart,
FogEnvironmentalEnd,
FogRenderDistanceStart,
FogRenderDistanceEnd,
FogColor
);
}
Download file