遮挡用在哪些场景
在WebGL中,gl.STENCIL_TEST
是一种模版测试(Stencil Test),它是一种基于模版缓冲区的技术,用于在绘制过程中进行更复杂的控制。模版测试允许你根据模版缓冲区中的值来决定是否允许绘制到屏幕上的特定像素。
常用的一些场景:
-
剪裁掩码:你可以使用模版测试来定义一个掩码,仅绘制到模版缓冲区特定区域内的像素。这对于实现各种形状的剪裁非常有用。
-
阴影体积:在阴影体积渲染中,你可以使用模版测试来确定哪些像素在阴影体积内,以便在渲染阴影时只考虑这些像素。
-
光栅化技术:模版测试可以用于实现各种复杂的光栅化效果,例如细节纹理映射、反射和折射等。
-
镜头遮挡:模版测试可以用于确定镜头遮挡效果,例如在FPS游戏中,当玩家的角色处于遮挡物后面时,遮挡物会遮挡玩家的视野。
-
图像处理:模版测试可以用于实现各种图像处理效果,例如抠像、边缘检测等。
如何实现剪裁掩码
以下的demo实现的把一个满屏的绘制对象,通过裁剪掩码到一半的大小,如下图:所示
1、准备所需要的顶点和片元着色器
const v = `
precision mediump float;
attribute vec2 a_pos;
varying vec2 vPos;
void main() {
vPos = a_pos;
gl_Position = vec4(a_pos,0.0,1.0);
}
`
const f = `
precision mediump float;
uniform sampler2D cmap;
varying vec2 vPos;
void main () {
gl_FragColor =vec4(1.0, 0.0, 0.0, 1.0);
}
`
const fmask = `
precision mediump float;
uniform sampler2D cmap;
varying vec2 vPos;
void main () {
gl_FragColor =vec4(0.0);
}
`
const vS = `
precision mediump float;
attribute vec2 a_pos;
varying vec2 vPos;
void main() {
vPos = a_pos;
gl_Position = vec4(1.0- 2.0 * a_pos,0.0,1.0);
}
`
const f1 = `
precision mediump float;
uniform sampler2D cmap;
varying vec2 vPos;
void main () {
vec4 color = texture2D(cmap, vPos);
gl_FragColor = color;
// gl_FragColor.a = 0.5;
}
`
2、绘制一个遮罩图形
function drawMask(gl:WebGLRenderingContext){
const maskPositions = createMesh.createGlPosition(0.5)
const maskProgramInfo = glUtil.creatProgramInfo(gl, v, fmask)
gl.useProgram(maskProgramInfo.program)
gl.viewport(0, 0, config.width, config.height)
const maskbuffer = glUtil.createBuffer(gl, maskPositions.position)
glUtil.setAttr(gl, maskProgramInfo.program, "a_pos", maskbuffer, 2)
glUtil.createIndexBuffer(gl, maskPositions.index)
gl.drawElements(gl.TRIANGLES,
maskPositions.index.length,
gl.UNSIGNED_SHORT, 0)
}
3、需要遮罩的对象
function draw(gl:WebGLRenderingContext){
const programinfo = glUtil.creatProgramInfo(gl, v, f)
const positions = createMesh.createGlPosition()
const buffer = glUtil.createBuffer(gl, positions.position)
gl.useProgram(programinfo.program)
gl.viewport(0, 0, config.width, config.height)
glUtil.setAttr(gl, programinfo.program, "a_pos", buffer, 2)
glUtil.createIndexBuffer(gl, positions.index)
gl.drawElements(gl.TRIANGLES,
positions.index.length,
gl.UNSIGNED_SHORT, 0)
}
4、绘制到屏幕上
function drawScreen(gl:WebGLRenderingContext, txt:WebGLTexture){
const positions = {
position:[
0,1,
0,0,
1,0,
1,1
],
index:[0, 1, 2, 2, 3,0]
}
const programUpdateInfo = glUtil.creatProgramInfo(gl, vS, f1);
gl.useProgram(programUpdateInfo.program)
gl.viewport(0, 0, config.width, config.height)
const buffer1 = glUtil.createBuffer(gl, positions.position)
glUtil.setAttr(gl, programUpdateInfo.program, 'a_pos', buffer1, 2)
glUtil.setTextureAndLoc(programUpdateInfo.program, gl, txt, 'cmap', 2)
glUtil.createIndexBuffer(gl, positions.index)
gl.drawElements(gl.TRIANGLES,
positions.index.length,
gl.UNSIGNED_SHORT, 0)
}
5、图片绘制的顺序
function createGl(){
const canvas1 = document.querySelector("#con") as HTMLCanvasElement;
const gl = canvas1.getContext("webgl")!
const txt = glUtil.createTexture(gl, null,
[config.width, config.height, 0],
new Array(config.width * config.height * 4).fill(0))
const framebuffer = glUtil.createFramebuffer(gl, txt,
config.width, config.height)!
glUtil.bindFramebuffer(gl, framebuffer, null)
gl.enable(gl.STENCIL_TEST) // 开启模版测试,后续的绘制操作将会考虑模版测试的设置
gl.clear(gl.STENCIL_BUFFER_BIT) // 清楚模版缓冲区
gl.stencilFunc(gl.ALWAYS,1, 0xff) //设置模版测试函数,gl.ALWAYS表示始终通过模版测试,1表示参考值,0xff表示参考值的位掩码
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE) // 模版测试操作,测试通过设置参考值
gl.stencilMask(0xff) //设置模版掩码,用于限制写入模版缓冲区的位
gl.colorMask(false, false, false, false) // 设置颜色写入的掩码
drawMask(gl)
gl.stencilFunc(gl.EQUAL, 1, 0xff) // 设置模版测试函数
gl.stencilMask(0x00)
gl.colorMask(true, true, true, true)
draw(gl)
gl.disable(gl.STENCIL_TEST)
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.disable(gl.STENCIL_TEST)
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
drawScreen(gl, framebuffer.texture)
}
总结文中使用的工具已经放在GitHub