void CMirror::drawMirrorImage(void (*drawScene)(), const CLighting& lighting) { glClear(GL_STENCIL_BUFFER_BIT); if (showMirror) { // Don't update color or depth. glDisable(GL_DEPTH_TEST); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Draw 1 into the stencil buffer. glEnable(GL_STENCIL_TEST); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); glStencilFunc(GL_ALWAYS, 1, 0xffffffff); // Now render mirror; mirror pixels just get their stencil set to 1. glEnable(GL_CULL_FACE); drawMirror(MIRROR_FRONT); glDisable(GL_CULL_FACE); // Re-enable update of color and depth. glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glEnable(GL_DEPTH_TEST); // Now, only render where stencil is set to 1. glStencilFunc(GL_EQUAL, 1, 0xffffffff); // draw if ==1 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glPushMatrix(); applyReflectionMatrix(); lighting.init(); // mirror light sources drawScene(); // render the reflected scene glPopMatrix(); glDisable(GL_STENCIL_TEST); lighting.init(); // back to the original light sources // Back face culling will get used to only draw either the front side or the // back side of the mirror. This let's us get a mirror with two distinct // appearances. The front surface is reflective and kind of grayish. // The back surface is not reflective and blue. // Draw "back" of mirror in blue. glColor4f(0.1f, 0.1f, 0.5f, 1.0f); glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); drawMirror(MIRROR_BACK); glCullFace(GL_BACK); glDisable(GL_CULL_FACE); // Draw the mirror with stencil value 3. glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 3, 0xffffffff); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // Draw reflective side of mirror. Use blending to blend in reflection. glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(0.9, 0.9, 0.9, 0.3); glCullFace(GL_BACK); drawMirror(MIRROR_FRONT); glDisable(GL_BLEND); drawMirror(MIRROR_BOUNDARY); } }
void MirrorDemo::drawScene() { // Clear the backbuffer and depth buffer. HR(gd3dDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, 0xffeeeeee, 1.0f, 0)); HR(gd3dDevice->BeginScene()); HR(mFX->SetTechnique(mhTech)); HR(mFX->SetValue(mhLightVecW, &mLightVecW, sizeof(D3DXVECTOR3))); HR(mFX->SetValue(mhDiffuseLight, &mDiffuseLight, sizeof(D3DXCOLOR))); HR(mFX->SetValue(mhAmbientLight, &mAmbientLight, sizeof(D3DXCOLOR))); HR(mFX->SetValue(mhSpecularLight, &mSpecularLight, sizeof(D3DXCOLOR))); // All objects use the same material. HR(mFX->SetValue(mhAmbientMtrl, &mWhiteMtrl.ambient, sizeof(D3DXCOLOR))); HR(mFX->SetValue(mhDiffuseMtrl, &mWhiteMtrl.diffuse, sizeof(D3DXCOLOR))); HR(mFX->SetValue(mhSpecularMtrl, &mWhiteMtrl.spec, sizeof(D3DXCOLOR))); HR(mFX->SetFloat(mhSpecularPower, mWhiteMtrl.specPower)); drawRoom(); drawMirror(); drawTeapot(); drawReflectedTeapot(); mGfxStats->display(); HR(gd3dDevice->EndScene()); // Present the backbuffer. HR(gd3dDevice->Present(0, 0, 0, 0)); }
void MirrorDemo::drawReflectedTeapot() { HR(gd3dDevice->SetRenderState(D3DRS_STENCILENABLE, true)); HR(gd3dDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS)); HR(gd3dDevice->SetRenderState(D3DRS_STENCILREF, 0x1)); HR(gd3dDevice->SetRenderState(D3DRS_STENCILMASK, 0xffffffff)); HR(gd3dDevice->SetRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff)); HR(gd3dDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP)); HR(gd3dDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP)); HR(gd3dDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE)); // Disable writes to the depth and back buffers HR(gd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, false)); HR(gd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true)); HR(gd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO)); HR(gd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE)); // Draw mirror to stencil only. drawMirror(); // Re-enable depth writes HR(gd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, true )); // Only draw reflected teapot to the pixels where the mirror // was drawn to. HR(gd3dDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL)); HR(gd3dDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP)); // Build Reflection transformation. D3DXMATRIX R; D3DXPLANE plane(0.0f, 0.0f, 1.0f, 0.0f); // xy plane D3DXMatrixReflect(&R, &plane); // Save the original teapot world matrix. D3DXMATRIX oldTeapotWorld = mTeapotWorld; // Add reflection transform. mTeapotWorld = mTeapotWorld * R; // Reflect light vector also. D3DXVECTOR3 oldLightVecW = mLightVecW; D3DXVec3TransformNormal(&mLightVecW, &mLightVecW, &R); HR(mFX->SetValue(mhLightVecW, &mLightVecW, sizeof(D3DXVECTOR3))); // Disable depth buffer and render the reflected teapot. HR(gd3dDevice->SetRenderState(D3DRS_ZENABLE, false)); HR(gd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false)); // Finally, draw the reflected teapot HR(gd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW)); drawTeapot(); mTeapotWorld = oldTeapotWorld; mLightVecW = oldLightVecW; // Restore render states. HR(gd3dDevice->SetRenderState(D3DRS_ZENABLE, true)); HR(gd3dDevice->SetRenderState( D3DRS_STENCILENABLE, false)); HR(gd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW)); }
void Application::drawScene() { GLenum err; glViewport(0, 0, 2048, 2048); glBindFramebuffer(GL_FRAMEBUFFER, fbo); float back_color[] = { 1, 1, 1, 1 }; float zero[] = { 0.0f, 0.0f, 0.0f, -10.0f }; float one = 1.0f; int zero_int = 0; glClearBufferfv(GL_COLOR, 0, back_color); glClearBufferfv(GL_DEPTH, 0, &one); glClearBufferiv(GL_STENCIL, 0, &zero_int); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glm::mat4* transform_matrices = nullptr; GL_ERROR // ===================================================================== // ===================================================================== // == Rendering the mirror contents // ===================================================================== // ===================================================================== #define RENDER_MIRROR #ifdef RENDER_MIRROR glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); GL_ERROR // Do Masking //glColorMask(0, 0, 0, 0); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); GL_ERROR // Apply the mirror glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_transformation_buffer); transform_matrices = (glm::mat4*)glMapBufferRange(GL_UNIFORM_BUFFER, 0, 3 * sizeof(glm::mat4), GL_MAP_WRITE_BIT); transform_matrices[0] = m_projmat; transform_matrices[1] = m_viewmat; transform_matrices[2] = m_worldmat * glm::mat4( 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f ); glUnmapBuffer(GL_UNIFORM_BUFFER); drawMirror(); // Render Mirrored Triangle glDepthMask(GL_FALSE); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_GREATER); glColorMask(1, 1, 1, 1); glStencilFunc(GL_EQUAL, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // Apply the mirror glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_transformation_buffer); transform_matrices = (glm::mat4*)glMapBufferRange(GL_UNIFORM_BUFFER, 0, 3 * sizeof(glm::mat4), GL_MAP_WRITE_BIT); transform_matrices[0] = m_projmat; transform_matrices[1] = m_viewmat; transform_matrices[2] = m_worldmat * glm::mat4( 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, -5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f ); glUnmapBuffer(GL_UNIFORM_BUFFER); drawTriangle(); GL_ERROR #endif // =================================================================== // =================================================================== // Render main triangle // =================================================================== // =================================================================== glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_transformation_buffer); transform_matrices = (glm::mat4*)glMapBufferRange(GL_UNIFORM_BUFFER, 0, 3 * sizeof(glm::mat4), GL_MAP_WRITE_BIT); transform_matrices[0] = m_projmat; transform_matrices[1] = m_viewmat; transform_matrices[2] = m_worldmat * glm::mat4( 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f ); glUnmapBuffer(GL_UNIFORM_BUFFER); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glDisable(GL_STENCIL_TEST); drawTriangle(); GL_ERROR glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_transformation_buffer); transform_matrices = (glm::mat4*)glMapBufferRange(GL_UNIFORM_BUFFER, 0, 3 * sizeof(glm::mat4), GL_MAP_WRITE_BIT); transform_matrices[0] = m_projmat; transform_matrices[1] = m_viewmat; transform_matrices[2] = m_worldmat; glUnmapBuffer(GL_UNIFORM_BUFFER); GL_ERROR }