使用模板缓冲创建一个镜面反射

昨天那一帖的延续. http://www.dreamfairy.cn/blog/index.php/2013/04/30/stencil-buffer-in-stage3d.html

由于模板缓冲总是在进行的,因此,很多并不想被缓冲的物体也会被牵连,结果就是绘制不出,又或者是错误的也被缓冲了.
那么对于无辜者的那些三角形,在绘制前,我们可以设置一个模板检测方式为总是检测,这样模板总是能检测成功,成功条件为不改变模板值,这样为之后要用到的对象正确的来改变它.

同时,对于不同深度的物体,有时候无法被缓冲,因为有可能是他们确实位于某些面之后,这里我们需要关闭深度缓存再绘制,绘制完毕后,再开启深度缓冲.

那么昨天的 renderScene() 函数要做些修改,并且加上一个作为无辜者的大矩形放在后面.
buffer
[cc lang=”actionscript”]
private function onEnter(e:Event) : void
{
renderScene();
}

private function renderScene() : void
{
m_context.clear(0,0,0,1,1,0);

m_context.setDepthTest(true,Context3DCompareMode.LESS);
m_context.setStencilActions(Context3DTriangleFace.FRONT_AND_BACK,
Context3DCompareMode.ALWAYS, Context3DStencilAction.KEEP);
drawBiggerCube();

m_context.setDepthTest(false,Context3DCompareMode.LESS);
m_context.setStencilReferenceValue(0);
m_context.setStencilActions(Context3DTriangleFace.FRONT_AND_BACK,
Context3DCompareMode.EQUAL, Context3DStencilAction.INCREMENT_SATURATE);

drawCube();

m_context.setStencilReferenceValue(1);

drawTriangle();
m_context.present();
}

private function drawBiggerCube() : void
{
t += .1;
m_modelMatrix.identity();
m_modelMatrix.appendTranslation(0,0,-1);
m_modelMatrix.appendScale(2,2,2);
m_finalMatrix.identity();
m_finalMatrix.append(m_modelMatrix);
m_finalMatrix.append(m_viewMatrix);
m_finalMatrix.append(m_projMatrix);

m_context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX,0,m_finalMatrix,true);

m_context.setProgram(m_textureShader);
m_context.setTextureAt(0,brickTexture);
m_context.setVertexBufferAt(0, m_rectVertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
m_context.setVertexBufferAt(1,m_rectVertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_2);
m_context.drawTriangles(m_rectIndexBuffer,0,2);
}

private function drawTriangle() : void
{
m_modelMatrix.identity();
m_finalMatrix.identity();
m_finalMatrix.append(m_modelMatrix);
m_finalMatrix.append(m_viewMatrix);
m_finalMatrix.append(m_projMatrix);

m_context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX,0,m_finalMatrix,true);

m_context.setProgram(m_shader);
m_context.setTextureAt(0,null);
m_context.setVertexBufferAt(0, m_triangleVertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
m_context.setVertexBufferAt(1,null);
m_context.drawTriangles(m_triangleIndexBuffer,0,1);
}

private var t : Number = 0.0;
private function drawCube() : void
{
t += .1;
m_modelMatrix.identity();
m_modelMatrix.appendTranslation(Math.sin(t),0,0);
m_finalMatrix.identity();
m_finalMatrix.append(m_modelMatrix);
m_finalMatrix.append(m_viewMatrix);
m_finalMatrix.append(m_projMatrix);

m_context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX,0,m_finalMatrix,true);

m_context.setProgram(m_textureShader);
m_context.setTextureAt(0,texture);
m_context.setVertexBufferAt(0, m_rectVertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
m_context.setVertexBufferAt(1,m_rectVertexBuffer, 3, Context3DVertexBufferFormat.FLOAT_2);
m_context.drawTriangles(m_rectIndexBuffer,0,2);
}
[/cc]

好了,接下来,就是今天的重点,镜面反射了.

当物体在镜子内部时:
z1

当物体在镜子外部时,不反射
z2

[cc lang=”actionscript3″]
private function renderScene() : void
{
//还原混合模式
m_context.setBlendFactors(Context3DBlendFactor.ONE,Context3DBlendFactor.ZERO);
//对于不参与的模板测试的三角形,统一都通过测试,但不改变模板值
m_context.setStencilActions(Context3DTriangleFace.BACK,Context3DCompareMode.ALWAYS);
//还原裁剪面
m_context.setCulling(Context3DTriangleFace.FRONT);
//还原深度测试
m_context.setDepthTest(true,Context3DCompareMode.LESS);

m_viewMatrix.pointAt(m_wall.position, CAM_FACING, CAM_UP);
m_cameraMatrix = m_viewMatrix.clone();
m_cameraMatrix.invert();

m_teapot.render(m_cameraMatrix,m_projMatrix,m_shader);
m_teapot.rotation(t, Vector3D.Y_AXIS);
m_wall.render(m_cameraMatrix, m_projMatrix, m_shader);

//关闭深度测试
m_context.setDepthTest(false,Context3DCompareMode.LESS);

//设置模板值为0,之后绘制的三角形会使模板值递增
m_context.setStencilReferenceValue(0);
m_context.setStencilActions(Context3DTriangleFace.BACK,
Context3DCompareMode.EQUAL, Context3DStencilAction.INCREMENT_SATURATE);

m_mirrorMesh.render(m_cameraMatrix,m_projMatrix,m_shader);

m_context.setStencilActions(Context3DTriangleFace.BACK,
Context3DCompareMode.EQUAL, Context3DStencilAction.KEEP);

//混合模式为 1 * dest + 0 * 0 = dest. 目标颜色为镜子颜色和飞船颜色的混合
m_context.setBlendFactors(Context3DBlendFactor.DESTINATION_COLOR, Context3DBlendFactor.ZERO);
m_context.setCulling(Context3DTriangleFace.BACK);
m_context.setStencilReferenceValue(1);

m_mirrorTeapot.render(m_cameraMatrix,m_projMatrix,m_shader);
m_mirrorTeapot.moveTo(m_teapot.position.x,m_teapot.position.y,m_teapot.position.z);
m_mirrorTeapot.rotation(t, Vector3D.Y_AXIS);
}
[/cc]

Demo is here : http://www.dreamfairy.cn/blog/work/flash/3d/stage3dStencilMirror/StencilMirror.html

W,S,A,D移动飞机. 方向键移动相机.

发表评论

电子邮件地址不会被公开。 必填项已用*标注