//----------------------------------------------------------------------------
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);
    }
}
예제 #2
0
//----------------------------------------------------------------------------
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);
}