128 lines
No EOL
3.8 KiB
GLSL
128 lines
No EOL
3.8 KiB
GLSL
#version 450
|
|
|
|
layout(location = 0) in vec2 fragTexCoord;
|
|
layout(location = 0) out vec4 outColor;
|
|
|
|
layout(set = 0, binding = 0) uniform sampler2D albedoSampler;
|
|
layout(set = 0, binding = 1) uniform sampler2D worldPosSampler;
|
|
layout(set = 0, binding = 2) uniform sampler2D normalSampler;
|
|
layout(set = 0, binding = 3) uniform sampler2D pbrSampler;
|
|
|
|
layout(set = 1, binding = 0) uniform CameraProperties {
|
|
mat4 projection;
|
|
mat4 invProjection;
|
|
mat4 view;
|
|
mat4 invView;
|
|
float ssrStepSize;
|
|
float ssrMaxDistance;
|
|
int maxSteps;
|
|
int padding;
|
|
vec4 cameraWorldPos;
|
|
} ubo;
|
|
|
|
const float THICKNESS = 0.35;
|
|
const float MIN_REFLECTION = 0.01;
|
|
|
|
float edgeFade(vec2 uv) {
|
|
vec2 fade = smoothstep(vec2(0.0), vec2(0.08), uv) *
|
|
smoothstep(vec2(0.0), vec2(0.08), vec2(1.0) - uv);
|
|
return fade.x * fade.y;
|
|
}
|
|
|
|
void main() {
|
|
vec4 sceneColor = texture(albedoSampler, fragTexCoord);
|
|
vec4 posSample = texture(worldPosSampler, fragTexCoord);
|
|
vec4 normalSample = texture(normalSampler, fragTexCoord);
|
|
vec4 pbrSample = texture(pbrSampler, fragTexCoord);
|
|
|
|
if (posSample.a == 0.0 || length(posSample.xyz) == 0.0 || length(normalSample.xyz) < 0.001) {
|
|
outColor = sceneColor;
|
|
return;
|
|
}
|
|
|
|
vec3 worldPos = posSample.xyz;
|
|
vec3 worldNormal = normalize(normalSample.xyz);
|
|
|
|
float roughness = clamp(pbrSample.g, 0.0, 1.0);
|
|
float metallic = clamp(pbrSample.b, 0.0, 1.0);
|
|
float reflectiveness = clamp(pbrSample.a, 0.0, 1.0);
|
|
float refractiveness = clamp(normalSample.a, 0.0, 2.0);
|
|
|
|
vec3 viewDirToCamera = normalize(ubo.cameraWorldPos.xyz - worldPos);
|
|
float NoV = clamp(dot(worldNormal, viewDirToCamera), 0.0, 1.0);
|
|
float fresnel = pow(1.0 - NoV, 5.0);
|
|
|
|
float materialReflection = reflectiveness + refractiveness - 1;
|
|
materialReflection *= mix(0.75, 1.0, metallic);
|
|
materialReflection *= smoothstep(0.7, 0.05, roughness);
|
|
materialReflection *= mix(0.45, 1.0, fresnel);
|
|
|
|
if (materialReflection <= MIN_REFLECTION) {
|
|
outColor = sceneColor;
|
|
return;
|
|
}
|
|
|
|
vec3 viewDir = normalize(worldPos - ubo.cameraWorldPos.xyz);
|
|
vec3 reflectDir = normalize(reflect(viewDir, worldNormal));
|
|
|
|
if (dot(reflectDir, worldNormal) <= 0.0) {
|
|
outColor = sceneColor;
|
|
return;
|
|
}
|
|
|
|
int steps = clamp(ubo.maxSteps, 1, 128);
|
|
float stepSize = max(ubo.ssrStepSize, 0.01);
|
|
float maxDistance = max(ubo.ssrMaxDistance, stepSize);
|
|
|
|
vec3 rayPos = worldPos;
|
|
vec2 hitUV = vec2(0.0);
|
|
bool hitFound = false;
|
|
|
|
for (int i = 0; i < steps; i++) {
|
|
rayPos += reflectDir * stepSize;
|
|
|
|
if (distance(rayPos, worldPos) > maxDistance) {
|
|
break;
|
|
}
|
|
|
|
vec4 clip = ubo.projection * ubo.view * vec4(rayPos, 1.0);
|
|
if (clip.w <= 0.0) {
|
|
break;
|
|
}
|
|
|
|
vec2 uv = clip.xy / clip.w;
|
|
uv = uv * 0.5 + 0.5;
|
|
uv.y = 1.0 - uv.y;
|
|
|
|
if (uv.x <= 0.0 || uv.x >= 1.0 || uv.y <= 0.0 || uv.y >= 1.0) {
|
|
break;
|
|
}
|
|
|
|
vec4 surfaceWorld = texture(worldPosSampler, uv);
|
|
if (surfaceWorld.a == 0.0 || length(surfaceWorld.xyz) == 0.0) {
|
|
continue;
|
|
}
|
|
|
|
float rayViewZ = abs((ubo.view * vec4(rayPos, 1.0)).z);
|
|
float surfaceViewZ = abs((ubo.view * vec4(surfaceWorld.xyz, 1.0)).z);
|
|
|
|
float depthDelta = rayViewZ - surfaceViewZ;
|
|
if (depthDelta >= 0.0 && depthDelta < THICKNESS) {
|
|
hitUV = uv;
|
|
hitFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!hitFound) {
|
|
outColor = sceneColor;
|
|
return;
|
|
}
|
|
|
|
vec3 reflectedColor = texture(albedoSampler, hitUV).rgb;
|
|
|
|
float fade = edgeFade(hitUV);
|
|
float weight = clamp(materialReflection * fade, 0.0, 0.85);
|
|
|
|
outColor = vec4(mix(sceneColor.rgb, reflectedColor, weight), sceneColor.a);
|
|
} |