前言
本章学习深度测试、深度写入、模板测试,简单制作魔镜世界,感谢Kerry大佬的教学
一、渲染顺序
Unity在决定渲染顺序时采用了深度缓冲技术。
当渲染物体时,每个所生成的 pixel 产生的深度数据会存储在 z-buffer(或称为 depth buffer),buffer 为二维矩阵,其尺寸大小与最后渲染尺寸相同。
如果渲染场景中其他物体时,并在同一个 pixel 位置渲染结果时,会检查 z-buffer 所存储的深度数据与当前Pixel的深度数据进行比较,决定是否将渲染结果覆盖原来的 pixel(Z-test),并且将新的深度速度写入到 z-buffer(Z-write)。通常条件会设定为深度数据比原本更接近摄像机时,就能够覆盖原本结果。
有 z-buffering 机制,不管物体渲染顺序(rendering order),使得离摄像机越近的物体,永远会渲染在其他离摄像机越远的物体之前。
二、深度测试(Z-test)与 深度写入(Z-write)
深度测试,所谓测试,就是针对当前对象在屏幕上(更准确的说是frame buffer)对应的像素点,将对象自身的深度值与当前该像素点缓存的深度值进行比较,如果通过了,本对象在该像素点才会将颜色写入颜色缓冲区,否则否则不会写入颜色缓冲。ZTest提供的状态较多。 ZTest Less(深度小于当前缓存则通过, ZTest Greater(深度大于当前缓存则通过),ZTest LEqual(深度小于等于当前缓存则通过),ZTest GEqual(深度大于等于当前缓存则通过),ZTest Equal(深度等于当前缓存则通过),ZTest NotEqual(深度不等于当前缓存则通过),ZTest Always(不论如何都通过)。注意,ZTest Off等同于ZTest Always,关闭深度测试等于完全通过。
ZWrite比较简单,只有两种状态, ZWrite On(开启深度写入)和ZWrite Off(关闭深度写入) 。当我们开启深度写入的时候,物体被渲染时针对物体在屏幕(更准确地说是frame buffer)上每个像素的深度都写入到深度缓冲区;反之,如果是ZWrite Off,那么物体的深度就不会写入深度缓冲区。
下面进行测试,默认z-write打开,每个物体在最开始的深度默认最大,最先开始渲染背景

(1)less
双色Z-test Mode 均为less
先渲染红色,红色与背景重叠,红色均less背景,所以红色部分所有都显示。

接下来渲染绿色,绿色有一部分与红色重叠,进行深度测试,重叠部分深度greater红色,所以不渲染,显示被红色遮挡,其余部分均less于背景,所以显示。

(2)greater
绿色为greater,红色为less
当渲染绿色时,进行深度测试,由于绿色深度测试mod为greater,所以与红色重叠部分显示,与背景(深度为MAX)部分不显示

(3)always
绿色开启always

虽然绿色重叠部分比红色greater,但是always则默认绿色通过,所以全部显示
我们在绿色后面添加一个白色,白色为greater

在渲染白色时,依旧会判断为Greater把绿色覆盖掉。
(4)关闭Z-write
红色绿色均为less,关闭红色的z-write

红色与背景进行Z-test后完成渲染,由于Z-write关闭,红色的深度不会被记录,默认为MAX,当渲染绿色时,重叠部分经过Z-test,便会覆盖红色。
三、模板测试(Stencil Test)
当片段着色器处理完片段之后,模板测试(Stencil Test) 就开始执行了,和深度测试一样,它能丢弃一些片段。仍然保留下来的片段进入深度测试阶段,深度测试可能丢弃更多。模板测试基于另一个缓冲,这个缓冲叫做模板缓冲(Stencil Buffer),我们被允许在渲染时更新它来获取有意思的效果。
模板缓冲中的模板值(Stencil Value)通常是8位的,因此每个片段/像素共有256种不同的模板值(译注:8位就是1字节大小,因此和char的容量一样是256个不同值)。这样我们就能将这些模板值设置为我们链接的,然后在模板测试时根据这个模板值,我们就可以决定丢弃或保留它了。

模板测试代码

模板测试的位置

四、简单制作魔镜世界

仅可以通过魔镜看到里面的世界
摆放模型,魔镜前放一个平面

开启平面的模板测试,测试值为1,让该平面总是通过任何模板测试,ColorMask 0让其完全透明
ColorMask 0
Stencil {
Ref 1
comp always
pass replace
}

此时移动摄像机会出现闪烁的问题,这是因为排序不明确,该平面设置为2460,魔镜世界设置为2470,让平面一直比魔镜世界先渲染,此时上图不会闪烁,但会一直挡住魔镜世界,此时关闭Z-write即可
ColorMask 0
Stencil {
Ref 1
comp always
pass replace
}
ZWrite off

此时给魔镜世界开启模板测试,此时模板值为一,只有通过平面才能看到
//开启模板测试
Stencil
{
Ref 1
Comp EQUAL
}
接下来解决魔镜世界可以看到其他物件的问题

给场景添加一个天空盒,这个天空盒非常大且远

给天空盒开启模板测试,开启ZTest Always
//开启模板测试
ZTest Always
Stencil
{
Ref 1
Comp equal
}
天空盒会为我们剔除没有开启模板测试的外面物件,而保留通过模板测试的物件

补充

大家可以用模板测试试着实现以下非欧几里得立方体

被折叠的 条评论
为什么被折叠?



