167 auto* renderer = app->GetRenderer();
168 if (!renderer)
return;
172 for (
size_t i = 0; i < m_lights.GetSize(); ++i) {
173 Light* light = m_lights[i];
178 shadowLight = dirLight;
187 for (
size_t i = 0; i < m_lights.GetSize(); ++i) {
188 Light* light = m_lights[i];
189 if (!light || !light->
IsEnabled())
continue;
192 anyDirLight = dirLight;
199 renderer->SetShadowPassEnabled(shadowLight !=
nullptr);
205 static bool warned =
false;
206 if (!warned) {
SLEAK_WARN(
"UpdateShadowData: No directional light found!"); warned =
true; }
211 auto color = activeLight->
GetColor();
228 + dir * (-shadowDist);
245 float left = -frustumSize, right = frustumSize;
246 float bottom = -frustumSize, top = frustumSize;
248 lightProj(0, 0) = 2.0f / (right - left);
249 lightProj(1, 1) = 2.0f / (top - bottom);
250 lightProj(2, 2) = 1.0f / (farP - nearP);
251 lightProj(3, 0) = -(right + left) / (right - left);
252 lightProj(3, 1) = -(top + bottom) / (top - bottom);
253 lightProj(3, 2) = -nearP / (farP - nearP);
264 const float shadowMapSize =
265 static_cast<float>(renderer->GetShadowMapResolution());
266 const float halfShadow = shadowMapSize * 0.5f;
276 float clipX = lightVP_raw(3, 0);
277 float clipY = lightVP_raw(3, 1);
278 float clipW = lightVP_raw(3, 3);
280 float ndcX = clipX / clipW;
281 float ndcY = clipY / clipW;
282 float texX = ndcX * halfShadow;
283 float texY = ndcY * halfShadow;
284 float roundedX = std::round(texX);
285 float roundedY = std::round(texY);
286 float offsetNdcX = (roundedX - texX) / halfShadow;
287 float offsetNdcY = (roundedY - texY) / halfShadow;
288 lightProj(3, 0) += offsetNdcX;
289 lightProj(3, 1) += offsetNdcY;
293 lightVP = lightView * lightProj;
301 static bool s_latched =
false;
302 static float s_frozenVP[16];
303 if (s_freeze && shadowLight) {
305 std::memcpy(s_frozenVP, &lightVP(0, 0),
sizeof(s_frozenVP));
307 SLEAK_WARN(
"shadowfreeze: light frustum latched");
309 std::memcpy(&lightVP(0, 0), s_frozenVP,
sizeof(s_frozenVP));
315 renderer->SetLightVP(&lightVP(0, 0));
334 ubo.
Ambient[3] = m_ambientIntensity;
351 std::memcpy(ubo.
LightVP, &lightVP(0, 0),
sizeof(
float) * 16);
362 if (Invert4x4(&camVP(0, 0), invVP)) {
364 std::memcpy(&invVPm(0, 0), invVP,
sizeof(
float) * 16);
365 std::memcpy(&lightVPm(0, 0), ubo.
LightVP,
sizeof(
float) * 16);
367 std::memcpy(ubo.
NdcToShadow, &comp(0, 0),
sizeof(
float) * 16);
376 1.0f /
static_cast<float>(renderer->GetShadowMapResolution());
405 for (
size_t i = 0; i < m_lights.GetSize() && ubo.
NumExtraLights < 3; ++i) {
406 Light* light = m_lights[i];
407 if (!light || !light->
IsEnabled())
continue;
408 if (light == activeLight)
continue;
410 if (!dlight)
continue;
412 auto eColor = dlight->GetColor();
425 renderer->UpdateShadowLightUBO(&ubo,
sizeof(ubo));