#include "Main.h" //remind kayvon variance-based shadow maps benefit from antialiasing void ShadowSceneObject::Init(GraphicsDevice &GD, const String &SimplifiedFilename, const String &FullFilename, float _Theta, float _LocalZOffset) { Mesh NewSimplifiedMesh(GD); NewSimplifiedMesh.LoadObj(SimplifiedFilename); Mesh NewFullMesh(GD); NewFullMesh.LoadObj(FullFilename); NewSimplifiedMesh.ApplyMatrix(NewSimplifiedMesh.UnitSphereTransform() * Matrix4::Scaling(3.0f)); NewSimplifiedMesh.ApplyMatrix(Matrix4::Translation(Vec3f::eZ * -NewSimplifiedMesh.BoundingBox().Min.z)); NewFullMesh.ApplyMatrix(NewFullMesh.UnitSphereTransform() * Matrix4::Scaling(3.0f)); NewFullMesh.ApplyMatrix(Matrix4::Translation(Vec3f::eZ * -NewFullMesh.BoundingBox().Min.z)); Init(GD, NewSimplifiedMesh, NewFullMesh, _Theta, _LocalZOffset); } void UpdateMeshTexture(BaseMesh &M) { float XFrequency = 0.5f; float ZFrequency = 0.5f; for(UINT VertexIndex = 0; VertexIndex < M.VertexCount(); VertexIndex++) { MeshVertex &Vtx = M.Vertices()[VertexIndex]; Vtx.TexCoord.x = Vtx.Pos.x * XFrequency; Vtx.TexCoord.y = Vtx.Pos.z * ZFrequency; } } void ShadowSceneObject::Init(GraphicsDevice &GD, const BaseMesh &_SimplifiedMesh, const BaseMesh &_FullMesh, float _Theta, float _LocalZOffset) { LocalZOffset = _LocalZOffset; Theta = _Theta; SimplifiedMesh.SetGD(GD); SimplifiedMesh = _SimplifiedMesh; SimplifiedMesh.Optimize(); FullMesh.SetGD(GD); FullMesh = _FullMesh; FullMesh.Optimize(); UpdateMeshTexture(SimplifiedMesh); UpdateMeshTexture(FullMesh); } void ShadowScene::ResetLight(const Vec3f &LightPos) { _LightCameras[0].Reset(LightPos, Vec3f::eY, LightPos + Vec3f::eX); _LightCameras[1].Reset(LightPos, -Vec3f::eY, LightPos - Vec3f::eX); _LightCameras[2].Reset(LightPos, Vec3f::eZ, LightPos + Vec3f::eY); _LightCameras[3].Reset(LightPos, -Vec3f::eZ, LightPos - Vec3f::eY); _LightCameras[4].Reset(LightPos, Vec3f::eX, LightPos + Vec3f::eZ); _LightCameras[5].Reset(LightPos, -Vec3f::eX, LightPos - Vec3f::eZ); } void ShadowScene::StatusText(AppState &state) { /*String PausedString = "[p] Paused"; if(_Paused) { PausedString = "[p] Not Paused"; } String VarianceString = "[v] Using Normal Shadow Maps"; if(_UseVarianceShadowMaps) { VarianceString = "[v] Using Variance Shadow Maps"; } UINT CurYOffset = 22; state.graphics->DrawString(PausedString, 2, CurYOffset); CurYOffset += 20; O.GetGraphicsDevice().DrawString(VarianceString, 2, CurYOffset); CurYOffset += 20; O.GetGraphicsDevice().DrawInteger("[b] Blur Passes: ", _BlurPasses, 2, CurYOffset); CurYOffset += 20; O.GetGraphicsDevice().DrawString(String("[m] Shadow Map Resolution: ") + String(_ShadowMapResolution) + String("x") + String(_ShadowMapResolution), 2, CurYOffset); CurYOffset += 20;*/ } void ShadowScene::UpdateScene(AppState &state) { if(!_Paused) { _ElapsedTime += state.timer.SPF(); } if(state.input.KeyCheckOnce(KEY_B)) { _BlurPasses = (_BlurPasses + 1) % 5; } if(state.input.KeyCheckOnce(KEY_P)) { _Paused = !_Paused; } if(state.input.KeyCheckOnce(KEY_V)) { _UseVarianceShadowMaps = !_UseVarianceShadowMaps; } if(state.input.KeyCheckOnce(KEY_M)) { /*if(_ShadowMapResolution == 64) { _ShadowMapResolution = 128; } else if(_ShadowMapResolution == 128) { _ShadowMapResolution = 256; } else */ if(_ShadowMapResolution == 256) { _ShadowMapResolution = 512; } else if(_ShadowMapResolution == 512) { _ShadowMapResolution = 1024; } else if(_ShadowMapResolution == 1024) { _ShadowMapResolution = 256; } _ShadowMap.Init(state.graphics->CastD3D9(), _ShadowMapResolution); } if(state.input.KeyCheckOnce(KEY_SPACE)) { _ViewMode = ShadowSceneViewModeType((_ViewMode + 1) % ShadowSceneViewModeCount); ResetLight(Vec3f(0.0f, 0.0f, 2.25f)); /*Vec3f LightPos = Vec3f(pmrnd() * 2.0f, pmrnd() * 2.0f, 0.5f + rnd() * 2.0f); _LightCameras[0].Reset(LightPos, Vec3f::eY, LightPos + Vec3f::eX); _LightCameras[1].Reset(LightPos, -Vec3f::eY, LightPos - Vec3f::eX); _LightCameras[2].Reset(LightPos, Vec3f::eZ, LightPos + Vec3f::eY); _LightCameras[3].Reset(LightPos, -Vec3f::eZ, LightPos - Vec3f::eY); _LightCameras[4].Reset(LightPos, Vec3f::eX, LightPos + Vec3f::eZ); _LightCameras[5].Reset(LightPos, -Vec3f::eX, LightPos - Vec3f::eZ); _LightCameras[0].Reset(Vec3f(2.0f * pmrnd(), 2.0f * pmrnd(), 1.5f + rnd()), Vec3f::eZ, Vec3f::Origin);*/ } if(_ViewMode == ShadowSceneViewModeLightRotatingAroundObjects) { float RotationTheta = _ElapsedTime * 1.0f; float HeightTheta = _ElapsedTime * 1.4f; const float LightRadius = 7.0f; const float MinLightHeight = 2.5f; const float MaxLightHeight = 5.0f; Vec3f LightPos = Vec3f(cosf(RotationTheta) * LightRadius, sinf(RotationTheta) * LightRadius, (cosf(HeightTheta) * 0.5f + 0.5f) * (MaxLightHeight - MinLightHeight) + MinLightHeight); ResetLight(LightPos); } } void ShadowScene::Init(D3D9GraphicsDevice &GD) { _Paused = false; _BlurPasses = 1; _ShadowMapResolution = 512; _UseVarianceShadowMaps = true; _Timer.Start(); _ElapsedTime = 0.0f; _LightPerspective = Matrix4::PerspectiveFov(110.0f * Math::PIf / 180.0f, 1.0f, 0.1f, 100.0f); _ViewMode = ShadowSceneViewModeLightRotatingAroundObjects; ResetLight(Vec3f(0.0f, 0.0f, 2.25f)); _Objects[0].Init(GD, "C:\\Data\\Models\\buddha10k.obj", "C:\\Data\\Models\\buddha.obj", 0.0f / 3.0f * Math::PIf * 2.0f, Math::PIf); _Objects[1].Init(GD, "C:\\Data\\Models\\bunny10k.obj", "C:\\Data\\Models\\bunny.obj", 1.0f / 3.0f * Math::PIf * 2.0f, Math::PIf); _Objects[2].Init(GD, "C:\\Data\\Models\\dragon10k.obj", "C:\\Data\\Models\\dragon.obj", 2.0f / 3.0f * Math::PIf * 2.0f, 0.0f); //_Torus.Translate(Vec3f(0.0f, 0.0f, 0.75f)); for(UINT BoxWallIndex = 0; BoxWallIndex < 6; BoxWallIndex++) { _BoxWalls[BoxWallIndex].SetGD(GD); _BoxTextures[BoxWallIndex].Init(GD); _BoxTextureRepeat[BoxWallIndex] = Vec3f(1.0f, 1.0f, 0.0f); } _WoodTexture.Init(GD); const float BoxSideLength = 15.0f; const float BoxHeight = 8.0f; const UINT BoxTessellation = 20; _BoxWalls[0].CreatePlane(Vec3f(-BoxSideLength, -BoxSideLength, 0.0f), Vec3f(BoxSideLength, BoxSideLength, 0.0f), BoxTessellation, BoxTessellation); _BoxWalls[1].CreatePlane(Vec3f(-BoxSideLength, -BoxSideLength, 0.0f), Vec3f(BoxSideLength, -BoxSideLength, BoxHeight), BoxTessellation, BoxTessellation); _BoxWalls[2].CreatePlane(Vec3f(-BoxSideLength, -BoxSideLength, 0.0f), Vec3f(-BoxSideLength, BoxSideLength, BoxHeight), BoxTessellation, BoxTessellation); _BoxWalls[3].CreatePlane(Vec3f(-BoxSideLength, -BoxSideLength, BoxHeight), Vec3f(BoxSideLength, BoxSideLength, BoxHeight), BoxTessellation, BoxTessellation); _BoxWalls[4].CreatePlane(Vec3f(-BoxSideLength, BoxSideLength, 0.0f), Vec3f(BoxSideLength, BoxSideLength, BoxHeight), BoxTessellation, BoxTessellation); _BoxWalls[5].CreatePlane(Vec3f(BoxSideLength, -BoxSideLength, 0.0f), Vec3f(BoxSideLength, BoxSideLength, BoxHeight), BoxTessellation, BoxTessellation); Bitmap Bmp; Bmp.LoadPNG("Assets\\Ceiling.png"); _BoxTextures[3].Load(Bmp); Bmp.LoadPNG("Assets\\Floor.png"); _BoxTextures[0].Load(Bmp); Bmp.LoadPNG("Assets\\Wall.png"); _BoxTextures[1].Load(Bmp); _BoxTextures[2].Load(Bmp); _BoxTextures[4].Load(Bmp); _BoxTextures[5].Load(Bmp); Bmp.LoadPNG("Assets\\Wood.png"); _WoodTexture.Load(Bmp); _BoxTextureRepeat[3] = Vec3f(5.0f, 5.0f, 0.0f); _BoxTextureRepeat[0] = Vec3f(2.0f, 2.0f, 0.0f); for(UINT BoxWallIndex = 0; BoxWallIndex < 6; BoxWallIndex++) { _BoxWalls[BoxWallIndex].GCNormals(); } } void ShadowScene::RenderFrame(D3D9GraphicsDevice &GD, MatrixController &MC) { IDirect3DDevice9 *Device = GD.GetDevice(); MatrixController LightMC; LightMC.Perspective = _LightPerspective; for(UINT ShadowMapIndex = 0; ShadowMapIndex < ShadowMapCount; ShadowMapIndex++) { D3D9ProtectRenderTarget Protector(Device, true, true); _ShadowMap.SetAsRenderTarget(ShadowMapIndex, Device); LightMC.View = _LightCameras[ShadowMapIndex].Matrix(); RenderScene(GD, LightMC, ShadowMapShaderCreate); } for(UINT Index = 0; Index < _BlurPasses; Index++) { _ShadowMap.BlurAllShadowMaps(Device); } _ShadowMap.SetAsTextures(Device); for(UINT ShadowMapIndex = 0; ShadowMapIndex < ShadowMapCount; ShadowMapIndex++) { Device->SetSamplerState(ShadowMapIndex + 1, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(ShadowMapIndex + 1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(ShadowMapIndex + 1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(ShadowMapIndex + 1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); Device->SetSamplerState(ShadowMapIndex + 1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); _ShadowMap.SetLightMatrices(ShadowMapIndex, _LightCameras[ShadowMapIndex], _LightPerspective); } RenderScene(GD, MC, ShadowMapShaderRender); } void ShadowScene::RenderScene(D3D9GraphicsDevice &GD, MatrixController &MC, ShadowMapShaderType Shader) { IDirect3DDevice9 *Device = GD.GetDevice(); Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC); Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC); Device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); Device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); MC.World = Matrix4::Identity(); _ShadowMap.SetCameraMatrices(MC, Shader); for(UINT BoxWallIndex = 0; BoxWallIndex < 6; BoxWallIndex++) { _BoxTextures[BoxWallIndex].Set(0); _ShadowMap._VShaderRender.SetVec3("TextureRepeat", _BoxTextureRepeat[BoxWallIndex]); _ShadowMap._PShaderRender.SetFloat("LightTermMinValue", 1.0f); _BoxWalls[BoxWallIndex].Render(); } Device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR); Device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_MIRROR); _WoodTexture.Set(0); float LocalRotationTheta = 0.0f; float OrbitalRotationTheta = 0.0f; float ObjectRadius = 0.0f; if(_ViewMode == ShadowSceneViewModeObjectsRotatingAroundLight) { LocalRotationTheta = _ElapsedTime * 1.647f; OrbitalRotationTheta = _ElapsedTime * 1.0f; ObjectRadius = 7.0f; } else if(_ViewMode == ShadowSceneViewModeLightRotatingAroundObjects) { LocalRotationTheta = 1.2f; ObjectRadius = 5.0f; } for(UINT ObjectIndex = 0; ObjectIndex < ShadowSceneObjectCount; ObjectIndex++) { const ShadowSceneObject &CurObject = _Objects[ObjectIndex]; Matrix4 LocalRotation = Matrix4::RotationZ(LocalRotationTheta + CurObject.LocalZOffset); Matrix4 Translation = Matrix4::Translation(Vec3f::eX * ObjectRadius); Matrix4 OrbitalRotation = Matrix4::RotationZ(CurObject.Theta + OrbitalRotationTheta); MC.World = LocalRotation * Translation * OrbitalRotation; _ShadowMap.SetCameraMatrices(MC, Shader); _ShadowMap._VShaderRender.SetVec3("TextureRepeat", Vec3f(1.0f, 1.0f, 1.0f)); _ShadowMap._PShaderRender.SetFloat("LightTermMinValue", 0.4f); if(Shader == ShadowMapShaderCreate) { CurObject.SimplifiedMesh.Render(); } else if(Shader == ShadowMapShaderRender) { CurObject.FullMesh.Render(); } } } void ShadowScene::RenderLight(D3D9GraphicsDevice &GD) { }