webgl——混合与模板测试
< 返回列表时间: 2019-12-26来源:OSCHINA
今天研究了一个混合与模板测试相结合的案例,这里做以总结。
案例中一个篮球在地板上不断弹起并且落下,这里主要涉及到了两项技术:混合与模板测试。首先篮球在地板上反射出来的镜像篮球就是通过混合技术实现的,为了让镜像体在运动脱离地板时消失,实现真实的效果,还需要加入模板测试。
首先介绍他们的绘制顺序
1.开启模板测试,关闭深度检测
2.绘制实体地板
3.设置模板测试参数
4.绘制镜像球 ,禁用模板测试
5.开启混合
6.设置混合参数,绘制半透明地板
7.关闭混合,开启深度检测
看到这里是不是有些头晕了,不过没关系,我们来一起理一理其中的思路。
首先关于深度检测:深度检测在此案例中不需要使用,我们完全可以根据绘制的顺序来确定他们的显示顺序,当不开启深度检测时,会根据我们绘制的顺序来决定谁会覆盖谁。
其次是模板测试,先清除上一次绘制产生的模板缓冲,使得缓冲中所有值为0,然后给地板设置模板缓冲的参数,其中设置 glStencilFunc(GL_ALWAYS, 1, 1); 这样一来,地板的像素的“模板值”为1,而其它地方像素的“模板值”为0。glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);这个函数第一个参数是未通过模板测试时的操作,第二个参数是通过模板测试,未通过深度测试的操作,第三个是深度测试和模板测试都通过时的操作。我对这个函数的理解是:当其它物体通过模板测试与深度测试时用其它物体的像素,取代该物体的像素。
//设置模板测试参数
gl.stencilFunc(gl.ALWAYS, 1, 1);
//设置模板测试后的操作
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
然后设置模板参数为equal,当进行比较时,通过比较ref也就是stencilFunc的第二个参数来确定是否通过模板测试,比较的方式是第一个参数也就是equal相等。所以当镜像体篮球在地板范围内时通过模板测试与深度测试,显示镜像。当球体超出地板范围之后模板测试失败,不显示该球体。
//设置模板测试参数
gl.stencilFunc(gl.EQUAL,1, 1);
//设置模板测试后的操作
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
最后是混合当理解了模板测试之后,混合也就更为简单了,我们在绘制地板时,实际是绘制了两次,第一次绘制了不透明度为1的地板,第二次绘制了不透明度为0.5的地板(也就是一个半透明的地板),半透明地板的作用就是参与混合,使得镜像篮球看起来更加真实,不会和实体篮球一样。所以这里使用了混合,目标因子是篮球的颜色,源因子是半透明地板,(用半透明地板去混合篮球,所以篮球是目标因子,地板是源因子)所以该参数的意思是根据(源因子的不透明度:目标因子减原因子的不透明度)这个比例来混合他们的颜色,最终达到镜像效果。
//开启混合
gl.enable(gl.BLEND);
//设置混合因子
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
下面是绘制部分的代码:
function drawFrame()
{
if(!rectdb||!ball)
{
alert("加载未完成!");//提示信息
return;
}
//清除着色缓冲与深度缓冲
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);
//设置模板测试后的操作
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
//绘制镜像体
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();
}
github地址:https://github.com/StringKun/WebGL-mirror-image
热门排行