[TA] 百人计划-图形3.1-深度与模版测试笔记
2026/9/23 9:53:31 网站建设 项目流程

目录

  • 一、 模版测试
    • 1.1 模版测试的原理
    • 1.2 模版测试核心配置
    • 1.3 应用
  • 二、深度测试
    • 2.1 深度测试原理
    • 2.2 基础概念
      • 2.2.1 Early-Z
      • 2.2.2 ZTest比较操作
      • 2.2.3 深度缓冲区
      • 2.2.4 ZWrite深度写入
      • 2.2.5 渲染队列
    • 2.3 深度值特性
    • 2.4 深度测试核心配置
    • 2.5 深度测试应用
    • 2.6 总结
  • 参考资料

一、 模版测试

1.1 模版测试的原理

模版缓冲区每个像素存储1个8位无符号整数,范围0-255 默认值0

  1. 原理:当前片元参考值与模版缓冲区指定值比较,通过保留片元,否则丢弃;1输出原本颜色,0不输出

从渲染管线理解:(图中流程均在frag之后)

frag阶段高度可配置,但无法编程

stencil test位置:alpha测试之后,深度测试之前

其他阶段说明:
Pixel OwnerShip Test像素权测试:在scene、game视图里的可视像素
Scissor Test裁剪测试:自定义渲染区域
Alpha Clip:按照阈值,剔除半透明区域;即alpha低于如0.7,都被剔除

  1. 常用场景:传送门(里面是另一个房间场景)(也可以用另一个相机拍RT)
    参考游戏:《笼中窥梦》

1.2 模版测试核心配置

配置项功能说明
Ref(参考值)自定义0-255的数值,用于和模板缓冲区值做比较
Read Mask(读掩码)与参考值、模板缓冲区值做按位与运算后再进行比较
Write Mask(写掩码)控制模板缓冲区可写入的位范围
Comp(比较操作)可选Never、Less、LEqual、Equal、NotEqual、Greater、GEqual、Always共8种规则
Pass模板测试通过时对模板缓冲区执行的操作
Fail模板测试失败时对模板缓冲区执行的操作
ZFail模板测试通过但深度测试失败时对模板缓冲区执行的操作
Color Mask颜色遮罩,设为0时不输出任何颜色,仅用于更新模板缓冲区

1.3 应用

思路:外界、边界、内界
即渲染物体->渲染mask->渲染被mask遮罩的物体

  1. 3d卡牌
    效果:卡牌呈现纵深3d感,随视角变化,卡牌内也有视差变化
    原来的完整场景,将卡牌边框外的东西都剔除
  2. 多面盒子
  3. 描边
  4. 反射
  5. 阴影体
  6. 蒙版

二、深度测试

2.1 深度测试原理

  1. 原理
    • 通过深度缓冲区,判断片元的前后遮挡关系
    • 针对当前对象在屏幕上(更准确的说是frame buffer)对应的像素点,将像素自身深度值与当前像素点缓冲的像素点比较;若通过,本对象的像素点才将颜色写入颜色缓冲,否则不写入。
  2. 位置:模版测试之后、alpha混合之前

深度缓冲区:存储每个像素深度值,精度为24位,高端显卡支持32位

深度测试的发展:
早期算法:画家算法(从远往近,层层覆盖,会产生大量overdraw,与现在相反被淘汰)、Z-Buffer算法:通过深度缓冲区存储像素深度值,自动比较前后关系,当前主流方案
->
控制Z-Buffer对深度值的存储:ZTest、ZWrite
->
控制不同类型物体的渲染顺序(渲染队列):透明、不透明物体
->
减少overdraw:Early-Z、Z-cull、Z-check

2.2 基础概念

2.2.1 Early-Z

  1. 定义:frag前进行深度测试,直接丢弃未通过测试的面片,降低无效片元在frag的计算
  2. 位置:光栅化后、frag之前
    注意:有时候会用到两次深度测试,Early-Z一次、FS处理后ZTest再进行一次起到检查作用;前次Z-Cull,后次Z-Check;

