//---------------------------------------------------------------------------- void SMShadowEffect::Draw (Renderer* renderer, const VisibleSet& visibleSet) { const int numVisible = visibleSet.GetNumVisible(); for (int j = 0; j < numVisible; ++j) { // Replace the object's effect instance by the shadow-effect instance. Visual* visual = (Visual*)visibleSet.GetVisible(j); VisualEffectInstancePtr save = visual->GetEffectInstance(); visual->SetEffectInstance(mInstance); // Draw the object using the shadow effect. renderer->Draw(visual); // Restore the object's effect instance. visual->SetEffectInstance(save); } }
//---------------------------------------------------------------------------- void PlanarShadowEffect::Draw (Renderer* renderer, const VisibleSet& visibleSet) { // Draw the potentially visible portions of the shadow caster. const int numVisible = visibleSet.GetNumVisible(); int j; for (j = 0; j < numVisible; ++j) { renderer->Draw((const Visual*)visibleSet.GetVisible(j)); } // Save the current global state overrides for restoration later. const DepthState* saveDState = renderer->GetOverrideDepthState(); const StencilState* saveSState = renderer->GetOverrideStencilState(); // Override the global state to support this effect. renderer->SetOverrideDepthState(mDepthState); renderer->SetOverrideStencilState(mStencilState); // Get the camera to store post-world transformations. Camera* camera = renderer->GetCamera(); for (int i = 0; i < mNumPlanes; ++i) { // Enable depth buffering. NOTE: The plane object should not have a // ZBufferState object that changes the current settings. mDepthState->Enabled = true; mDepthState->Writable = true; mDepthState->Compare = DepthState::CM_LEQUAL; // Enable the stencil buffer so that the shadow can be clipped by the // plane. The stencil values are set whenever the corresponding // plane pixels are visible. mStencilState->Enabled = true; mStencilState->Compare = StencilState::CM_ALWAYS; mStencilState->Reference = (unsigned int)(i + 1); mStencilState->OnFail = StencilState::OT_KEEP; // irrelevant mStencilState->OnZFail = StencilState::OT_KEEP; // invisible to 0 mStencilState->OnZPass = StencilState::OT_REPLACE; // visible to i+1 // Draw the plane. renderer->Draw(mPlanes[i]); // Blend the shadow color with the pixels drawn on the projection // plane. The blending equation is // (rf,gf,bf) = as*(rs,gs,bs) + (1-as)*(rd,gd,bd) // where (rf,gf,bf) is the final color to be written to the frame // buffer, (rs,gs,bs,as) is the shadow color, and (rd,gd,bd) is the // current color of the frame buffer. const AlphaState* saveAState = renderer->GetOverrideAlphaState(); renderer->SetOverrideAlphaState(mAlphaState); mAlphaState->BlendEnabled = true; mAlphaState->SrcBlend = AlphaState::SBM_SRC_ALPHA; mAlphaState->DstBlend = AlphaState::DBM_ONE_MINUS_SRC_ALPHA; mMaterial->Diffuse = mShadowColors[i]; // Disable the depth buffer reading so that no depth-buffer fighting // occurs. The drawing of pixels is controlled solely by the stencil // value. mDepthState->Enabled = false; // Only draw where the plane has been drawn. mStencilState->Enabled = true; mStencilState->Compare = StencilState::CM_EQUAL; mStencilState->Reference = (unsigned int)(i + 1); mStencilState->OnFail = StencilState::OT_KEEP; // invisible kept 0 mStencilState->OnZFail = StencilState::OT_KEEP; // irrelevant mStencilState->OnZPass = StencilState::OT_ZERO; // visible set to 0 // Get the projection matrix relative to the projector (light). HMatrix projection; if (!GetProjectionMatrix(i, projection)) { continue; } camera->SetPreViewMatrix(projection); // Draw the caster again, but temporarily use a material effect so // that the shadow color is blended onto the plane. TODO: This // drawing pass should use a VisibleSet relative to the projector so // that objects that are out of view (i.e. culled relative to the // camera and not in the camera's VisibleSet) can cast shadows. for (j = 0; j < numVisible; ++j) { Visual* visual = (Visual*)visibleSet.GetVisible(j); VisualEffectInstancePtr save = visual->GetEffectInstance(); visual->SetEffectInstance(mMaterialEffectInstance); renderer->Draw(visual); visual->SetEffectInstance(save); } camera->SetPreViewMatrix(HMatrix::IDENTITY); renderer->SetOverrideAlphaState(saveAState); } // Restore the global state that existed before this function call. renderer->SetOverrideStencilState(saveSState); renderer->SetOverrideDepthState(saveDState); }