DirectX11级联阴影地图出现无限FOV异常问题求助
DirectX11级联阴影地图(CSM)无限FOV异常问题
用DirectX11实现级联阴影地图(CSM),参考LearnOpenGL的CSM教程,灯光设置为垂直向下照射,但最终生成的阴影图出现无限FOV的异常效果。
核心代码片段
LookAt函数实现
template <class T> inline CU::Matrix4x4<T> CU::Matrix4x4<T>::LookAt(CU::Vector3f aEye, CU::Vector3f aCenter, CU::Vector3f aUp) { CU::Matrix4x4<T> mat; auto Z = aCenter - aEye; Z.Normalize(); auto X = Z.Cross(aUp); X.Normalize(); if (!X.Length()) { aUp = CU::Vector3f(0, 0, 1); X = Z.Cross(aUp); X.Normalize(); } auto Y = X.Cross(Z); Y.Normalize(); mat.SetRow(1, X.ToVector4(( - X.Dot(aEye)))); mat.SetRow(2, Y.ToVector4(( - Y.Dot(aEye)))); mat.SetRow(3, (-Z).ToVector4((Z.Dot(aEye)))); mat.SetRow(4, CU::Vector4f(0, 0, 0, 1)); return mat.GetTranspose(); }
视锥体顶点转换到灯光空间代码
auto vec = MainSingleton::Get()->mySceneManager->GetCamera()->GetCameraData().GetFrustumCornersWorldSpace(); std::vector<std::pair<CU::Vector3f, CU::Vector3f>> minMax; std::vector <CU::Matrix4x4f> views; constexpr float zMult = 100.0f; for (auto& v : vec) { CU::Vector3f center; for (auto& vP : v) { center += vP; } center /= static_cast<float>(v.size()); views.emplace_back(CU::Matrix4x4f::LookAt(center + myDirectionalLights.front()->GetData().direction, center, CU::Vector3f(0.f, 1.f, 0.f))); //views.back().SetRow(4, myDirectionalLights.front()->gameObject->GetTransform().GetPosition().ToVector4(1)); minMax.emplace_back(); minMax.back().first.x = std::numeric_limits<float>::max(); minMax.back().first.y = std::numeric_limits<float>::max(); minMax.back().first.z = std::numeric_limits<float>::max(); minMax.back().second.x = std::numeric_limits<float>::lowest(); minMax.back().second.y = std::numeric_limits<float>::lowest(); minMax.back().second.z = std::numeric_limits<float>::lowest(); for (auto& vP : v) { const auto trf = vP * views.back(); minMax.back().first.x = std::min(minMax.back().first.x, trf.x); minMax.back().first.y = std::min(minMax.back().first.y, trf.y); minMax.back().first.z = std::min(minMax.back().first.z, trf.z); minMax.back().second.x = std::max(minMax.back().second.x, trf.x); minMax.back().second.y = std::max(minMax.back().second.y, trf.y); minMax.back().second.z = std::max(minMax.back().second.z, trf.z); } if (minMax.back().first.z < 0) minMax.back().first.z *= zMult; else minMax.back().first.z /= zMult; if (minMax.back().second.z < 0) minMax.back().second.z /= zMult; else minMax.back().second.z *= zMult; }
阴影图渲染代码
std::wstringstream stream; stream << "Shadow map nr: " << index; myRHI->BeginRenderTag(stream.str().c_str()); GraphicsEngine::GetRHI()->GetContext()->ClearDepthStencilView(myShadowMaps[index]->GetDepthStencilView().Get(), D3D11_CLEAR_DEPTH, 1.0f, 0); ID3D11ShaderResourceView* nullView = nullptr; GraphicsEngine::GetRHI()->GetContext()->PSSetShaderResources(105 + index, 1, &nullView); GraphicsEngine::GetRHI()->GetContext()->OMSetRenderTargets(0, nullptr, myShadowMaps[index]->GetDepthStencilView().Get()); CU::Camera camera; auto val = miniMax[index]; //camera.GetSettings().myNearPlane = 10; //camera.GetSettings().myFarPlane = 500000; //float x = val.second.x - val.first.x; //float y = val.second.y - val.first.y; float left = val.first.x; float right = val.second.x; float bottom = val.first.y; float top = val.second.y; float nearPlane = val.first.z; float farPlane = val.second.z; camera.Init(left, right, bottom, top, nearPlane, farPlane); auto& timer = CU::Time::Get(); myFrameBuffer.myCameraPosition = view[index].GetRowVector(4); myFrameBuffer.myInverseViewMatrix = view[index].GetInverse(); myFrameBuffer.myProjectionMatrix = camera.GetClipSpace(); myFrameBuffer.myScreenResolution = GetResolution(); myFrameBuffer.myDeltaTime = timer.GetDeltaTime(); myFrameBuffer.myUnscaledDeltaTime = timer.GetDeltaTimeUnscaled(); myFrameBuffer.myTotalTime = timer.GetTotalTime(); myFrameBuffer.myForward = cam->GetData().direction; UpdateAndSetConstantBuffer(ConstantBufferType::FrameBuffer, myFrameBuffer); //this->SetFrameBuffer(cam->GetShadowCamera()); //auto& transform = cam->GetShadowCamera()->GetTransform(); //myFrameBuffer.myCameraPosition = transform.GetPosition().ToVector4(1.f); //myFrameBuffer.myInverseViewMatrix = cam->GetShadowCamera()->GetView().GetInverse(); //myFrameBuffer.myForward = transform.Forward().GetNormalized(); D3D11_VIEWPORT viewport = {}; viewport.TopLeftX = 0; viewport.TopLeftY = 0; viewport.Width = 4096; viewport.Height = 4096; viewport.MaxDepth = 1.0f; myRHI->GetContext()->RSSetViewports(1, &viewport); GraphicsEngine::GetRHI()->GetContext()->PSSetShader(nullptr, nullptr, 0);
视锥体顶点获取函数
std::vector< std::vector<CU::Vector3f>> Camera::GetFrustumCornersWorldSpace() { std::vector< std::vector<CU::Vector3f>> frustumCorners; const Vector3f up = myTransform.Up(); const Vector3f right = myTransform.Right(); const int nbSplits = 3; std::vector<float> splitpoints{10, 100, 300, 1000}; //for (int i = 0; i < nbSplits; i++) //{ // float ratio = static_cast<float>(i) / nbSplits; // splitpoints[i] = mySettings.myNearPlane + ratio * (mySettings.myFarPlane - mySettings.myNearPlane); //} for (int i = 1; i < nbSplits + 1; i++) { float fakeNearPlane = splitpoints[i - 1]; float fakeFarPlane = splitpoints[i]; const float farHeight = std::tan(mySettings.myFov * Deg2Rad * 0.5f) * fakeFarPlane; const float farWidth = farHeight * (16.f / 9.f); const float nearHeight = std::tan(mySettings.myFov * Deg2Rad * 0.5f) * fakeNearPlane; const float nearWidth = nearHeight * (16.f / 9.f); const Vector3f farCentre = myTransform.GetPosition() + myTransform.Forward() * fakeFarPlane; const Vector3f ftr = farCentre + up * farHeight + right * farWidth; //Far Top Right const Vector3f ftl = farCentre + up * farHeight - right * farWidth; //Far Top Left const Vector3f fbr = farCentre - up * farHeight + right * farWidth; //Far Bottom Right const Vector3f fbl = farCentre - up * farHeight - right * farWidth; //Far Bottom Left frustumCorners.emplace_back(); frustumCorners.back().emplace_back(ftr); frustumCorners.back().emplace_back(ftl); frustumCorners.back().emplace_back(fbr); frustumCorners.back().emplace_back(fbl); const Vector3f nearCentre = myTransform.GetPosition() + myTransform.Forward() * fakeNearPlane; const Vector3f ntr = nearCentre + up * nearHeight + right * nearWidth;//Near Top Right const Vector3f ntl = nearCentre + up * nearHeight - right * nearWidth;//Near Top Left const Vector3f nbr = nearCentre - up * nearHeight + right * nearWidth;//Near Bottom Right const Vector3f nbl = nearCentre - up * nearHeight - right * nearWidth;//Near Bottom Left frustumCorners.back().emplace_back(ntr); frustumCorners.back().emplace_back(ntl); frustumCorners.back().emplace_back(nbr); frustumCorners.back().emplace_back(nbl); } return frustumCorners; }
异常效果
生成的阴影图呈现无限FOV异常:阴影被过度拉伸,覆盖范围远超相机视锥体,画面中出现大量不应存在的阴影区域,整体表现为视野无限扩大的错误状态。
已尝试的解决方案
- 修改裁剪矩阵参数
- 放大平行光方向向量以模拟灯光拉远
- 对裁剪空间矩阵、投影矩阵及其逆矩阵执行求逆和转置操作
以上方案均未解决问题,恳请提供技术帮助。
内容的提问来源于stack exchange,提问作者Simon Henriksson
相关产品推荐
相关产品推荐

