WebGL模板缓冲区

您所在的位置:网站首页 mask蒙版是什么意思 WebGL模板缓冲区

WebGL模板缓冲区

2023-05-06 18:42| 来源: 网络整理| 查看: 265

课程目标

理解Stencil Buffer 的概念

掌握Stencil Buffer 的用法

1-stencil buffer简介

Stencil的本意是模板,即有镂空图案的板子。

stencil buffer 就是模板缓冲区的意思,这是一个存储着模板数据的缓冲区。

在上图中,如果没有模板,喷枪中的颜料会直接喷到画布上。

有了镂空的模板后,便可以对颜料进行过滤,从而喷出特定的图案。

Stencil buffer会为每个fragment提供8位的存储空间,在其中可以写入[0,255]的数字。

其实要实现上图那样的简单效果,1位0和1就够了。

我们通过下面的示意图具体说一下这个逻辑。

A:要喷绘的颜色

B:模板

C:模板过滤出的图像

由此我们可以思考一下用模板绘图的逻辑。

1.准备一张模板。这张模板上需要有一堆参考数据reference。

2.喷涂颜色,喷涂之前要指定参考值reference和模板测试方法,这里的reference会与模板的reference做模板测试。

2-stencil buffer的使用

在stencil buffer相关操作中,有两个很重要的方法:gl.stencilFunc()、gl.stencilOp()。

stencilFunc(func, ref, mask) 设置模板测试的前后函数和参考值。

func 测试函数,默认gl.ALWAYS。

下面是其可以取的值,拷贝自MDN,英语很简单,不翻译了。

gl.NEVER: Never pass.

gl.LESS: Pass if (ref & mask) < (stencil & mask).

gl.EQUAL: Pass if (ref & mask) = (stencil & mask).

gl.LEQUAL: Pass if (ref & mask) (stencil & mask).

gl.NOTEQUAL: Pass if (ref & mask) !== (stencil & mask).

gl.GEQUAL: Pass if (ref & mask) >= (stencil & mask).

gl.ALWAYS: Always pass.

ref 用于指定模板测试的参考值。默认值为0。

mask 指定一个逐位掩码,用于在测试完成时对参考值和存储的模板值进行AND运算。默认值为1。

stencilOp(fail, zfail, zpass):指定通过测试和未通过测试时要怎么处理。

fail 模板测试失败时要使用的函数。默认值为gl.KEEP。

zfail 模板测试通过但深度测试失败时要使用的函数。默认值为gl.KEEP。

zpass 模板测试和深度测试都通过时,或者模板测试通过且深度缓冲区无效时要使用的函数。默认值为gl.KEEP。

上面参数可以写入以下值:

gl.KEEP 保持当前值。

gl.ZERO 将模板缓冲区值设置为0。

gl.REPLACE 将模板缓冲区值设置为WebGLRenderingContext.stencilFunc()里的reference。

gl.INCR 增加当前模板缓冲区值。最大为unsigned 值。

gl.INCR_WRAP 增加当前模板缓冲区值。 增加到unsigned 值时,模板缓冲区的值为零。

gl.DECR 减小当前模板缓冲区的值。最小为0。

gl.DECR_WRAP 减小当前模板缓冲区的值。减小到0时,模板缓冲区的值为unsigned 值。

gl.INVERT 逐位反转当前模板缓冲区值。

接下来我们举个简单的例子。

我要透过一个圆形的遮罩画一个圆,效果如下:

A:要喷绘的颜色

B:模板

C:模板过滤出的图像

其整体代码如下:

效果如下:

解释一下其原理。

1.圆形是用一点加上距离算法实现的。

2.在通过canvas获取webgl上下文对象的时候,stencil需要设置为true,并且开启STENCIL_TEST 模板测试功能。

3.初始化着色器。

4.定义背景色和模板值,清理缓冲区。

现在的模板缓冲区里都是0:

5.获取顶点的attribute 变量,并对其做一下初始化设置。

6.建立一个圆形的模板。

我们可以画一下看看:

效果如下:

