GameTech/URP 渲染实战
源码 / features/Cookbook.Ch29.OverdrawFeature.js
features/Cookbook.Ch29.OverdrawFeature.js
// 案例 29.5:Overdraw 可视化 Renderer Feature 的网页版(对应 Ch29/OverdrawFeature.cs)。
// 用 overrideMaterial 把可见物体全部重画一遍到一张 R16 浮点 RT(每层 +1),再用热度图画回相机颜色。
import { RenderPassEvent, featureMaterial, layerMask } from '../engine/features.js';

// 和 URP 自己画不透明/透明物体时用的 LightMode 列表一致
const TAGS = ['UniversalForward', 'UniversalForwardOnly', 'SRPDefaultUnlit', 'LightweightForward'];

export default class OverdrawFeature {
  constructor(engine, data, scene) {
    this.engine = engine;
    this.scene = scene;
    const s = (data && data.settings) || {};
    this.settings = { opaque: true, transparent: true, layerMask: -1, ...s };
  }

  async init() {
    const s = this.settings;
    this.countMaterial = featureMaterial(this.scene, s.countMaterial);       // Cookbook/Ch29/OverdrawCount
    this.heatmapMaterial = featureMaterial(this.scene, s.heatmapMaterial);   // Cookbook/Ch29/OverdrawHeatmap
  }

  addPasses(frame, enqueue) {
    const s = this.settings;
    if (!this.countMaterial || !this.heatmapMaterial) return;
    enqueue(RenderPassEvent.AfterRenderingTransparents, (fr) => {
      const gl = fr.gl, E = this.engine;
      // OnCameraSetup:和相机同尺寸、不要 MSAA 和深度;计数可能超过 1,要浮点格式;点采样
      const count = fr.getTemporaryRT('_OverdrawCount', fr.width, fr.height, { color: 'R16F', filter: 'Point' });
      E.bindTarget(count);
      gl.colorMask(true, true, true, true);
      gl.clearColor(0, 0, 0, 0);
      gl.clear(gl.COLOR_BUFFER_BIT);   // ConfigureClear(ClearFlag.Color, Color.black)
      const mask = layerMask(s.layerMask);
      // Execute:所有物体都用计数材质画(overrideMaterial)
      if (s.opaque) fr.drawRenderers({ queue: 'opaque', lightModes: TAGS, layerMask: mask, overrideMaterial: this.countMaterial, overridePass: 0 });
      if (s.transparent) fr.drawRenderers({ queue: 'transparent', lightModes: TAGS, layerMask: mask, overrideMaterial: this.countMaterial, overridePass: 0, sort: 'backToFront' });
      // Blitter.BlitCameraTexture(cmd, m_Count, m_CameraColor, heatmapMaterial, 0)
      fr.blit(count.texture, 'camera', this.heatmapMaterial, 0);
      fr.bindCamera();
    }, 'OverdrawView');
  }
}