Anyway, the latest addition to my source code collection is my Stencil class.
Using the relevant chapters in 'Introduction to 3D Game Programming' by Frank Luna I have built up a stencil class to handle reflections and shadows. At least at a basic level with room for growth.
Here is the resulting output of my project with the stencil class in use:
There is a slight problem with the shadowing technique but I am sure that will get worked out in due course.
For those interested here is a snipping of my Stencil class functionality:
#pragma once#include #include "DirectXObject.h"class CDXStencil : public IDirectXObject{public: enum enStencilType { Reflection = 0x0001, Shadow = Reflection << 1, Nothing = 0xFFFF };protected: enStencilType m_enType;private:public: CDXStencil(IDirect3DDevice9* pDevice, enStencilType enType); ~CDXStencil(); bool Initialise(void); void DeInitialise(void); void Start(void); // Sets the Stencil render states void End(void); // Restores the render states void SetReflectionStates(); // Sets the Reflection special states D3DXMATRIX GetShadowMatrix(float ax, float by, float cz, float dw, D3DXVECTOR3 lDirection, float lType); D3DXMATRIX GetReflectiveMatrix(float ax, float by, float cz, float dw);};
As you can see from the header file there isn't much to work with but this is how the class is used within a project:
// DeclareCDXStencil* gpReflection = NULL;CDXStencil* gpShadow = NULL;// CreategpReflection = new CDXStencil(gpDirectX->Device(),CDXStencil::Reflection);gpShadow = new CDXStencil(gpDirectX->Device(),CDXStencil::Shadow);// Use// Draw Normal SceneDrawTeapot(false,false);DrawMirror();DrawFloor();// End of Normal Scene// Draw Shadow ScenegpShadow->Start();DrawTeapot(false,true);gpShadow->End();// End of Shadow Scene// Draw Reflection ScenegpReflection->Start();DrawMirror();gpReflection->SetReflectionStates();DrawTeapot(true,false);gpReflection->End();// End of Reflection Scene// Finished withdelete gpShadow;delete gpReflection;
The DrawTeapot routine is where the fancy work is utilised:
// draw teapotgpTeapotWorld->Initialise();gpTeapotWorld->Position(TeapotPosition);gpMaterial->SetColor(true,true,true,true,1.0f,1.0f,1.0f,0.0f);if (bReflection) { gpMaterial->SetColor(true,true,true,true,0.8f,0.8f,0.8f,0.0f); gpTeapotWorld->Reflection(gpReflection->GetReflectiveMatrix(0.0f,0.0f,1.0f,0.0f));}if (bShadow) { gpMaterial->SetColor(true,true,true,true,0.2f,0.2f,0.2f,0.0f); gpTeapotWorld->Shadow(gpShadow->GetShadowMatrix(0.0f,-1.0f,0.0f,0.0f,D3DXVECTOR3(0.0f,-1.0f,-1.0f),0.0f));}gpTeapotWorld->UpdateWorld();gpMaterial->Use();gpTexture->StopUsing(0);gpTeapot->DrawSubset(0);
TeapotWorld is an instance of the WorldObject class I use to handle the Matrix Transformations for each object that requires it.
The code for the GetReflective and GetShadow routines are as follows:
D3DXMATRIX CDXStencil::GetReflectiveMatrix(float ax, float by, float cz, float dw){ D3DXMATRIX matReflection; D3DXPLANE plane(ax, by, cz, dw); // xy plane D3DXPlaneNormalize(&plane,&plane); D3DXMatrixReflect(&matReflection, &plane); return matReflection;}D3DXMATRIX CDXStencil::GetShadowMatrix(float ax, float by, float cz, float dw, D3DXVECTOR3 lDirection, float lType){ D3DXMATRIX matShadow; D3DXVECTOR4 lightDirection; lightDirection.x = lDirection.x; lightDirection.y = lDirection.y; lightDirection.z = lDirection.z; lightDirection.w = lType; D3DXPLANE plane(ax,by,cz,dw); D3DXPlaneNormalize(&plane,&plane); D3DXMatrixShadow(&matShadow,&lightDirection,&plane); return matShadow;}
Now to post the query regarding the shadow offset.