当前的模板缓冲区中,圆内为1,圆外为0:

7.我们只需要用gl.drawArrays()方法把模板数据写入模板缓冲区即可,但不需要显示出来,所以得这么做。

现在画布中除了浅黄色的背景,啥也木有了:

8.再绘制一个蓝色的圆,这个圆是要显示出来的,不再是模板了。

stencilFunc()不是模板专有的方法,因为你要画的图形与模板怎么合成,是两方面的事。

所以在正常画图时,也要通过stencilFunc()方法告诉程序对象,你希望它如何与模板打配合。

stencilFunc()中的gl.EQUAL表示当我这里面的reference与模板那里的reference相等时,代表模板测试通过了。

stencilFunc()中的1是要与之前模板里的reference做比较的。

后面没有执行stencilOp(),这是因我们现在不需要再向stencil buffer里写入内容。

现在stencil buffer的基本操作流程就说完了。

我们在画图时,也可以用stencilFunc()方法实现反向遮罩效果。

效果如下:

webgl中stencil buffer是可以精确到模型的哪一面的,比如正面、反面和双面。

要精确到模型的哪一面,将之前的stencilFunc(func, ref, mask)、stencilOp(fail, zfail, zpass)、stencilMask(mask)替换成stencilFuncSeparate(face, func, ref, mask)、stencilOpSeparate(face, fail, zfail, zpass)、stencilMaskSeparate(face, mask)。

其中的face就指定模型哪一面的,其值可以取 gl.FRONT、gl.BACK和gl.FRONT_AND_BACK。

具体我就不再演示了,很简单,大家可以自己试试,若有问题再跟我说。

3-多缓冲区

模板是可以进行合成的,比如我可以用两个圆异或出一个模板来:

异或是一种运算逻辑,其符号是^。

两个白色的圆是1,相交部分是1^1=0,所以其相交的部分是黑的。

1.模板代码如下:

模板1和之前一样,我们看模板2.

模板2以1为reference值,若1等于当前模板缓冲区中的reference,则通过模板测试,其值为1的INVERT,即0。否则,若1不等于当前模板缓冲区中的reference,其值去模板2的reference,即1。

按照异或逻辑,模板2的stencilFunc()和stencilOp()也可以这么写:

2.正常画一个圆

效果如下:

遮罩原理如下:

整体代码如下:

以此原理,我们可以来个平构玩玩。

代码如下:

4-模板缓冲区之深度测试

我们之前说模板缓冲区的时候,并没有开启深度测试,其实利用深度测试,也可以做一些有趣的操作。

比如,我们可以使用深度缓冲区,制作一张高亮的帧缓冲图像,对某一区域的模型进行高亮显示。

图像源自:https://blog.51cto.com/u_15098014/2613644

接下来咱们用webgl写一下这个遮罩原理。

整体代码如下:

效果如下:

解释一下其逻辑。

1.开启深度测试。

2.建立一个初始模板,这个模板可视之为包裹了一部分要高亮的建筑的盒子。

模板示意图:

当前模板的深度为0.5。

2.以场景中的所有物体为模板与初始模板进行合成。

模板示意图:

在初始模板前面的图形会通过模板测试,所以会取reference的INVERT,即0。

在初始模板后面的图形不会通过模板测试,所以会保持模板缓冲区的当前值。

3.关闭模板缓冲区,基于模板值,绘制高亮的物体。

示意图:

效果如下:

关于模板缓冲区就先说到这,当前以理解原理为主,至于具体的案例实现,我会放到three.js里实现。

总结

模板缓冲区使用过程:

1.将模板形状绘制到模板缓冲区,这个过程中通常会禁止写入颜色,模板检测设置为总通过,设置好之后会调用一次绘制,画完后恢复写入颜色缓冲区。

2.重新调整模板检测方法,指明什么情况下通过测试,不再写入模板缓冲区,再进行一次绘制。

我们可以在WebGL渲染管线中对Stencil Test有一个整体认知:

参考链接:

http://www.jiazhengblog.com/blog/2016/04/05/2941/

https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/stencilFunc#specifications



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3