17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 15:39:20 +02:00
Files
maszyna/betterRenderer/renderer/source/csm.cpp
maj00r 26501b0fd7 hoist standard includes above everything else
Ordering them before the imports in the same file was not enough: a
project header on line 1 can import a module several levels down whose
global module fragment already pulled in the same standard header, and
that include guard does not cross the module boundary. Putting them
first means the guard is set before anything can import.

Skips vendored single-header libraries and anything inside an #if.
2026-09-10 01:02:17 +02:00

191 lines
7.0 KiB
C++

#include <limits>
#include <vector>
#include "csm.h"
#include <nvrhi/utils.h>
#include "config.h"
#include "nvrenderer/nvrenderer.h"
#include "nvrendererbackend.h"
MaShadowMap::MaShadowMap(NvRenderer* renderer)
: MaResourceRegistry(renderer), m_backend(renderer->m_backend.get()) {}
void MaShadowMap::Init() {
InitResourceRegistry();
const auto& shadow_config = NvRenderer::Config()->m_shadow;
int num_cascades = shadow_config.m_cascade_distances.size();
m_cascade_matrices.resize(num_cascades);
m_cascade_matrices_clamped.resize(num_cascades);
m_shadow_planes.resize(num_cascades + 1);
m_far_plane_first = shadow_config.m_cascade_distances.front();
m_far_plane_last = shadow_config.m_cascade_distances.back();
m_projection_buffer = m_backend->GetDevice()->createBuffer(
nvrhi::utils::CreateStaticConstantBufferDesc(
sizeof(ShadowProjectionConstants), "Shadow projections")
.setInitialState(nvrhi::ResourceStates::ConstantBuffer)
.setKeepInitialState(true));
m_inverse_projection_buffer = m_backend->GetDevice()->createBuffer(
nvrhi::utils::CreateStaticConstantBufferDesc(
sizeof(ShadowProjectionConstants), "Inverse shadow projections")
.setInitialState(nvrhi::ResourceStates::ConstantBuffer)
.setKeepInitialState(true));
RegisterResource(true, "shadow_projection_buffer", m_projection_buffer,
nvrhi::ResourceType::ConstantBuffer);
}
void MaShadowMap::CalcCascades(const glm::dmat4& projection,
const glm::dmat4& view,
const glm::dvec3& light) {
const auto& shadow_config = NvRenderer::Config()->m_shadow;
glm::dmat4 inverse_projection = glm::inverse(projection);
glm::dmat4 inverse_view = glm::inverse(view);
double projection_near, projection_far;
{
glm::dvec4 ndc_near{0., 0., 0., 1.};
glm::dvec4 ndc_far{0., 0., 1., 1.};
ndc_near = inverse_projection * ndc_near;
ndc_far = inverse_projection * ndc_far;
projection_near = -ndc_near.z / ndc_near.w;
projection_far = -ndc_far.z / ndc_far.w;
}
// Set near and far plane offset
m_shadow_planes.front() = projection_near;
for (int i = 1; i < shadow_config.m_cascade_distances.size(); ++i)
m_shadow_planes[i] = shadow_config.m_cascade_distances[i];
// m_shadow_planes.back() = std::min(m_far_plane_last, projection_far);
// m_shadow_planes[1] = std::min(m_far_plane_first, m_shadow_planes.back());
//
//// Fill intermediate plane offsets
// double base = m_shadow_planes.back() / m_shadow_planes[1];
// double denom = 1. / (m_shadow_planes.size() - 2.);
// for (int i = 2; i < m_shadow_planes.size() - 1; ++i) {
// m_shadow_planes[i] = m_shadow_planes[1] * glm::pow(base, (i - 1) *
// denom);
// }
static std::vector<glm::dvec3> plane_corners;
plane_corners.resize(4 * (m_shadow_planes.size()));
// for (int i = 0; i < m_shadow_planes.size(); ++i) {
// glm::dvec3* plane = &plane_corners[i * 4];
// GetViewPlaneCornersWorldSpace(projection, inverse_projection,
// inverse_view,
// m_shadow_planes[i], plane[0], plane[1],
// plane[2], plane[3]);
// }
glm::dvec3 up = glm::abs(light.y) > .999 ? glm::dvec3{0., 0., 1.}
: glm::dvec3{0., 1., 0.};
for (int i = 0; i < m_cascade_matrices.size(); ++i) {
glm::dvec3 plane[8];
GetViewPlaneCornersWorldSpace(projection, inverse_projection, inverse_view,
m_shadow_planes[i], true, plane[0], plane[1],
plane[2], plane[3]);
GetViewPlaneCornersWorldSpace(projection, inverse_projection, inverse_view,
m_shadow_planes[i + 1], false, plane[4],
plane[5], plane[6], plane[7]);
glm::dvec3 world_min{std::numeric_limits<double>::max()};
glm::dvec3 world_max{-std::numeric_limits<double>::max()};
double offset = 0.;
for (int j = 0; j < 8; ++j) {
world_min = glm::min(world_min, plane[j]);
world_max = glm::max(world_max, plane[j]);
}
double actual_size = glm::max(glm::distance(plane[0], plane[7]),
glm::distance(plane[4], plane[7]));
glm::dvec3 center = -Global.pCamera.Pos;
glm::dmat4 shadow_view = glm::lookAtRH(center, center - light, up);
glm::dvec3 min{std::numeric_limits<double>::max()};
glm::dvec3 max{-std::numeric_limits<double>::max()};
double frustumchunkdepth =
m_shadow_planes[i + 1] -
(m_shadow_planes[i] > 1.f ? m_shadow_planes[i] : 0.f);
double quantizationstep{glm::min(frustumchunkdepth, 50.)};
for (int j = 0; j < 8; ++j) {
glm::dvec3 v = shadow_view * glm::dvec4(plane[j], 1.f);
min = glm::min(min, v);
max = glm::max(max, v);
}
glm::dvec2 size = max - min;
glm::dvec2 diff = static_cast<glm::dvec2>(actual_size) - size;
max.xy += glm::max(diff * .5, 0.);
min.xy -= glm::max(diff * .5, 0.);
glm::dvec2 pixel_size =
static_cast<glm::dvec2>(actual_size / shadow_config.m_resolution);
min.xy = glm::round(min.xy / pixel_size) * pixel_size;
max.xy = glm::round(max.xy / pixel_size) * pixel_size;
// max = quantizationstep * glm::ceil(max / quantizationstep);
// min = quantizationstep * glm::floor(min / quantizationstep);
glm::dmat4 shadow_proj = glm::orthoRH_ZO(min.x, max.x, min.y, max.y,
-max.z - 500., -min.z + 500.);
glm::dmat4 shadow_proj_clamped = glm::orthoRH_ZO(
min.x, max.x, min.y, max.y, -max.z - 500., -min.z + 500.);
m_cascade_matrices[i] = shadow_proj * shadow_view;
m_cascade_matrices_clamped[i] = shadow_proj_clamped * shadow_view;
}
}
void MaShadowMap::UpdateConstants(nvrhi::ICommandList* command_list) {
{
ShadowProjectionConstants constants{};
for (int i = 0; i < std::min(m_cascade_matrices.size(),
constants.m_shadow_projection.size());
++i) {
constants.m_shadow_projection[i] = m_cascade_matrices[i];
constants.m_shadow_planes[i] =
m_shadow_planes[i + 1] * m_shadow_planes[i + 1];
}
command_list->writeBuffer(m_projection_buffer, &constants,
sizeof(constants));
}
}
void MaShadowMap::GetViewPlaneCornersWorldSpace(
const glm::dmat4& projection, const glm::dmat4& inverse_projection,
const glm::dmat4& inverse_view, const double& d, bool normalize,
glm::dvec3& ll, glm::dvec3& lr, glm::dvec3& ul, glm::dvec3& ur) {
glm::dvec4 lll{-1., -1., 1., 1.};
glm::dvec4 llr{1., -1., 1., 1.};
glm::dvec4 lul{-1., 1., 1., 1.};
glm::dvec4 lur{1., 1., 1., 1.};
auto unproject = [&](glm::dvec4& v) -> void {
v = inverse_projection * v;
if (normalize) {
v /= v.w;
v *= d / glm::length(glm::dvec3(v.xyz));
} else {
v *= d / -v.z;
}
v.w = 1.;
};
unproject(lll);
unproject(llr);
unproject(lul);
unproject(lur);
ll = inverse_view * lll;
lr = inverse_view * llr;
ul = inverse_view * lul;
ur = inverse_view * lur;
}