跳到主要内容
forward-deferred · 代码
查看代码目录
Shader 与渲染管线 · source map

Forward 和 Deferred 是资源选择题:代码定位

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

← 回到对应自由实验状态
Forward / Deferred 分支

同一批灯光如何在两条路径上分配工作。

src/lib/lab/rendering-effects/effects-source.ts · section forward-deferred

当前起点查看这段精确实现
// SECTION:forward-deferred
// Forward: light work follows each visible material.
// Deferred: write G-buffer, then light screen-space pixels.
float lightingCost = renderPath == FORWARD
  ? visiblePixels * lightCount
  : gbufferBandwidth + visiblePixels;
G-buffer / 带宽证据

Deferred 先写下来的 albedo、normal、depth,决定了后续能做什么。

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

按需展开查看这段精确实现
// SECTION:gbuffer - the color, normal and depth attachments are sampled independently
vec4 readAlbedo(vec2 uv) { return texture2D(uColorTexture, uv); }
float readDeviceDepth(vec2 uv) { return texture2D(uDepthTexture, uv).r; }
vec3 readNormal(vec2 uv) { return normalize(texture2D(uNormalTexture, uv).xyz * 2.0 - 1.0); }

float linearDepth(float depth) {
  if (uProjection == 1) return mix(uNearPlane, uFarPlane, depth);
  return (uNearPlane * uFarPlane) / max(uFarPlane - depth * (uFarPlane - uNearPlane), 0.0001);
}

vec3 reconstructViewPosition(vec2 uv, float depth) {
  vec4 clip = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
  vec4 view = uInverseProjection * clip;
  return view.xyz / max(abs(view.w), 0.0001);
}

vec3 reconstructWorldPosition(vec2 uv, float depth) {
  vec4 world = uInverseView * vec4(reconstructViewPosition(uv, depth), 1.0);
  return world.xyz / max(abs(world.w), 0.0001);
}

vec3 readPosition(vec2 uv, float depth) {
  return uPositionSource == 1 ? texture2D(uPositionTexture, uv).xyz : reconstructViewPosition(uv, depth);
}
屏幕空间 debug

把路径结果直接切成证据视图,而不是只盯最终颜色。

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>
}