技美知识学习3500:Early-z和Z-prepass

学习教程来自:【技术美术百人计划】图形 3.5 Early-z和Z-prepass

Early-z和Z-prepass

1.深度测试

Depth Test,用来解决物体可见遮挡性

顶点着色器->曲面细分->几何着色器->光栅化->片元着色器->透明度测试->模板测试->深度测试->混合

渲染流程详见:
技美知识学习1100:渲染管线

没有通过测试的片元会被丢弃,导致这些片元的计算量被浪费

2.提前深度测试

Early-Z,用来解决过多不必要的片元计算问题(1中的缺陷)
顶点着色器->曲面细分->几何着色器->光栅化->提前深度测试->片元着色器->透明度测试->模板测试->深度测试->混合
没有通过Early-Z的片元会被丢弃,不进入片元着色器进行计算
在提前阶段的位置也可以添加模板测试

2.1.Early-Z失效的情况

  1. 开启Alpha Test或clip/discard等手动丢弃片元操作(但是深度信息还在)
  2. 手动修改GPU插值得到的深度(原因同上)
  3. 开启Alpha Blend(深度写入关闭ZWrite Off)
  4. 关闭深度测试Depth Test

2.2.Early-Z使用条件

当渲染顺序为如图所示时,每次提前深度测试时都抛弃了上一次计算得到的片元,保留了当前的计算结果。这样的渲染顺序不会有优化结果
反之,顺序颠倒后则优化效果最大

渲染顺序从右向左,依次被较大物体遮挡

CPU:将待渲染物体按照距离摄像机的远近排序后,再交给GPU处理,可以达到Early-Z的优化目的,但是频繁的排序操作会消耗CPU的性能。并且严格按照由近到远的顺序渲染,将不能搭配合批的优化方法

3.Z-Prepass

用来解决上一方法中的缺陷

3.1.双Pass法

  1. Pass1(Z-Prepass):仅仅写入深度、不输出颜色(保留了最近的深度信息)
  2. Pass2:关闭深度写入,深度比较条件为相等(和上一步的深度信息对比,相等则为最近的物体)

以上两步完成了深度的排序,减少了CPU对排序计算的消耗,但增加了DrawCall的数量

3.2.提前分离的PrePass

  1. Z-Prepass单独作为一个Shader渲染整个场景的不透明物体,写入深度
  2. 同样作为单独的Shader,计算相同

参考教程雨松MOMO:Unity3D研究院之URP下PrePassZ(一百一十九)

以上,Z_Prepass也是透明渲染的一种解决方案,解决了排序问题但也导致剔除了透明物体的背面(解决思路:渲染正面时剔除背面,渲染背面时剔除正面,再将结果合并)

4.Z-Prepass的其他问题

消耗问题

以下数据来自:lipsryme的实验,50k个带有完整贴图的不透明cube

条件性能
关闭Z-Prepass + 几何变换光栅Pass0 + 2.7 ms
开启Z-Prepass + 几何变化光栅Pass2.0+ 2.4 ms

后续:当一个复杂场景中存在大量OverDraw但又无法用排序来有效解决时,可以尝试用Z-Prepass来优化

5.Early-Z和Z-Prepass的实例应用

面片叠加的头发渲染

3个Pass:

  1. 不透明部分:对不透明物体开启深度测试,关闭背面剔除,开启深度写入,深度测试中保留深度值较小的片元
  2. 透明-背面部分:对透明物体开启深度测试,剔除正面多边形,关闭深度写入,深度测试中保留深度值较小的片元
  3. 透明-正面部分:对透明物体开启深度测试,剔除背面多边形,开启深度写入,深度测试中保留深度值较小的片元

以上过程会带来OverDraw问题,解决思路:
使用一个Shader将透明度测试的结果写入Z buffer(即Z-Prepass方法)
解决后的流程,4个Pass:

  1. 对不透明物体开启深度测试,关闭背面剔除,使用Z-Prepass
  2. 不透明部分:关闭背面剔除,关闭深度写入,深度测试中保留深度值相等的片元(同上1)
  3. 透明-背面部分:剔除正面多边形,关闭深度写入,深度测试中保留深度值较小的片元(同上2)
  4. 透明-正面部分:剔除背面多边形,开启深度写入,深度测试中保留深度值较小的片元(同上3)

作业

preZ效果测试

硬件环境:8700k 1080

测试场景:

10k个球体,由近到远,依次变大,逐个嵌套

左:单Pass,关闭深度写入 中:单Pass,开启深度测试 右:双Pass PreZ + 关闭深度写入、Ztest Equal
左:EarlyZ失效 中:EarlyZ生效 右:EarlyZ生效

中:尽管待渲染物体的位置变化是规律的,但Unity渲染时还是对其进行了某种排序,使得Early-Z起到了优化作用

结论:
在渲染不透明物体时,尽管prePass提前绘制了深度信息,但也造成了的成倍的Batches数量增加,性能下降。其次,Unity本身没有按照由近到远的顺序渲染物体,而是做了最大限度优化GPU的排序(见下面参考),这使得当在如上图的过程中,序号为9332的物体绘制完成后,编号在这之前的物体都不会通过EarlyZ的深度测试,不会造成大量的OverDraw,也就避免了片元着色器的浪费。
因此手动增加一个Pass来渲染深度,从结果上看没有必要。

来自Unity文档OpaqueSortMode的参考:
Opaque objects are sorted by various criteria (sorting layers, shader queues, materials, distance, lightmaps etc.) to maximize both the CPU efficiency (reduce number of state changes and improve draw call batching), and to maximize GPU efficiency (many GPUs prefer rough front-to-back rendering order for faster rejection of invisible surfaces).

Demo:双Pass仿X光透视效果实现

灵感来源及参考资料:

Unity3D-Shader-实现X光效果
一口气解决RenderQueue、Ztest、Zwrite、AlphaTest、AlphaBlend和Stencil
Unity Shader-渲染队列,ZTest,ZWrite,Early-Z
模型来自互联网

实现效果
效果图1

效果图2

效果图3

实现原理

第一个Pass关闭深度写入,使用Greater渲染透视的效果,第二个Pass正常渲染Lambert效果
预先配置: Tags {“Queue”=“Transparent” “RenderType”=“TransParent” “IgnoreProjector”=“True”}

第一个Pass:透视效果

  1. 配置:ZWrite off ZTest Greater Blend SrcAlpha OneMinusSrcAlpha
  2. 顶点着色器:片元颜色 = (1-viewDir · normalDir) * Color * Intensity
  3. 片元着色器:返回顶点中计算的颜色

第二个Pass:Lambert

  1. 配置:ZWrite On ZTest LEqual Blend Off
  2. 计算Lambert漫反射效果
效果图

总结earlyZ的限制

  1. 很多简单物体存在场景中时,如上测试场景1,单独一个Pass计算深度信息消耗很大。
  2. 有效的排序、合理的渲染顺序可以很好的发挥EarlyZ的效果(见OpaqueSortMode)。
  3. 反之,渲染顺序的不合理会频繁的让待渲染的物体通过EarlyZ、进行片元计算却又被抛弃,造成浪费。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值