跳到主要内容
← Advanced Rendering

Advanced Rendering

Screen Space Reflections

shader-learning 自学第 20 课:Screen Space Reflections

代码复盘 GLSL

第 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);
}