2.2.2 ZTest比较操作

ZTest 状态描述
Greater深度大于当前缓存则通过
LEqual深度小于等于当前缓存则通过
Less深度小于当前缓存则通过
GEqual深度大于等于当前缓存则通过
Equal深度等于当前缓存则通过
NotEqual深度不等于当前缓存则通过
Always(Off)深度不论如何都通过
Never深度不论如何都不通过

2.2.3 深度缓冲区

  1. 定义:类似颜色缓冲(储存所有的像素颜色),每个像素存储信息。跟颜色缓冲一样有宽度和高度。
    深度缓冲是由窗口系统自动创信息,它会以16、24或32位float的形式诸存它的深度值。
    在大部分的系统中,深度缓冲的精度都是24位
  2. z-buffer里存储当前深度信息

2.2.4 ZWrite深度写入

深度写入包括两种状态:ZWrite OnZWrite Off

先ZTest、再ZWrite
ZTest:读深度缓冲,拿当前片元 Z 和缓冲里已存 Z
ZWrite:写深度缓冲,把本片元的 Z 存进去,只有测试成功才会执行写操作

ZTest分为通过和不通过两种情况,ZWrite分为开启和关闭两种情况的话,一共就是四种情况:

序号状态组合结果
1深度测试通过,深度写入开启写入深度缓冲区,写入颜色缓冲区
2深度测试通过,深度写入关闭不写深度缓冲区,写入颜色缓冲区
3深度测试失败不写深度缓冲区,不写颜色缓冲区

渲染呈现:

ZWrite On:渲染队列>Always>LEqual(越靠前越先渲染)
ZWrite Off:不写入深度,被后来者覆盖;除非渲染队列更大

←——————相机前方—————— 相机位置 —————相机后方————→ -10 -5 0 +5 +10 方块B 方块A 相机

-1,1->0,1 方块a更近,覆盖b

ps:shader中默认状态是ZTest LEqual、ZWrite On

2.2.5 渲染队列

  1. 内置渲染队列介绍
    队列数越小,越先渲染;队列数越大,越后渲染。
队列名称队列号描述
Background1000最早被渲染的物体的队列
Geometry2000不透明物体的渲染队列。大多数物体都应该使用该队列进行渲染,也是Unity Shader中默认的渲染队列
AlphaTest2450有透明通道,需要进行Alpha Test的物体的队列,比在Geometry中更有效
Transparent3000半透物体的渲染队列。一般是不写深度的物体,Alpha Blend等的在该队列渲染
Overlay4000最后被渲染的物体的队列,一般是覆盖效果,比如镜头光晕,屏幕贴片之类的
  1. 设置位置

    1. Shader代码中设置:
      Tags { "Queue" = "Transparent" },默认是Geometry
    2. Shader / Material 的 Inspector面板,可以查看Render Queue相关属性;在此处设置,会覆盖shader里的设置
  2. 物体渲染顺序规则

  • 不透明物体的渲染顺序:从前往后
  • 透明物体的渲染顺序:从后往前(OverDraw)

2.3 深度值特性

  1. 深度缓冲区
    • 存储0-1之间非线性缓冲值,因为在适应透视相机的投影阶段(viewport),视椎体->前后裁剪面一致大小的面;此时深度值映射变为非线性,近处深度值间间隔宽,越远越密集(想象人眼看通向远处的树)
    • 利用有限的缓冲区精度,近平面分配高精度、远平面分配低精度(近清晰、远模糊)

ps:时刻结合生活中真实的视觉效果理解

  1. 空间变化:
    模型空间(无深度)->世界空间(线性,z)->视空间(线性,获取场景内线性深度就是转到这一步,z)->裁剪空间(线性,M(Perspective)z,A·z + B)->NDC(非线性,z/w)->屏幕空间

  1. 深度冲突(Z-Fighting):两个平面极近平行时,深度缓冲区精度不足导致导致前后像素频繁切换,造成画面频闪
    解决:
    • . 物理上拉开物体之间距离
    • 调远摄像机近平面,提高近处深度精度
    • 使用更高精度的32位缓冲区

