- 常用业务需求:
- 绘制物体的轮廓
- 实现镜面效果
- 实现阴影效果(Shadow Volume)
- 删除重叠的部分,防止出现z-fighting的问题
- 只需要绘制部分我们所需要的, 其他部分不考虑
- 模板缓冲区是一个buffer,可以通过gl.clear/gl.clearStencil 执行/设置初始值
- Stencil buffer为每个fragment提供8位的存储空间,即可以存储256个不同的数值,但是如果要实现一个简单的模板剪裁效果,其实1位(0和1)就够用了
- gl.stencilFunc 用来控制stencil的测试方式,即怎样才算通过测试
const GLenum NEVER = 0x0200;
const GLenum LESS = 0x0201;
const GLenum EQUAL = 0x0202;
const GLenum LEQUAL = 0x0203;
const GLenum GREATER = 0x0204;
const GLenum NOTEQUAL = 0x0205;
const GLenum GEQUAL = 0x0206;
const GLenum ALWAYS = 0x0207;
void stencilFunc(GLenum func,
GLint ref,
GLuint mask);
void stencilFuncSeparate(GLenum face,
GLenum func,
GLint ref,
GLuint mask);
- gl.stencilOp 用来指定通过测试和未通过测试时要怎么处理。
const GLenum GL_ZERO ;
const GLenum KEEP = 0x1E00;
const GLenum REPLACE = 0x1E01;
const GLenum INCR = 0x1E02;
const GLenum INCR_WRAP = 0x8507;
const GLenum DECR = 0x1E03;
const GLenum INVERT = 0x150A;
const GLenum DECR_WRAP = 0x8508;
- 默认情况下glStencilOp是设置为(GL_KEEP, GL_KEEP, GL_KEEP)的,所以不论任何测试的结果是如何,模板缓冲都会保留它的值。
void stencilOp(GLenum fail,
GLenum zfail,
GLenum zpass);
void stencilOpSeparate(GLenum face,
GLenum fail,
GLenum zfail,
GLenum zpass);
- glStencilMask(0xFF); // 每一位写入模板缓冲时都保持原样
- glStencilMask(0x00); // 每一位在写入模板缓冲时都会变成0(禁用写入)
- 大部分情况下都只会使用0x00或者0xFF作为模板掩码(Stencil Mask)
void stencilMask(GLuint mask);
void stencilMaskSeparate(GLenum face, GLuint mask);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.clear(gl.STENCIL_BUFFER_BIT);
gl.disable(gl.DEPTH_TEST);
gl.enable(gl.STENCIL_TEST);
gl.stencilFunc(gl.ALWAYS, 1, 1);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
ms.pushMatrix();
ms.scale(0.3, 0.3, 0.3);
rectdb.drawSelf(ms, texMap["db"]);
ms.popMatrix();
gl.stencilFunc(gl.EQUAL, 1, 1);
drawmirror();
gl.disable(gl.STENCIL_TEST);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
ms.pushMatrix();
ms.scale(0.3, 0.3, 0.3);
rectdb.drawSelf(ms, texMap["tm"]);
ms.popMatrix();
gl.enable(gl.DEPTH_TEST);
gl.disable(gl.BLEND);
drawball();
- 代码讲解
- 代码讲解
- 案例1
- 这里面有三个设置
-
function getGLContext() {
var glContextNames = ["webgl", "experimental-webgl"];
for (var i = 0; i < glContextNames.length; i++) {
try {
gl = canvas.getContext(glContextNames[i], {
stencil: true
});
} catch (e) {}
if (gl) {
gl.clearColor(74 / 255, 115 / 255, 94 / 255, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
gl.viewport(0, 0, canvas.width, canvas.height);
gl.enable(gl.STENCIL_TEST);
break;
}
}
}
- stencilFunc stencilOp stencilMask(0xff) stencilFunc stencilMask(0x00)
-
gl.stencilFunc(gl.ALWAYS, 1, 0xff);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
gl.stencilMask(0xff);
gl.clear(gl.STENCIL_BUFFER_BIT);
gl.colorMask(0, 0, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, maskVertex.length / 3);
gl.useProgram(program);
gl.stencilFunc(gl.EQUAL, 1, 0xff);
gl.stencilMask(0x00);
gl.colorMask(1, 1, 1, 1);
var color = [1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1];
var colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(color), gl.STATIC_DRAW);
var aColorPosition = gl.getAttribLocation(program, "aColor");
gl.vertexAttribPointer(aColorPosition, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(aColorPosition);
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array(vertex),
gl.STATIC_DRAW
);
var aVertexPosition = gl.getAttribLocation(program, "aPos");
gl.vertexAttribPointer(aVertexPosition, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(aVertexPosition);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, vertex.length / 3);