代码改变世界

WebGL学习笔记(十五):模板缓冲

2019-11-17 16:00  阿诚de窝  阅读(1898)  评论(0编辑  收藏  举报

可以用来干啥?

模板缓冲一般用来实现一些地面反射投影和类似镜子的特殊效果,如下:

开启模板缓冲

默认情况下,模板缓冲是关闭的,模板缓冲如果处于关闭状态,运行模板相关的代码不会报错,但是不会出现预期的效果。

使用下面的代码可以开启模板缓冲:

var gl = canvas.getContext("webgl", { stencil: true });

使用流程

模板缓冲可以确定下次渲染时,指定的像素是否要进行剔除,可以理解为每个像素只有 0(丢弃) 和 1(保留) 两个数值。

具体使用模板缓冲大体流程如下:

  1. 启用模板测试;
  2. 设定模板参数;
  3. 渲染物体,同时根据本次渲染出来的内容更新模板缓冲的内容,注意本次渲染会正常更新颜色缓冲和深度缓冲(如果深度缓冲开启);
  4. 设定模板参数;
  5. 渲染(其它)物体,这次根据模板缓冲的内容丢弃特定的片段;
  6. 禁用模板测试;

通过使用模板缓冲,我们可以根据场景中已绘制的其它物体的片段,来决定是否丢弃特定的片段。

当你启用模板测试之后,所有的渲染调用都会以某种方式影响着模板缓冲。

模板相关方法

常规方法

1 // 清除模板缓冲,模板缓冲所有像素值都为0。
2 gl.clear(gl.STENCIL_BUFFER_BIT);
3 // 开启模板测试
4 gl.enable(gl.STENCIL_TEST);
5 // 关闭模板测试
6 gl.disable(gl.STENCIL_TEST);

gl.stencilMask

glStencilMask允许我们设置一个位掩码(Bitmask),它会与将要写入缓冲的模板值进行与(AND)运算;

gl.stencilMask(0xFF); // 每一位写入模板缓冲时都保持原样
gl.stencilMask(0x00); // 每一位在写入模板缓冲时都会变成0(禁用写入)

gl.stencilFunc

https://developer.mozilla.org/zh-CN/docs/Web/API/WebGLRenderingContext/stencilFunc

确定后续的渲染,和当前模板缓冲中的像素模板值对比之后,是否丢弃掉渲染的结果。

glStencilFunc(GLenum func, GLint ref, GLuint mask)

func可选值如下:

GL_ALWAYS:不和模板缓冲中的值进行对比,所有渲染出的像素值都进行正常绘制;

GL_NEVER:不和模板缓冲中的值进行对比,所有渲染出的像素值都丢弃;

GL_LESS、GL_LEQUAL、GL_GREATER、GL_GEQUAL、GL_EQUAL、GL_NOTEQUAL:按照规则对比模板缓冲中的值和渲染出来的值进行释放丢弃渲染结果的判定。

ref 和 mask:

配合func参数使用,具体规则请看MDN。

gl.stencilOp

https://developer.mozilla.org/zh-CN/docs/Web/API/WebGLRenderingContext/stencilOp

设定如何根据下一次渲染的结果来更新模板缓冲中的值。

glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)
  1. sfail:模板测试失败时采取的行为。
  2. dpfail:模板测试通过,但深度测试失败时采取的行为。
  3. dppass:模板测试和深度测试都通过时采取的行为。

具体可以传递的参数如下:

  • KEEP(不改变,这也是默认值)
  • ZERO(回零)
  • REPLACE(使用测试条件中的设定值来代替当前模板值,stencilFunc方法中的ref参数)
  • INCR(增加1,但如果已经是最大值,则保持不变)
  • INCR_WRAP(增加1,但如果已经是最大值,则从零重新开始)
  • DECR(减少1,但如果已经是零,则保持不变)
  • DECR_WRAP(减少1,但如果已经是零,则重新设置为最大值)
  • INVERT(按位取反)

示例

https://hammerc.github.io/dou3d-ts/learning/learningNotes/lesson_15/index.html

上下箭头控制小方块的移动。