笔记15-图形 3.1 深度与模板测试 传送门效果示例
模板测试 Stencil Test
类似蒙版。可参考大佬:Minions Art-关于模板测试的讲解
《笼中窥梦》游戏中立方体各个面显示不同,就用到了模板测试。
渲染管线中的位置
位于逐片元操作:
1 | 片元和相关数据->Pixel Ownership Test(像素所有权测试)->Scissor Test(剪刀测试)->Alpha Test(Alpha测试)->Stencil Test(模板测试)->Depth Test(深度测试)->Blending(混合)->Dithering(抖动)->Logic Op(逻辑操作)->帧缓存 |
- Pixel Ownership Test 是逐片元操作流程中的第一道关卡,但它跟渲染3D物体没有直接关系,它检测像素是不是被其他窗口挡住。
- Scissor Test:不修改几何体,只是将矩形外的片元丢弃/跳过栅格化。例如,用
glScissor指定一个小矩形,那么矩形的绘制和清除操作都只会发生在这个区域内。 - Dithering:当显示设备(或帧缓冲)的颜色深度不够时(例如只有16位色,或移动端常见的低精度帧缓冲),像“撒芝麻”一样混合两种颜色的像素,利用人眼的低通滤波特性(即会把细微的点模糊掉),让视觉上感觉那里是一个平滑的中间色,从而打破生硬的色块感。
从 逻辑与书面概念 上理解
通过一定条件来判断是对该片元或片元属性执行抛弃操作还是保留操作。
说到模板测试,就要先说到模板缓冲区。模板缓冲区与颜色缓冲区和深度缓冲区类似,模板缓冲区可以为屏幕上的每个像素点保存一个无符号整数值(通常的话是个8位整数)。这个值的具体意义视程序的具体应用而定。在渲染的过程中,可以用这个值与一个预先设定的参考值相比较,根据比较的结果来决定是否更新相应的像素点的颜色值。这个比较的过程被称为模板测试。模板测试发生在透明度测试(alpha test)之后,深度测试(depthtest)之前。如果模板测试通过,则相应的像素点更新,否则不更新。
Unity Shader 中的 Stencil Test
1 | stencil{ |
Comparison Function
| 名称 | 比较方法 |
|---|---|
| Greater | 相当于“>”操作,即仅当左边>右边,模板测试通过,渲染像素 |
| GEqual | 相当于“>=”操作,即仅当左边>=右边,模板测试通过,渲染像素 |
| Less | 相当于“<”操作,即仅当左边<右边,模板测试通过,渲染像素 |
| LEqual | 相当于“<=”操作,即仅当左边<=右边,模板测试通过,渲染像素 |
| Equal | 相当于“=”操作,即仅当左边=右边,模板测试通过,渲染像素 |
| NotEqual | 相当于“!=”操作,即仅当左边!=右边,模板测试通过,渲染像素 |
| Always | 不管公式两边为何值,模板测试总是通过,渲染像素 |
| Never | 不敢公式两边为何值,模板测试总是失败,像素被抛弃 |
更新值(stenciloperation)
| 名称 | 比较方法 |
|---|---|
| Keep | 保留当前缓冲中的内容,即stencilBufferValue不变。 |
| Zero | 将0写入缓冲,即stencilBufferValue值变为0。 |
| Replace | 将参考值写入缓冲,即将referenceValue赋值给stencilBufferValue。 |
| IncrSat | stencilBufferValue加1,如果stencilBufferValue超过255了,那么保留为255,即不大于255。 |
| DecrSat | stencilBufferValue减1,如果stencilBufferValue超过为0,那么保留为0,即不小于0。 |
| Invert | 将当前模板缓冲值(stencilBufferValue)按位取反 |
| IncrWrap | 当前缓冲的值加1,如果缓冲值超过255了,那么变成0,(然后继续自增)。 |
| DecrWrap | 当前缓冲的值减1,如果缓冲值已经为0,那么变成255,(然后继续自减) |
Unity 项目展示与讲解
3D 卡牌效果,略。
蒙版:Render Queue = “Geometry+1”
使用蒙版的物体:Render Queue = “Geometry+2”(在蒙版之后)
- 物体默认的comp是 Always,也就是不受蒙版/模板测试影响。
Stencil Test 扩展
- 描边
- 多边形填充
- 反射区域控制
- shadow volume 阴影渲染
- 等等
掌握模板测试的核心思想,利用模板测试的特性同其他测试或图形算法结合使用
深度测试
处理物体前后遮挡关系。
渲染管线中的位置:读书笔记01《Unity Shader入门精要》
和模板测试差不多,或者说它俩差不多。
书面概念
所谓深度测试,就是针对当前对象在屏幕上(更准确的说是 frame buffer)对应的像素点,将对象自身的深度值与当前该像素点缓存的深度值进行比较,如果通过了,本对象在该像素点才会将颜色写入颜色缓冲区,否则不会写入颜色缓冲。
深度缓冲区(Z-Buffer)
深度缓冲就像颜色缓冲(储存所有的片段颜色:视觉输出)一样,在每个片段中储存了信息,并且(通常)和颜色缓冲有着一样的宽度和高度。深度缓冲是由窗口系统自动创建的,它会以16、24或32位float的形式储存它的深度值。在大部分的系统中,深度缓冲的精度都是24位的
Z-buffer 中存储的是当前的深度信息,对于每个像素存储一个深度值通过 ZTest 后,若 ZWrite On,则更新深度缓冲区的值
| ZTest 状态 | 描述 |
|---|---|
| Greater | 深度大于当前缓存则通过 |
| LEqual | 深度小于等于当前缓存则通过 |
| Less | 深度小于当前缓存则通过 |
| GEqual | 深度大于等于当前缓存则通过 |
| Equal | 深度等于当前缓存则通过 |
| NotEqual | 深度不等于当前缓存则通过 |
| Always (Off) | 深度不论如何都通过 |
| Never | 深度不论如何都不通过 |
- 默认: ZWrite On, ZTest Lequal, 深度缓冲中的值为无穷大
Unity 的渲染队列
Unity 中的几种内置的渲染队列,按照渲染顺序,从先到后进行排序,队列数越小的,越先渲染,队列数越大的,越后渲染。可以在 Inspector 中 shader 的 Render Queue 属性查看。
| 名称 | 用途 |
|---|---|
| Background(1000) | 最早被渲染的物体的队列。 |
| Geometry(2000) | 不透明物体的渲染队列。大多数物体都应该使用该队列进行渲染,也是UnityShader中默认的渲染队列。 |
| AlphaTest(2450) | 有透明通道,需要进行AlphaTest的物体的队列,比在Geomerty中更有效。 |
| Transparent(3000) | 半透物体的渲染队列。一般是不写深度的物体,Alpha Blend等的在该队列渲染。 |
| Overlay(4000) | 最后被渲染的物体的队列,一般是覆盖效果,比如镜头光晕,屏幕贴片之类的。 |
Unity 中设置渲染队列的方法:Tags{“Queue”=“Transparent”},默认是Geometry
不透明物体的渲染顺序:从前往后
透明物体的渲染顺序:从后往前(OverDraw)
Early-Z 技术
在着色计算前增加深度测试,减少计算浪费。(原来的ZTest 还是要的)
深度值
深度缓冲中最终存储的值,是经过 z/w 计算后,再映射到 [0,1] 范围内的结果。
给近处分配更多的精度;减少近处深度冲突的出现。
Unity 项目展示与讲解
X-Ray效果
1 | Pass // xRay绘制 |
1 | Pass//正常绘制 |
vertXray, fragXray, vertNormal, fragNormal,在前面的 CGINCLUDE 中写好了
粒子效果
“Queue”=”Transparent”
ZWrite Off
ZTest LEqual(或者不写)
Blend One One
应用拓展
- 基于深度的着色(湖水渲染)
- 阴影贴图(ShadowMap)
- 透明物体、粒子渲染
- 透视X-Ray效果
- 切边效果
- 等等
深入了解深度值在不同阶段的变化过程,通过深度测试、深度写入、深度图等方法控制深度缓冲区
-作业-
使用深度测试和模板测试做一些*有意思*的效果
- 标题: 笔记15-图形 3.1 深度与模板测试 传送门效果示例
- 作者: 铁名_IronName
- 创建于 : 2026-02-25 19:42:12
- 更新于 : 2026-02-26 18:48:23
- 链接: https://blog.ironname.top/2026/02/25/笔记15-技术美术百人计划/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。