第 20 课:Screen Space Reflections
本课需 多 pass / 后处理,暂以代码复盘呈现。
实现
uniform vec2 iResolution;
uniform mat4 projectionMatrix;
uniform mat4 inverseProjectionMatrix;
uniform mat4 inverseViewMatrix;
uniform sampler2D iRTBuffer0;
uniform sampler2D iRTBuffer1;
uniform sampler2D iDepthBuffer;
out vec4 FragColor;
vec3 getViewPosition(vec2 uv, float depth) {
vec4 position = vec4(1.0);
position.x = uv.x * 2.0 - 1.0;
position.y = uv.y * 2.0 - 1.0;
position.z = depth * 2.0 - 1.0;
position = inverseProjectionMatrix * position;
position /= position.w;
return position.xyz;
}
vec3 getUV(vec3 viewPos) {
vec4 pos = projectionMatrix * vec4(viewPos, 1.0f);
return pos.xyz / pos.w * 0.5 + 0.5;
}
void main() {
vec2 uv = gl_FragCoord.xy / iResolution.xy;
float depth = texture(iDepthBuffer, uv).r;
vec3 pos = getViewPosition(uv, depth);
vec3 normal = normalize(texture(iRTBuffer1, uv).xyz);
vec3 viewDir = normalize(pos);
vec3 reflectDir = normalize(reflect(viewDir, normal));
vec4 reflection = vec4(0.0);
float L = 0.0;
pos += normal * 0.1;
for(int i = 0; i < 100; i++) {
vec3 nextPos = pos + reflectDir * (0.01 * float(i));
vec3 nextUV = getUV(nextPos);
float sampleDepth = texture(iDepthBuffer, nextUV.xy).r;
//Terminate testing points that are out of the screen space
if (nextUV.x < 0.0 || nextUV.x > 1.0 || nextUV.y < 0.0 || nextUV.y > 1.0) {
reflection = texture(iRTBuffer0, uv);
break;
}
//If the testing point is below the surface and not too much below
if (abs(sampleDepth - nextUV.z) < 0.001) {
//Terminate intersections that are out of range
if (nextUV.z < 0.0 || nextUV.z > 1.0) {
reflection = texture(iRTBuffer0, uv);
break;
}
//Simply return scene color of the intersection point.
reflection = texture(iRTBuffer0, nextUV.xy);
L = 1.0 - distance(pos, nextPos);
L = clamp(L, 0.0, 1.0);
break;
}
}
float fresnel = 1.0 - max(0.0, normal.z);
float reflectStrength = step(0.1, texture(iRTBuffer1, uv).w);
FragColor = mix(texture(iRTBuffer0, uv), reflection, fresnel * L * reflectStrength);
}