HPP_Graphics_3.5 Early-Z和Z Prepass(Pre-Z)

a). Review Z-test

  • 先回顾下深度测试

ZTest_Workflow

  • 问题: 被遮挡的物体也会进行shading,造成overdraw;

    Overdraw

    • 解决思路: 在shading前提前剔除被遮挡的片元;

b). Early-Z

Early-Z

  • 是在传统管线中的光栅化阶段之后、片元着色器之前加的一步操作。
    • 提前的深度测试叫作Z-Cull
    • 后续的深度测试为了确定正确的遮挡关系,叫作Z-Check
  • Early-Z同样可以搭配使用模板测试

b.1). Early-Z失效情况

  1. 开启Alpha Test或 clip/discard等手动丢弃片元操作
    • 通常Early-Z不仅会进行深度测试,还要进行深度写入
    • 那在这种情况下,如果经过AlphaTest,前面渲染的片元被丢弃了(但写入了深度),那么后续的像素都将无法正常渲染。
  2. 手动修改GPU插值得到的深度
  3. 开启Alpha Blend
  4. 关闭深度测试Depth Test

b.2). Early-Z排序

不透明物体由远往近渲染,early-z将没有任何优化效果

  • 在渲染前,将不透明物体从近往远渲染的话,Early-Z能发挥最大的性能优化(注意此处还是前向渲染的思路)
  • 具体怎么排序?

    • 可以让CPU将物体按照由近到远的顺序排好,再交付给GPU进行渲染
  • 问题:

    • 复杂的场景,CPU性能消耗很大
    • 严格按照由近到远的顺序渲染,将不能同时搭配批处理优化手段。
  • 解决方法:Pre-Z / Z Prepass

c). Pre-Z

  • 用于解决使用early-Z可能造成的Overdraw问题(用Drawcall或Set Pass Call的消耗换取减少Overdraw,因此使用时需要进行权衡)

Method1: 双Pass

使用两个Pass:

  • 第一个Pass(Z-Prepass):仅写入深度;

  • 第二个Pass:关闭深度写入,并将深度测试比较符改为等于;

    D-pass_shader

造成问题:

  1. 在Unity中,无法动态批处理(多Pass的Shader无法进行动态批处理)

  2. 增多DrawCall;

    Z_Pre_Drawcall

因此,我们可以提前分离Prepass,以便其可以进行动态批处理,减少Set pass call

Method2: 提前分离的Prepass

  • 将Z-Prepass分离出一个shader,用这个shader将场景中不透明物体先渲染一遍;
  • 而原先材质只剩下原先的第二个Pass,仍然关闭深度写入,并且将深度比较函数设置为相等。

URP以后并不是所有Pass都会执行,因为它预制了两个Pass所以,优先执行”UniversalForward”在执行”SrpDefaultUnlit”的Pass

……

RendererFeature

Link: https://www.xuanyusong.com/archives/4759


半透明渲染

Pre-Z也是半透明物体渲染的解决方案;

PreZ_Translution

Z-prepass的其他问题

1.Z-prepass的性能消耗是否能被忽视

  • 国外论坛一位名为lipsryme的老哥做了一项实验:

    • img
    • 可以看到,Z-prepass的消耗为2.0ms,而带来的优化只减少了0.3ms(2.7-2.4)
    • 后续讨论中,发现Z-prepass是需要根据项目的实际情况来决定是否采用的。
  • 总结有以下建议

    • 当一个有非常多OverDraw的场景,且不能很好的将不透明物体从前往后进行排序时,可以考虑使用PreZ进行优化
    • 注意,PreZ会增加DrawCall,如果用错了可能是负优化

d). Early-Z Z-Prepass的实例应用

d.1). 面片叠加的头发渲染

  • 对于半透明的面片来说,需要从后往前进行排序渲染才能得到正确的透明度混合结果

    Hair_PreZ00


  • 排序后头发的渲染

    Hair_PreZ01

  • 分为3个pass

    • pass1

      • 处理不透明部分,开启Alpha test透明度测试,仅通过不透明的像素,
      • 关闭背面剔除
      • 开启深度写入
    • pass2

      • 剔除正面,渲染背面
    • pass3
      • 剔除背面,渲染正面
  • 问题:会带来非常多OverDraw的问题
    • 解决方法:Pre-Z

Hair_PreZ02

  • 使用Early-Z剔除
  • 透明度测试开启时Early-Z无法使用的解决方案:使用Z-Prepass
    • 使用一个简单的shader进行Alpha Test生成Z-Buffer

改善后的渲染方案:

Hair_PreZ03

  • 不透明物体
    1. Pass1 - PreZ
      • 开启透明度测试
      • 关闭背面剔除
      • 开启深度写入,深度测试设置为Less
      • 关闭颜色缓冲区写入
      • 用于一个简单的片元着色器来返回透明度值
    2. Pass2:
      • 关闭背面剔除
      • 关闭深度写入,深度测试设置为Equal
  • 半透明物体
    1. Pass3:
      • 剔除正面
      • 关闭深度写入,对背面进行深度测试,设置为Less
    2. Pass4:
      • 剔除背面
      • 关闭深度写入,对正面进行深度测试,设置为Less

https://www.cnblogs.com/ghl_carmack/p/10166291.html

Homework

Homework