Files
Prism/Editor/assets/shaders/SSR.glsl

179 lines
4.7 KiB
GLSL

#type vertex
#version 430
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec2 a_TexCoord;
out vec2 v_TexCoord;
void main()
{
vec4 position = vec4(a_Position.xy, 0.0, 1.0);
v_TexCoord = a_TexCoord;
gl_Position = position;
}
#type fragment
#version 430
layout(location = 0) out vec4 o_Color;
in vec2 v_TexCoord;
uniform sampler2D u_ColorTexture;
uniform sampler2D u_DepthTexture;
uniform sampler2D u_MaterialInfoTexture;
uniform mat4 u_Projection;
uniform mat4 u_View;
uniform mat4 u_InvViewProjection;
uniform vec3 u_CameraPosition;
uniform vec2 u_ScreenSize;
uniform float u_CameraNear;
uniform float u_CameraFar;
uniform int u_Steps = 32;
uniform float u_Thickness = 0.5;
uniform float u_MaxDistance = 30.0;
uniform float u_StepSize = 0.5;
uniform float u_RayOffset = 0.1;
uniform float u_Intensity = 1.0;
float saturate(float x)
{
return clamp(x, 0.0, 1.0);
}
float LinearizeDepth(float depth)
{
float z = depth * 2.0 - 1.0;
return (2.0 * u_CameraNear * u_CameraFar) / (u_CameraFar + u_CameraNear - z * (u_CameraFar - u_CameraNear));
}
vec3 ComputeWorldSpacePosition(vec2 uv, float depth)
{
vec4 clipPos = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
vec4 worldPos = u_InvViewProjection * clipPos;
return worldPos.xyz / worldPos.w;
}
vec3 ReconstructNormalFromDepth(vec2 tc, float depth)
{
vec2 texelSize = 1.0 / u_ScreenSize;
vec2 tcL = tc - vec2(texelSize.x, 0.0);
vec2 tcR = tc + vec2(texelSize.x, 0.0);
vec2 tcB = tc - vec2(0.0, texelSize.y);
vec2 tcT = tc + vec2(0.0, texelSize.y);
float depthL = texture(u_DepthTexture, tcL).r;
float depthR = texture(u_DepthTexture, tcR).r;
float depthB = texture(u_DepthTexture, tcB).r;
float depthT = texture(u_DepthTexture, tcT).r;
vec3 pC = ComputeWorldSpacePosition(tc, depth);
vec3 pR = ComputeWorldSpacePosition(tcR, depthR);
vec3 pT = ComputeWorldSpacePosition(tcT, depthT);
vec3 dx = pR - pC;
vec3 dy = pT - pC;
return normalize(cross(dx, dy));
}
vec3 ComputeNDCWithZ(vec3 worldPos)
{
vec4 clipPos = u_Projection * u_View * vec4(worldPos, 1.0);
vec3 ndc = clipPos.xyz / clipPos.w;
ndc.xy = ndc.xy * 0.5 + 0.5;
return ndc;
}
void main()
{
float depth = texture(u_DepthTexture, v_TexCoord).r;
if (depth >= 1.0)
{
o_Color = vec4(0.0);
return;
}
vec4 matInfo = texture(u_MaterialInfoTexture, v_TexCoord);
float metalness = matInfo.r;
float roughness = matInfo.g;
if (roughness > 0.9)
{
o_Color = vec4(0.0);
return;
}
vec3 positionWS = ComputeWorldSpacePosition(v_TexCoord, depth);
vec3 viewWS = normalize(u_CameraPosition - positionWS);
vec3 normalWS = ReconstructNormalFromDepth(v_TexCoord, depth);
vec3 reflectionWS = normalize(reflect(-viewWS, normalWS));
if (dot(reflectionWS, normalWS) < 0.0)
{
o_Color = vec4(0.0);
return;
}
vec3 rayWS = positionWS + normalWS * u_RayOffset;
for (int i = 0; i < u_Steps; i++)
{
rayWS += reflectionWS * u_StepSize;
vec3 rayNDC = ComputeNDCWithZ(rayWS);
float rayDepth = rayNDC.z;
vec2 raySS = rayNDC.xy * u_ScreenSize;
if (rayNDC.x < 0.0 || rayNDC.x > 1.0 || rayNDC.y < 0.0 || rayNDC.y > 1.0)
break;
float sceneDepth = texture(u_DepthTexture, rayNDC.xy).r;
float sceneDepthLinear = LinearizeDepth(sceneDepth);
float rayDepthLinear = LinearizeDepth(rayDepth * 0.5 + 0.5);
float delta = rayDepthLinear - sceneDepthLinear;
if (delta >= 0.0 && delta <= u_Thickness)
{
vec3 hitNormalWS = ReconstructNormalFromDepth(rayNDC.xy, sceneDepth);
if (dot(hitNormalWS, reflectionWS) > 0.0)
break;
float ssrStrength = saturate(1.0 - roughness * roughness);
float dist = distance(positionWS, rayWS);
float fadeFactor = 1.0 - smoothstep(u_MaxDistance * 0.3, u_MaxDistance, dist);
float edgeFade = 1.0;
edgeFade *= smoothstep(0.0, 0.1, rayNDC.x);
edgeFade *= smoothstep(0.0, 0.1, rayNDC.y);
edgeFade *= smoothstep(0.0, 0.1, 1.0 - rayNDC.x);
edgeFade *= smoothstep(0.0, 0.1, 1.0 - rayNDC.y);
float NdotV = max(dot(normalWS, viewWS), 0.0);
vec3 F0 = mix(vec3(0.04), vec3(1.0), metalness);
vec3 Fresnel = F0 + (1.0 - F0) * pow(1.0 - NdotV, 5.0);
ssrStrength *= fadeFactor * edgeFade * u_Intensity;
vec4 color = texture(u_ColorTexture, rayNDC.xy);
color.rgb *= ssrStrength * Fresnel;
color.a = ssrStrength * dot(Fresnel, vec3(0.333));
o_Color = color;
return;
}
}
o_Color = vec4(0.0);
}