WebGL中Stencil Buffer的运用以及ThreeJS的实现
Posted 奴彼的笔记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebGL中Stencil Buffer的运用以及ThreeJS的实现相关的知识,希望对你有一定的参考价值。
这是从七月份开始就没有更新文章了啊...不知道仅有的几位读者还在不在?
整理一下上周遇到的问题:Stencil Buffer(模板缓冲区)
据OpenGL红皮书中描述,OpenGL大致存在四种缓冲区:
颜色缓冲区(Color Buffer):用于绘图的缓冲区,包含了颜色索引或者RGBA数据;
深度缓冲区(Depth Buffer):存储每个像素的深度值,当启用深度测试的时候,片段像素深度值和深度缓冲区的深度值进行比较,决定片段的哪些像素点可以替换到颜色缓冲区中。
模板缓冲区(Stencil Buffer):与颜色缓冲区和深度缓冲区类似,模板缓冲区可以为屏幕上的每个像素点保存一个无符号整数值。这个值的具体意义视程序的具体应用而定。在渲染的过程中,可以用这个值与一个预先设定的参考值相比较,根据比较的结果来决定是否更新相应的像素点的颜色值。这个比较的过程被称为模板测试。模板测试发生在透明度测试(alpha test)之后,深度测试(depth test)之前。如果模板测试通过,则相应的像素点更新,否则不更新。就像使用纸板和喷漆一样精确的混图一样,当启动模板测试时,通过模板测试的片段像素点会被替换到颜色缓冲区中,从而显示出来,未通过的则不会保存到颜色缓冲区中,从而达到了过滤的功能。
累积缓冲区(Accumulate Buffer):累积缓冲区允许你把渲染到颜色缓冲区的值,拷贝到累积缓冲区。在多次拷贝操作到累积缓冲区时,可以用不同方式的把颜色缓冲区内容和当前累积缓冲区的内容进行重复混合。
那么说到底,Stencil Buffer的一个主要应用就是画模板,在模板区域内显示内容。比如说第一人称的赛车游戏,玩家视角中车窗始终显示在屏幕上,但是窗子里的内容是随着车子的移动而发生变化的。这个时候,Stencil Buffer的运用将会节省游戏设计的很多时间。
下面是ThreeJS中模板缓冲区应用的实例:
例子中画面的背景为:
实例中画了一个旋转的立方体为模板,利用Stencil Buffer因此只显示立方体内部的部分。
那么ThreeJS是如何实现的呢?——Post Processing
Post Processing 可以为场景增加新的特效,提高整个场景的视觉效果。在Post Processing过程中,首先创建一个EffectComposer。可以通过EffectComposer的AddPass成员函数添加Passes,Passes是我们定义的渲染序列。EffectComposer的第一个参数通常是之前定义的renderer,第二个参数为可选参数,通常是一个不同于renderer的Render Target。这个Composer会在update中取代以往的renderer.render(camera,scene);
var composer = new THREE.EffectComposer(renderer);
//NOTE: this goes in your render loop
composer.render();
关于Passes,通常有Render Pass 、Shader Pass以及Texture Pass。
Render Pass这个通道为我们需要正常显示场景的通道,也就是说这个通道里的物体是正常被绘制在屏幕上的。
var renderPass = new THREE.RenderPass(scene, camera);
composer.addPass(renderPass);
Shader Pass顾名思义,对上层pass的着色处理。ThreeJS提供了一些基本的Shader,也可以在应用程序中定义自己的shader。
var shaderPass = new THREE.ShaderPass(THREE.SepiaShader);
composer.addPass(shaderPass);
Texture Pass简单地将纹理以背景的形式画到渲染序列中。
var texturePass = new THREE.TexturePass(map, opacity);
composer.addPass(texturePass);
还有很多例如ClearPass、MaskPass以及SavePass的通道,都有各自的意义。而涉及到遮罩处理的是MaskPass,通过启用Stencil buffer来实现遮罩功能。
ThreeJS详细实现流程:(我又不愿意解释了,先放着吧,有疑问再修改)
var renderpass = new THREE.RenderPass(scene, camera);
var outputPass = new THREE.ShaderPass(THREE.CopyShader);
//important 不能自动清除
renderpass.clear = false;
var clearPass = new THREE.ClearPass();
var clearMaskPass = new THREE.ClearMaskPass();
var maskPass1 = new THREE.MaskPass(scene1, camera);
maskPass1.inverse = true;
outputPass.renderToScreen = true;
var parameters = {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBFormat,
stencilBuffer: true
};
renderTarget = new THREE.WebGLRenderTarget(window.innerWidth * 2,
window.innerHeight * 2, parameters);
composer = new THREE.EffectComposer(renderer, renderTarget);
composer.addPass(clearPass);
composer.addPass(maskPass1);
composer.addPass(renderpass);
composer.addPass(clearMaskPass);
composer.addPass(outputPass);
~Happy End~
以上是关于WebGL中Stencil Buffer的运用以及ThreeJS的实现的主要内容,如果未能解决你的问题,请参考以下文章
OpenGL Stencil Buffer,它们的支持程度如何?