写在前面:

本文章为个人学习笔记,方便以后自己复习,也希望能帮助到他人。

由于本人水平有限难免出现错误,还请评论区指出,多多指教。

部分图元和素材来源于网络,如有侵权请联系本人删除。

参考资料与链接会在文章末尾贴出。

=======================================================================

还记得深度缓冲区吗?它帮助我们比较对象的深度,以确保它们有正确相互遮挡关系。而本文会简单介绍模板缓冲区,模板缓冲区主要用于仅渲染对象的一部分而丢弃其他对象。

1 Writing from the Stencil Buffer

模板缓冲区为每个像素存储一个 8 位整数值(0-255)在帧缓冲区中。在执行片段着色器之前对于给定的像素,GPU 可以将模板缓冲区中的当前值与给定的参考值进行比较,这称为模板测试(Stencil Test)。如果模板测试通过,GPU 将执行深度测试。如果模板测试失败,GPU 会跳过该像素的其余处理。这意味着我们可以使用模板缓冲区作为掩码来告诉 GPU 哪些像素要绘制,哪些像素要丢弃。

模板测试是可配置的,所有的模板操作都是通过我们的 hlsl 代码之外的一个小的模板代码块来完成的。像大多数shaderlab的东西一样,我们可以在我们的子着色器中编写它们以将它们用于整个subshader或仅在某个shader pass中使用它们。

模板测试的基本公式是:

整一块模板测试的语义:

看着非常多,但其实我们并不需要为所有的signature指定值,因为很多signature都有默认值,本文的例子中我们只需要指定几个参数就能做出我们想要的效果。

本文例子将会有两个shader,一个write shader,一个read shader。

stencil 操作最重要的参数是 Ref,它标记了我们操作的模板参考值。默认值为 0,这是缓冲区在写入任何内容之前的默认值。我们首先将它设置为 0,这目前不会改变任何东西,但是现在输入它会使代码结构更清晰一些,且后面更改起来更轻松。

我们需要的模板操作的另一个参数是 Comp,它定义了模板操作何时通过。默认值为 Always,这意味着无论我们使用什么参考值,对象都将始终被绘制。对于read shader,我们将使用 Equal,意思是我们标记的Ref值与该位置的模板缓冲区Ref值相等时才绘制对象。

场景中我们简单搭建了一个窗框,窗框前后各有一个plane,现在把write shader的材质赋给front plane,并在fragment shader 中return 0,意料之中没有什么改变:

这是因为现在所有默认的stencil ref都是0,假如我们将ref改为1:

现在我们将ref作为属性暴露在外方便后续调试,[IntRange] attribute是保证我们的值为整数值。

目前的效果仍然是0为可见,其他的值全都不可见。

2 Reading to the Stencil Buffer

首先我们会完善之前的write shader,我们暴露Ref值,并把Comp改为always,这样它总是会通过模板测试,在通过模板测试后会把当前模板缓冲区的值改为自己当前的值,还有就是把深度写入关闭,不然会遮挡后面的物体:

接下来我们需要编写read shader,我们将之前光照模型的shader作为基础,再加上Stencil部分即可:

这里Comp改为Equal,即当前ref值与模板缓冲区ref值相等才会通过模板测试。

 

这样说明可能会更好理解一点,我们的plane实际上就是提前为屏幕中某片区域设置好了stencil value(这里为1),我们这里叫作write(Stencil Ref)shader;而真正想要渲染的物体也设定一个当前的Stencil value,但只有当此物体与模板缓冲区的值一致时才会渲染,假如我们设为1,那么因为默认为0,该物体无法通过模板测试自然不会渲染。当时当我们透过之前的plane观察此物体时,由于这个plane覆盖区域的stecil value被设为1,该物体Stencil value与之相等,因此就会被渲染。

先上效果图:

可以看到,假如不是透过plane的话是无法看到此物体的,因为没有通过模板测试不会被渲染。

接下来我们需要编写read shader

为了真正使用从模板缓冲区读取的着色器,我们将编写第二个从模板缓冲区读取的着色器。第二个着色器本身不会写入屏幕,而是在第一个着色器之前渲染,因此我们确保模板缓冲区在读取时已经写入了正确的值。

对于这个着色器,我们从一个基本的无光照着色器开始,就像在基础中一样,因为它非常简单而且我们不需要太多。为了让它根本不渲染到屏幕上,而只是操纵模板缓冲区,我们将向它添加一些其他的小细节。

我们可以继续完善一下write shader,因为我们在fragment shader中return0,所以看到背景是黑色的,我们可以把ColorMask设为0,这样就完全不输出颜色;此外,按照上面的逻辑我们需要write shader在read shader之前渲染,因为我们把其渲染队列改为Geometry-1,而read shader则保持Geometry:

我们把画框的另一面也做同样的配置,只不过前面的ref值为1,后面的ref值为2:

实际上两个物体处于相近的位置,却因为我们利用了模板缓冲区,呈现了这种效果。

原文地址:http://www.cnblogs.com/pisconoob/p/16849922.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性