GameTech/URP 渲染实战
源码 / features/Cookbook.Ch30.FullscreenDebugFeature.js
features/Cookbook.Ch30.FullscreenDebugFeature.js
// 第 30 章的全屏调试 Feature 的网页版(对应 Ch30/FullscreenDebugFeature.cs):
// 把相机颜色拷贝一份,再用调试材质(像素校验等)画回去。
import { RenderPassEvent, featureMaterial } from '../engine/features.js';

export default class FullscreenDebugFeature {
  constructor(engine, data, scene) {
    this.engine = engine;
    this.scene = scene;
    // C# Settings 的默认值
    this.settings = { material: null, passIndex: 0, renderPassEvent: RenderPassEvent.BeforeRenderingPostProcessing, requirements: 0, ...((data && data.settings) || {}) };
  }

  async init() {
    this.material = featureMaterial(this.scene, this.settings.material);
  }

  addPasses(frame, enqueue) {
    const s = this.settings;
    if (!this.material) return;
    enqueue(s.renderPassEvent, (fr) => {
      // 网页版的后处理输出是一张单独的贴图(frame.postOutput):AfterRenderingPostProcessing 且开了后处理时,读写它
      const afterPost = s.renderPassEvent >= RenderPassEvent.AfterRenderingPostProcessing && fr.postDone;
      const src = afterPost ? fr.postOutput : fr.cameraColorTexture();
      // 临时 RT 与相机目标同尺寸、同格式,但不要 MSAA、不要深度
      const copy = fr.getTemporaryRT('_FullscreenDebugCopy', fr.width, fr.height);
      // 不能边读边写同一张 RT:先拷贝,再以拷贝为 _BlitTexture 画回去
      fr.blit(src, copy);
      if (afterPost) {
        const out = fr.getTemporaryRT('_FullscreenDebugOut', fr.width, fr.height, { color: 'RGBA16F' });
        fr.blit(copy.texture, out, this.material, s.passIndex);
        fr.postOutput = out.texture;
      } else fr.blit(copy.texture, 'camera', this.material, s.passIndex);
      fr.bindCamera();
    }, 'FullscreenDebug');
  }
}