2025-01-22 16:18:30 +01:00
|
|
|
#version 450
|
|
|
|
|
|
|
|
|
|
#include "compiled.inc"
|
|
|
|
|
#include "std/math.glsl"
|
|
|
|
|
#include "std/gbuffer.glsl"
|
|
|
|
|
|
|
|
|
|
uniform sampler2D tex;
|
|
|
|
|
uniform sampler2D gbufferD;
|
|
|
|
|
uniform sampler2D gbuffer0; // Normal, roughness
|
|
|
|
|
uniform sampler2D gbuffer1; // basecol, spec
|
|
|
|
|
uniform mat4 P;
|
|
|
|
|
uniform mat3 V3;
|
|
|
|
|
uniform vec2 cameraProj;
|
2026-08-07 02:04:01 -07:00
|
|
|
uniform vec2 screenSize;
|
2025-01-22 16:18:30 +01:00
|
|
|
|
|
|
|
|
#ifdef _CPostprocess
|
|
|
|
|
uniform vec3 PPComp9;
|
|
|
|
|
uniform vec3 PPComp10;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
in vec3 viewRay;
|
|
|
|
|
in vec2 texCoord;
|
|
|
|
|
out vec4 fragColor;
|
|
|
|
|
|
|
|
|
|
vec3 hitCoord;
|
|
|
|
|
float depth;
|
|
|
|
|
|
2026-08-07 02:04:01 -07:00
|
|
|
const int numBinarySearchSteps = 8;
|
|
|
|
|
const int maxSteps = 50;
|
2025-01-22 16:18:30 +01:00
|
|
|
|
|
|
|
|
vec2 getProjectedCoord(const vec3 hit) {
|
|
|
|
|
vec4 projectedCoord = P * vec4(hit, 1.0);
|
|
|
|
|
projectedCoord.xy /= projectedCoord.w;
|
|
|
|
|
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
|
|
|
|
|
#ifdef _InvY
|
|
|
|
|
projectedCoord.y = 1.0 - projectedCoord.y;
|
|
|
|
|
#endif
|
|
|
|
|
return projectedCoord.xy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float getDeltaDepth(const vec3 hit) {
|
2026-08-07 02:04:01 -07:00
|
|
|
vec2 tc = getProjectedCoord(hit);
|
|
|
|
|
if (tc.x < 0.0 || tc.x > 1.0 || tc.y < 0.0 || tc.y > 1.0)
|
|
|
|
|
return -1.0;
|
|
|
|
|
depth = textureLod(gbufferD, tc, 0.0).r * 2.0 - 1.0;
|
2025-01-22 16:18:30 +01:00
|
|
|
vec3 viewPos = getPosView(viewRay, depth, cameraProj);
|
|
|
|
|
return viewPos.z - hit.z;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-07 02:04:01 -07:00
|
|
|
vec4 binarySearch(vec3 dir, float stepSize) {
|
2025-01-22 16:18:30 +01:00
|
|
|
float ddepth;
|
|
|
|
|
for (int i = 0; i < numBinarySearchSteps; i++) {
|
2026-08-07 02:04:01 -07:00
|
|
|
stepSize *= 0.5;
|
|
|
|
|
hitCoord -= dir * stepSize;
|
2025-01-22 16:18:30 +01:00
|
|
|
ddepth = getDeltaDepth(hitCoord);
|
2026-08-07 02:04:01 -07:00
|
|
|
if (ddepth < 0.0) hitCoord += dir * stepSize;
|
2025-01-22 16:18:30 +01:00
|
|
|
}
|
|
|
|
|
#ifdef _CPostprocess
|
2026-08-07 02:04:01 -07:00
|
|
|
float maxDist = PPComp9.z;
|
2025-01-22 16:18:30 +01:00
|
|
|
#else
|
2026-08-07 02:04:01 -07:00
|
|
|
float maxDist = ssrSearchDist;
|
2025-01-22 16:18:30 +01:00
|
|
|
#endif
|
2026-08-07 02:04:01 -07:00
|
|
|
if (abs(ddepth) > maxDist * 0.005) return vec4(0.0);
|
|
|
|
|
vec2 hitTC = getProjectedCoord(hitCoord);
|
|
|
|
|
if (hitTC.x < 0.0 || hitTC.x > 1.0 || hitTC.y < 0.0 || hitTC.y > 1.0)
|
|
|
|
|
return vec4(0.0);
|
|
|
|
|
return vec4(hitTC, 0.0, 1.0);
|
2025-01-22 16:18:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vec4 rayCast(vec3 dir) {
|
|
|
|
|
#ifdef _CPostprocess
|
2026-08-07 02:04:01 -07:00
|
|
|
float baseStep = PPComp9.x;
|
|
|
|
|
float maxDist = PPComp9.z;
|
2025-01-22 16:18:30 +01:00
|
|
|
#else
|
2026-08-07 02:04:01 -07:00
|
|
|
float baseStep = ssrRayStep;
|
|
|
|
|
float maxDist = ssrSearchDist;
|
2025-01-22 16:18:30 +01:00
|
|
|
#endif
|
2026-08-07 02:04:01 -07:00
|
|
|
float stepSize = baseStep * max(1.0, -viewRay.z * 0.1);
|
|
|
|
|
vec3 startPos = hitCoord;
|
2025-01-22 16:18:30 +01:00
|
|
|
for (int i = 0; i < maxSteps; i++) {
|
2026-08-07 02:04:01 -07:00
|
|
|
hitCoord += dir * stepSize;
|
|
|
|
|
float dist = length(hitCoord - startPos);
|
|
|
|
|
if (dist > maxDist) break;
|
|
|
|
|
float ddepth = getDeltaDepth(hitCoord);
|
|
|
|
|
if (ddepth > 0.0) return binarySearch(dir, stepSize);
|
|
|
|
|
stepSize *= 1.03;
|
2025-01-22 16:18:30 +01:00
|
|
|
}
|
|
|
|
|
return vec4(0.0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
|
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
|
2026-08-07 02:04:01 -07:00
|
|
|
float roughness = g0.b;
|
2025-01-22 16:18:30 +01:00
|
|
|
if (roughness == 1.0) { fragColor.rgb = vec3(0.0); return; }
|
|
|
|
|
|
|
|
|
|
float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a);
|
|
|
|
|
if (spec == 0.0) { fragColor.rgb = vec3(0.0); return; }
|
|
|
|
|
|
|
|
|
|
float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
|
|
|
|
|
if (d == 1.0) { fragColor.rgb = vec3(0.0); return; }
|
|
|
|
|
|
|
|
|
|
vec2 enc = g0.rg;
|
|
|
|
|
vec3 n;
|
|
|
|
|
n.z = 1.0 - abs(enc.x) - abs(enc.y);
|
|
|
|
|
n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
|
|
|
|
|
n = normalize(n);
|
|
|
|
|
|
|
|
|
|
vec3 viewNormal = V3 * n;
|
|
|
|
|
vec3 viewPos = getPosView(viewRay, d, cameraProj);
|
2026-08-07 02:04:01 -07:00
|
|
|
float NdotV = clamp(dot(viewNormal, -normalize(viewPos)), 0.0, 1.0);
|
|
|
|
|
vec3 reflected = reflect(normalize(viewPos), viewNormal);
|
2025-01-22 16:18:30 +01:00
|
|
|
hitCoord = viewPos;
|
|
|
|
|
|
2026-08-07 02:04:01 -07:00
|
|
|
vec3 dir = reflected;
|
2025-01-22 16:18:30 +01:00
|
|
|
|
|
|
|
|
vec4 coords = rayCast(dir);
|
|
|
|
|
|
2026-08-07 02:04:01 -07:00
|
|
|
if (coords.w <= 0.0) {
|
|
|
|
|
fragColor.rgb = vec3(0.0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy);
|
|
|
|
|
float screenEdgeFactor = smoothstep(0.5, 0.15, deltaCoords.x)
|
|
|
|
|
* smoothstep(0.5, 0.15, deltaCoords.y);
|
|
|
|
|
screenEdgeFactor = max(screenEdgeFactor, 0.15);
|
|
|
|
|
|
|
|
|
|
float hitDepth = textureLod(gbufferD, coords.xy, 0.0).r * 2.0 - 1.0;
|
|
|
|
|
vec3 hitViewPos = getPosView(viewRay, hitDepth, cameraProj);
|
|
|
|
|
vec3 hitDir = normalize(hitViewPos - viewPos);
|
|
|
|
|
float hitNdotV = clamp(dot(viewNormal, -hitDir), 0.0, 1.0);
|
|
|
|
|
float hitBackFace = smoothstep(-0.15, 0.3, hitNdotV);
|
2025-01-22 16:18:30 +01:00
|
|
|
|
|
|
|
|
float reflectivity = 1.0 - roughness;
|
|
|
|
|
#ifdef _CPostprocess
|
2026-08-07 02:04:01 -07:00
|
|
|
float falloffExp = PPComp10.x;
|
|
|
|
|
float maxDist = PPComp9.z;
|
2025-01-22 16:18:30 +01:00
|
|
|
#else
|
2026-08-07 02:04:01 -07:00
|
|
|
float falloffExp = ssrFalloffExp;
|
|
|
|
|
float maxDist = ssrSearchDist;
|
2025-01-22 16:18:30 +01:00
|
|
|
#endif
|
|
|
|
|
|
2026-08-07 02:04:01 -07:00
|
|
|
float distAttenuation = 1.0 - clamp(length(viewPos - hitCoord) / maxDist, 0.0, 1.0);
|
|
|
|
|
distAttenuation = pow(distAttenuation, 1.5);
|
|
|
|
|
|
|
|
|
|
float fresnel = pow(1.0 - NdotV, 5.0);
|
|
|
|
|
fresnel = mix(0.04, 1.0, fresnel);
|
|
|
|
|
|
|
|
|
|
float intensity = pow(reflectivity, falloffExp) * screenEdgeFactor
|
|
|
|
|
* smoothstep(0.0, 0.1, -reflected.z)
|
|
|
|
|
* distAttenuation
|
|
|
|
|
* hitBackFace
|
|
|
|
|
* coords.w;
|
|
|
|
|
|
2025-01-22 16:18:30 +01:00
|
|
|
intensity = clamp(intensity, 0.0, 1.0);
|
2026-08-07 02:04:01 -07:00
|
|
|
|
2025-01-22 16:18:30 +01:00
|
|
|
vec3 reflCol = textureLod(tex, coords.xy, 0.0).rgb;
|
|
|
|
|
reflCol = clamp(reflCol, 0.0, 1.0);
|
2026-08-07 02:04:01 -07:00
|
|
|
fragColor.rgb = reflCol * intensity * mix(0.5, 1.0, fresnel);
|
2025-01-22 16:18:30 +01:00
|
|
|
}
|