跳到主要内容
ssr-failure-lab · 代码
查看代码目录
屏幕空间与实时效果 · source map

SSR 为什么会在屏幕边缘“凭空消失”?:代码定位

这里显示课程实际引用的代码片段。先看每段在说人话,再回到实验验证它对画面的影响。

← 回到对应自由实验状态
SSR 射线步进

逐步沿反射方向查深度,命中条件在这里发生。

src/lib/lab/screen-space/shaders.ts · section ssr

当前起点查看这段精确实现
// SECTION:ssr - march a reflected screen ray until the depth buffer supplies a hit
vec4 traceSsr(vec2 uv, float centerDepth, vec3 normal) {
  if (!uSsrEnabled) return vec4(0.0);
  vec3 viewPosition = reconstructViewPosition(uv, centerDepth);
  vec3 viewDirection = normalize(-viewPosition);
  vec3 reflected = normalize(reflect(viewDirection, normal));
  vec2 rayDirection = normalize(reflected.xy + vec2(0.0001));
  float rayDepth = centerDepth;
  for (int index = 1; index <= 64; index += 1) {
    if (index > uSsrMaxSteps) break;
    float distance = float(index) * uSsrStepSize;
    if (distance > uSsrMaxDistance) break;
    vec2 sampleUv = uv + rayDirection * distance;
    if (sampleUv.x < 0.0 || sampleUv.x > 1.0 || sampleUv.y < 0.0 || sampleUv.y > 1.0) return vec4(0.0);
    float sampleDepth = readDeviceDepth(sampleUv);
    rayDepth += reflected.z * uSsrStepSize * 0.025;
    if (sampleDepth <= rayDepth + uSsrThickness) {
      float confidence = screenEdgeFade(sampleUv);
      return vec4(readAlbedo(sampleUv).rgb, confidence);
    }
  }
  return vec4(0.0);
}
屏幕边界与可信度

屏幕外没有几何证据,所以要把 miss 和 edge fade 说清楚。

src/lib/lab/screen-space/shaders.ts · section bounds

按需展开查看这段精确实现
// SECTION:bounds - screen-space effects expose their own validity and edge fade
vec3 boundsDebug(vec2 uv, vec4 ssr) {
  float edge = min(min(uv.x, 1.0 - uv.x), min(uv.y, 1.0 - uv.y));
  return mix(vec3(0.95, 0.2, 0.18), vec3(0.2, 0.8, 0.55), clamp(edge * 12.0, 0.0, 1.0)) * (0.25 + 0.75 * ssr.a);
}
深度 debug 输出

把 SSR、深度和位置直接输出,建立画面证据到 shader 的联系。

src/lib/lab/screen-space/shaders.ts · section debug

按需展开查看这段精确实现
// SECTION:debug - switch from the final composite to evidence views for teaching
void main() {
  vec4 albedo = readAlbedo(vUv);
  float deviceDepth = readDeviceDepth(vUv);
  float linear = linearDepth(deviceDepth);
  vec3 normal = readNormal(vUv);
  vec3 viewPosition = readPosition(vUv, deviceDepth);
  vec3 worldPosition = reconstructWorldPosition(vUv, deviceDepth);
  float ao = computeSsao(vUv, deviceDepth);
  vec4 ssr = traceSsr(vUv, deviceDepth, normal);

  vec3 color = albedo.rgb;
  color *= 1.0 - ao * 0.72;
  color = mix(color, ssr.rgb, ssr.a * 0.48);

  if (uDebugMode == 1) color = albedo.rgb;
  if (uDebugMode == 2) color = normal * 0.5 + 0.5;
  if (uDebugMode == 3) color = normalize(worldPosition) * 0.5 + 0.5;
  if (uDebugMode == 4) color = vec3(deviceDepth);
  if (uDebugMode == 5) color = vec3(clamp(linear / uFarPlane, 0.0, 1.0));
  if (uDebugMode == 6) color = vec3(1.0 - ao, 0.24 + ao * 0.65, 0.08);
  if (uDebugMode == 7) color = mix(vec3(0.08, 0.12, 0.18), ssr.rgb, ssr.a);
  if (uDebugMode == 8) color = boundsDebug(vUv, ssr);

  gl_FragColor = vec4(color, 1.0);
  #include <tonemapping_fragment>
  #include <colorspace_fragment>
}