GameTech/URP 渲染实战
源码 / features/Cookbook.Ch28.ScreenEffectFeature.js
features/Cookbook.Ch28.ScreenEffectFeature.js
// 第 28 章通用的“全屏效果” Renderer Feature(对应 Ch28/ScreenEffectFeature.cs)。
// 把相机颜色拷贝到一张临时 RT,再用指定材质的指定 Pass 画回相机颜色。
// 本章的世界坐标重建、扫描线、雾、SSR 都靠它跑,算法全部写在各自的 Shader 里。
import { featureMaterial, RenderPassEvent } from '../engine/features.js';
import { PassInput, renderDepthNormals, ensureDepth } from './Cookbook.Ch28.ScreenSpaceUtil.js';

export default class ScreenEffectFeature {
  constructor(engine, data, scene) {
    this.engine = engine;
    this.scene = scene;
    this.settings = { material: null, passIndex: 0, renderPassEvent: RenderPassEvent.BeforeRenderingPostProcessing, requirements: PassInput.Depth, ...((data && data.settings) || {}) };
  }

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

  addPasses(frame, enqueue) {
    const s = this.settings, m = this.material;
    if (!m) return;
    // ConfigureInput(Normal):DepthNormals 预渲染在不透明物体之前
    if (s.requirements & PassInput.Normal) enqueue(RenderPassEvent.BeforeRenderingOpaques, (fr) => renderDepthNormals(fr), 'DepthNormalPrepass');
    enqueue(s.renderPassEvent, (fr) => {
      if (!(s.requirements & PassInput.Normal) && (s.requirements & PassInput.Depth)) ensureDepth(fr);
      // 不能边读边写同一张 RT:先拷贝,再以拷贝为 _BlitTexture 画回去
      const copy = fr.getTemporaryRT('_ScreenEffectCopy', fr.width, fr.height);
      fr.blit(fr.cameraColorTexture(), copy);
      fr.blit(copy.texture, 'camera', m, s.passIndex);
      fr.bindCamera();
    }, 'ScreenEffect');
  }
}