2.4 深度测试核心配置

  1. 核心配置两项

(1)Unity内置渲染队列(队列号越小越先渲染)

队列名称队列号适用场景渲染顺序规则
Background1000背景-
Geometry2000不透明物体从前往后渲染,减少Overdraw
AlphaTest2450透明度测试物体-
Transparent3000半透明物体从后往前渲染,保证混合效果正确
Overlay4000镜头光晕、屏幕贴片等覆盖效果-

(2)ZTest与ZWrite组合

序号状态组合结果
1深度测试通过,深度写入开启写入深度缓冲区,写入颜色缓冲区
2深度测试通过,深度写入关闭不写深度缓冲区,写入颜色缓冲区
3深度测试失败不写深度缓冲区,不写颜色缓冲区
  1. 举例:被遮挡物体的显示
    Greater,ABC, 深度:A>B>C
    如果B要展示在A之上,

Pass 0 :正常绘制 ZTest:Lequal ZWrite:On
Pass 1 :被遮挡发光 ZTest:Greater ZWrite:Off

被遮挡部分通过测试,绘制在A上;如果背景深度是无穷远,不通过,露出部分不绘制
不写入深度:他后面的物体还是Lequal,都大于这个深度,无法正确绘制在屏幕上

适用场景:被建筑物等遮挡时,人物依然有轮廓显示

  1. 注意

(1)QueueSubShader 标签,Pass没有独立生效的渲染队列。

材质的渲染队列默认使用inspector里设置的,会覆盖shader的队列设置

(2)透明混合的pass出现在不透明阶段
原因:材质队列2000,某pass使用Blend SrcAlpha OneMinusSrcAlpha混合

(3)URP下,所有Pass无法保证按顺序书写
UPR根据

  • 渲染阶段
  • LightMode
  • 管线绘制
    安排pass,不会默认把shader内所有pass都执行;

会执行的pass:
① 标准用途:LightMode为以下,都会执行:

LightMode用途
UniversalForward前向渲染路径中绘制物体
UniversalForwardOnly始终以前向方式绘制,兼容前向和延迟 Renderer
UniversalGBuffer延迟渲染时写入 GBuffer
SRPDefaultUnlit未设置LightMode时的默认值,也用于额外绘制,如描边
ShadowCaster写入阴影贴图,让物体投射阴影
DepthOnly深度预通过,输出相机视角的深度
DepthNormalsOnly深度与法线预通过,配合 SSAO 等功能
Universal2D供 2D Renderer 使用
Meta光照贴图烘焙时提取材质信息

② 相同LightMode默认只执行第一个匹配项
③ 其他pass要自己设置renderer feature
没写LightMode的 Pass 会被视为SRPDefaultUnlit,不是任意数量的无标签 Pass 都会自动执行

2.5 深度测试应用

  1. 基于深度着色:水体渲染:比较跟水底的深度,做颜色渐变
  2. 阴影贴图:比较灯光空间和视空间的深度差
  3. 透明物体、粒子渲染(透掉黑底)
  4. 角色遮挡透视效果
  5. 能量罩切边效果

2.6 总结

  1. 深度缓冲重要的两个值:当前深度缓冲值(ZBufferValue)与深度参考值(rederenceValue),通过比较抉择是否更换深度缓冲值
  2. Early-Z能节省开销,提前抛弃会造成overdraw的无效片元
  3. 深度测试通过ZTest、ZWrite完成控制,如半透明、透明的渲染
  4. 深度缓冲区存储的是0-1范围内的浮点,非线性
  5. 深度渲染顺序:先渲染不透明物体,从前往后;再渲染透明物体,从后往前

如有错漏,欢迎指正!

参考资料

1.【【技术美术百人计划】图形 3.1 深度与模板测试 传送门效果示例】 https://www.bilibili.com/video/BV1Tb4y1C7Qa/?share_source=copy_web&vd_source=ffa9f839ea8afb4bd7809dfc7ae336f8

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询