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

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

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

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

那么昨天的 renderScene() 函数要做些修改,并且加上一个作为无辜者的大矩形放在后面.
buffer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
        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);
        }

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

当物体在镜子内部时:
z1

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
        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);
        }

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

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

发表评论

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.