図0023a
1、シャドウマップを書き込みむ方法 2、シャドウマップを受け止め、描画する方法 3、シャドウマップの細かさ
void GameStage::OnCreate() {
//描画デバイスの取得
auto Dev = App::GetApp()->GetDeviceResources();
Dev->GetShadowMapRenderTarget(2048.0f);
//中略
//プレイヤーの作成
AddGameObject<Player>(
18,
L"TRACE_TX",
true,
Vec3(0.0f, 0.125f, 0.0f)
);
//シャドウマップ描画オブジェクトの作成
AddGameObject<ShadowmapDrawObject>();
//PNT描画オブジェクトの作成
AddGameObject<PNTDrawObject>();
//PNTシャドウ描画オブジェクトの作成
AddGameObject<PNTShadowDrawObject>();
//中略
}
void GameStage::OnDrawStage() {
//描画デバイスの取得
auto Dev = App::GetApp()->GetDeviceResources();
Dev->ClearDefaultViews(Col4(0, 0, 0, 1.0f));
Dev->ClearShadowmapViews();
Dev->StartShadowmapDraw();
for (auto& v : GetGameObjectVec()) {
//各オブジェクトの描画
v->OnDrawShadowmap();
}
Dev->EndShadowmapDraw();
//デフォルト描画の開始
Dev->StartDefaultDraw();
for (auto& v : GetGameObjectVec()) {
//各オブジェクトの描画
v->OnDraw();
}
//自分自身の描画
this->OnDraw();
//デフォルト描画の終了
Dev->EndDefaultDraw();
}
void Player::OnDrawShadowmap() {
auto PtrGameStage = GetStage<GameStage>();
//ワールド行列の決定
Mat4x4 World;
World.affineTransformation(m_Scale, Vec3(0, 0, 0),
m_Qt, m_Pos);
auto shptr
= PtrGameStage->FindTagGameObject<ShadowmapDrawObject>(L"ShadowmapDrawObject");
shptr->AddDrawMesh(
m_SphereMesh,
World
);
}
template<typename T> shared_ptr<T> FindTagGameObject(const wstring& TagName) const { for (auto& v : GetGameObjectVec()) { if (v->FindTag(TagName)) { auto shptr = dynamic_pointer_cast<T>(v); if (shptr) { return shptr; } } } throw BaseException( L"オブジェクトが見つかりません", TagName, L"Stage::FindGameObject()" ); return nullptr; }
1、ShadowmapDrawObjectクラス 2、PNTDrawObjectクラス 3、PNTShadowDrawObjectクラス
//-------------------------------------------------------------------------------------- /// シャドウマップ描画に使用する構造体 //-------------------------------------------------------------------------------------- struct ShadowmapObject { shared_ptr<MeshResource> m_MeshRes; Mat4x4 m_WorldMatrix; ShadowmapObject() : m_MeshRes(nullptr), m_WorldMatrix() {} }; //-------------------------------------------------------------------------------------- /// シャドウマップの描画クラス //-------------------------------------------------------------------------------------- class ShadowmapDrawObject : public GameObject { vector<ShadowmapObject> m_ShadowmapObjectVec; public: static float m_LightHeight; //ライトの高さ(向きをこの値で掛ける) static float m_LightNear; //ライトのNear static float m_LightFar; //ライトのFar static float m_ViewWidth; static float m_ViewHeight; //-------------------------------------------------------------------------------------- /*! @brief コンストラクタ @param[in] StagePtr ステージのポインタ */ //-------------------------------------------------------------------------------------- ShadowmapDrawObject(const shared_ptr<Stage>& StagePtr); //-------------------------------------------------------------------------------------- /*! @brief デストラクタ */ //-------------------------------------------------------------------------------------- virtual ~ShadowmapDrawObject(); //-------------------------------------------------------------------------------------- /*! @brief 描画するオブジェクトを追加する @param[in] MeshRes メッシュ @param[in] WorldMat ワールド行列 @return なし */ //-------------------------------------------------------------------------------------- void AddDrawMesh(const shared_ptr<MeshResource>& MeshRes, const Mat4x4& WorldMat); //-------------------------------------------------------------------------------------- /*! @brief 初期化 @return なし */ //-------------------------------------------------------------------------------------- virtual void OnCreate() override; //-------------------------------------------------------------------------------------- /*! @brief 更新 @return なし */ //-------------------------------------------------------------------------------------- virtual void OnUpdate()override; //-------------------------------------------------------------------------------------- /*! @brief シャドウマップの描画処理(仮想関数) @return なし */ //-------------------------------------------------------------------------------------- virtual void OnDrawShadowmap() override; //-------------------------------------------------------------------------------------- /*! @brief 描画 @return なし */ //-------------------------------------------------------------------------------------- virtual void OnDraw()override {} };
void ShadowmapDrawObject::AddDrawMesh(const shared_ptr<MeshResource>& MeshRes, const Mat4x4& WorldMat) { ShadowmapObject Obj; Obj.m_MeshRes = MeshRes; Obj.m_WorldMatrix = WorldMat; m_ShadowmapObjectVec.push_back(Obj); }
void ShadowmapDrawObject::OnDrawShadowmap() { auto PtrGameStage = GetStage<GameStage>(); auto Dev = App::GetApp()->GetDeviceResources(); auto pID3D11DeviceContext = Dev->GetD3DDeviceContext(); auto RenderState = Dev->GetRenderState(); //各オブジェクト共通処理 //シェーダの設定 //頂点シェーダーのセット pID3D11DeviceContext->VSSetShader(VSShadowmap::GetPtr()->GetShader(), nullptr, 0); //ピクセルシェーダはセットしない! pID3D11DeviceContext->PSSetShader(nullptr, nullptr, 0); //ジオメトリシェーダの設定(使用しない) pID3D11DeviceContext->GSSetShader(nullptr, nullptr, 0); //インプットレイアウトのセット pID3D11DeviceContext->IASetInputLayout(VSShadowmap::GetPtr()->GetInputLayout()); //描画方法(3角形) pID3D11DeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); //ストライドとオフセット UINT stride = sizeof(VertexPositionNormalTexture); UINT offset = 0; //個別処理 for (auto& v : m_ShadowmapObjectVec) { //位置の取得 auto Pos = v.m_WorldMatrix.transInMatrix(); Vec4 LightDir4; PtrGameStage->GetLightDir(LightDir4); Vec3 LightDir(LightDir4.x, LightDir4.y, LightDir4.z); Vec3 PosSpan = LightDir; PosSpan *= 0.1f; Pos += PosSpan; //行列の定義 Mat4x4 World, LightView, LightProj; //ワールド行列の決定 World.affineTransformation( v.m_WorldMatrix.scaleInMatrix(), //スケーリング Vec3(0, 0, 0), //回転の中心(重心) v.m_WorldMatrix.quatInMatrix(), //回転角度 Pos //位置 ); LightDir = LightDir * -1.0; Vec3 LightAt = PtrGameStage->GetCamera().m_CamerAt; Vec3 LightEye = LightAt + (LightDir * m_LightHeight); //ライトのビューと射影を計算 LightView = XMMatrixLookAtLH(LightEye, LightAt, Vec3(0, 1.0f, 0)); LightProj = XMMatrixOrthographicLH(m_ViewWidth, m_ViewHeight, m_LightNear, m_LightFar); ShadowConstants Cb; Cb.mWorld = bsm::transpose(World); Cb.mView = bsm::transpose(LightView); Cb.mProj = bsm::transpose(LightProj); //コンスタントバッファの更新 pID3D11DeviceContext->UpdateSubresource(CBShadow::GetPtr()->GetBuffer(), 0, nullptr, &Cb, 0, 0); //頂点バッファをセット pID3D11DeviceContext->IASetVertexBuffers(0, 1, v.m_MeshRes->GetVertexBuffer().GetAddressOf(), &stride, &offset); //インデックスバッファのセット pID3D11DeviceContext->IASetIndexBuffer(v.m_MeshRes->GetIndexBuffer().Get(), DXGI_FORMAT_R16_UINT, 0); //コンスタントバッファの設定 ID3D11Buffer* pConstantBuffer = CBShadow::GetPtr()->GetBuffer(); ID3D11Buffer* pNullConstantBuffer = nullptr; pID3D11DeviceContext->VSSetConstantBuffers(0, 1, &pConstantBuffer); //コンスタントバッファをピクセルシェーダにセット pID3D11DeviceContext->PSSetConstantBuffers(0, 1, &pNullConstantBuffer); //描画 pID3D11DeviceContext->DrawIndexed(v.m_MeshRes->GetNumIndicis(), 0, 0); } //後始末 Dev->InitializeStates(); m_ShadowmapObjectVec.clear(); }
//頂点シェーダーのセット
pID3D11DeviceContext->VSSetShader(VSShadowmap::GetPtr()->GetShader(), nullptr, 0);
struct PNTStaticShadowConstantBuffer { bsm::Mat4x4 World; bsm::Mat4x4 View; bsm::Mat4x4 Projection; bsm::Col4 Emissive; bsm::Col4 Diffuse; bsm::Vec4 LightDir; bsm::Vec4 LightPos; bsm::Vec4 EyePos; bsm::Mat4x4 LightView; bsm::Mat4x4 LightProjection; PNTStaticShadowConstantBuffer() { memset(this, 0, sizeof(PNTStaticShadowConstantBuffer)); Diffuse = bsm::Col4(1.0f, 1.0f, 1.0f, 1.0f); }; };
void PNTShadowDrawObject::SetConstants(DrawObject& DrawObj, PNTStaticShadowConstantBuffer& Cb) { auto PtrGameStage = GetStage<GameStage>(); //行列の定義 bsm::Mat4x4 World, ViewMat, ProjMat; //ワールド行列の決定 World = DrawObj.m_WorldMatrix; //転置する World.transpose(); //カメラを得る PtrGameStage->GetCamera().GetViewProjMatrix(ViewMat, ProjMat); Vec4 LightDir; PtrGameStage->GetLightDir(LightDir); //転置する ViewMat.transpose(); //転置する ProjMat.transpose(); Cb.World = World; Cb.View = ViewMat; Cb.Projection = ProjMat; //ディフューズ Cb.Diffuse = Col4(1.0f, 1.0f, 1.0f, 1.0f); //エミッシブ加算。 Cb.Emissive = Col4(0.4f, 0.4f, 0.4f, 0); //ライティング Cb.LightDir = LightDir; Cb.LightDir.w = 1.0f; Cb.EyePos = PtrGameStage->GetCamera().m_CamerEye; Cb.EyePos.w = 1.0f; Vec3 CalcLightDir(LightDir.x, LightDir.y, LightDir.z); CalcLightDir = -1.0 * CalcLightDir; Vec3 LightAt = PtrGameStage->GetCamera().m_CamerAt; Vec3 LightEye = CalcLightDir; auto ShadowObj = PtrGameStage->FindTagGameObject<ShadowmapDrawObject>(L"ShadowmapDrawObject"); LightEye *= ShadowmapDrawObject::m_LightHeight; LightEye = LightAt + LightEye; Cb.LightPos = LightEye; Cb.LightPos.w = 1.0f; bsm::Mat4x4 LightView, LightProj; //ライトのビューと射影を計算 LightView = XMMatrixLookAtLH(LightEye, LightAt, Vec3(0, 1.0f, 0)); LightProj = XMMatrixOrthographicLH(ShadowmapDrawObject::m_ViewWidth, ShadowmapDrawObject::m_ViewHeight, ShadowmapDrawObject::m_LightNear, ShadowmapDrawObject::m_LightFar); Cb.LightView = bsm::transpose(LightView); Cb.LightProjection = bsm::transpose(LightProj); }
void PNTShadowDrawObject::OnDraw() { auto PtrGameStage = GetStage<GameStage>(); auto Dev = App::GetApp()->GetDeviceResources(); auto pD3D11DeviceContext = Dev->GetD3DDeviceContext(); auto RenderState = Dev->GetRenderState(); //サンプラーの準備 ID3D11SamplerState* pSamplerClamp = RenderState->GetLinearClamp(); ID3D11SamplerState* pSamplerWrap = RenderState->GetLinearWrap(); //個別処理 for (auto& v : m_DrawObjectVec) { //コンスタントバッファの準備 PNTStaticShadowConstantBuffer Cb; SetConstants(v, Cb); //テクスチャ pD3D11DeviceContext->PSSetShaderResources(0, 1, v.m_TextureRes->GetShaderResourceView().GetAddressOf()); //コンスタントバッファの更新 pD3D11DeviceContext->UpdateSubresource(CBPNTStaticShadow::GetPtr()->GetBuffer(), 0, nullptr, &Cb, 0, 0); //ストライドとオフセット UINT stride = v.m_MeshRes->GetNumStride(); UINT offset = 0; //頂点バッファのセット pD3D11DeviceContext->IASetVertexBuffers(0, 1, v.m_MeshRes->GetVertexBuffer().GetAddressOf(), &stride, &offset); //インデックスバッファのセット pD3D11DeviceContext->IASetIndexBuffer(v.m_MeshRes->GetIndexBuffer().Get(), DXGI_FORMAT_R16_UINT, 0); //描画方法(3角形) pD3D11DeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); //コンスタントバッファの設定 ID3D11Buffer* pConstantBuffer = CBPNTStaticShadow::GetPtr()->GetBuffer(); ID3D11Buffer* pNullConstantBuffer = nullptr; //頂点シェーダに渡す pD3D11DeviceContext->VSSetConstantBuffers(0, 1, &pConstantBuffer); //ピクセルシェーダに渡す pD3D11DeviceContext->PSSetConstantBuffers(0, 1, &pConstantBuffer); //シェーダの設定 pD3D11DeviceContext->VSSetShader(VSPNTStaticShadow::GetPtr()->GetShader(), nullptr, 0); if (v.m_OwnShadowmapActive) { //自己影がある場合 pD3D11DeviceContext->PSSetShader(PSPNTStaticShadow2::GetPtr()->GetShader(), nullptr, 0); } else { //自己影がない場合 pD3D11DeviceContext->PSSetShader(PSPNTStaticShadow::GetPtr()->GetShader(), nullptr, 0); } //シャドウマップのレンダラーターゲット auto ShadowmapPtr = Dev->GetShadowMapRenderTarget(); ID3D11ShaderResourceView* pShadowSRV = ShadowmapPtr->GetShaderResourceView(); pD3D11DeviceContext->PSSetShaderResources(1, 1, &pShadowSRV); //シャドウマップサンプラー ID3D11SamplerState* pShadowSampler = RenderState->GetComparisonLinear(); pD3D11DeviceContext->PSSetSamplers(1, 1, &pShadowSampler); //インプットレイアウトの設定 pD3D11DeviceContext->IASetInputLayout(VSPNTStaticShadow::GetPtr()->GetInputLayout()); //オブジェクトのサンプラー if (v.m_Wrap) { pD3D11DeviceContext->PSSetSamplers(0, 1, &pSamplerWrap); } else { pD3D11DeviceContext->PSSetSamplers(0, 1, &pSamplerClamp); } //デプスステンシルステート pD3D11DeviceContext->OMSetDepthStencilState(RenderState->GetDepthDefault(), 0); //ブレンドステート if (v.m_Trace) { //透明処理 pD3D11DeviceContext->OMSetBlendState(RenderState->GetAlphaBlendEx(), nullptr, 0xffffffff); //透明処理の場合は、ラスタライザステートを変更して2回描画 //ラスタライザステート(裏面描画) pD3D11DeviceContext->RSSetState(RenderState->GetCullFront()); //描画 pD3D11DeviceContext->DrawIndexed(v.m_MeshRes->GetNumIndicis(), 0, 0); //ラスタライザステート(表面描画) pD3D11DeviceContext->RSSetState(RenderState->GetCullBack()); //描画 pD3D11DeviceContext->DrawIndexed(v.m_MeshRes->GetNumIndicis(), 0, 0); } else { //透明処理しない pD3D11DeviceContext->OMSetBlendState(RenderState->GetOpaque(), nullptr, 0xffffffff); //ラスタライザステート(表面描画) pD3D11DeviceContext->RSSetState(RenderState->GetCullBack()); //描画 pD3D11DeviceContext->DrawIndexed(v.m_MeshRes->GetNumIndicis(), 0, 0); } } //後始末 Dev->InitializeStates(); m_DrawObjectVec.clear(); }
図0023b
図0023c
下のほうが明らかに影が細かくなっています。これは、シャドウマップのビューの範囲を調整することで、細かくすることができます。ビューの範囲は、DrawObjects.cppの冒頭にある
float ShadowmapDrawObject::m_ViewWidth(8.0f); float ShadowmapDrawObject::m_ViewHeight(8.0f);
図0023d
奥のボックスの影が途中で切れているのがわかると思います。
void GameStage::OnCreate() {
//描画デバイスの取得
auto Dev = App::GetApp()->GetDeviceResources();
Dev->GetShadowMapRenderTarget(2048.0f);
//中略
}
void GameStage::OnUpdate() { //中略 if (m_Camera.m_CameraArmLen < 10.0f) { ShadowmapDrawObject::m_ViewHeight = 8.0f; ShadowmapDrawObject::m_ViewWidth = 8.0f; } else { ShadowmapDrawObject::m_ViewHeight = 32.0f; ShadowmapDrawObject::m_ViewWidth = 32.0f; } } }