rendering::ShadowCameraTransform rendering::lighting::DirectionalLight::CalcShadowCameraTransform(const math::Vector3D& cameraPos, const math::Quaternion& cameraRot) const { //return BaseLight::CalcShadowCameraTransform(cameraPos, cameraRot); // This function in directional light allows the directional light to be casting shadows only in the area around the camera current position ShadowCameraTransform shadowCameraTransform(cameraPos + cameraRot.GetForward() * m_halfShadowArea, GetTransform().GetTransformedRot()); /** * The reoccurring shimmering is caused by the moving shadow camera by the value less than * the shadow map texel size. If I move by, let's say, half the texel size, render the scene * and generate the shadow map again, the objects aren't going to map to exactly the same texels * in the shadow map. This causes approximation to be calculated slightly differently each frame. * To fix the shimmering effect we have to make sure we only move by the multiple of the texel size. */ /* ==================== Fixing the shimmering effect begin ==================== */ const auto shadowMapSize = static_cast<math::Real>(1 << GetShadowInfo()->GetShadowMapSizeAsPowerOf2()); const auto worldSpaceShadowMapTexelSize = m_halfShadowArea * 2.0f / shadowMapSize; // Now we transform from the world space into the light space auto lightSpaceCameraPos(shadowCameraTransform.pos.Rotate(shadowCameraTransform.rot.Conjugate())); // Now we need to snap the lightSpaceCameraPos to shadow map texel size increments lightSpaceCameraPos.x = worldSpaceShadowMapTexelSize * math::Floor(lightSpaceCameraPos.x / worldSpaceShadowMapTexelSize); lightSpaceCameraPos.y = worldSpaceShadowMapTexelSize * math::Floor(lightSpaceCameraPos.y / worldSpaceShadowMapTexelSize); // Now we transform back from the light space into the world space shadowCameraTransform.pos = lightSpaceCameraPos.Rotate(shadowCameraTransform.rot); /* ==================== Fixing the shimmering effect end ==================== */ return shadowCameraTransform; }
ShadowCameraTransform DirectionalLight::CalcShadowCameraTransform(const Vector3f& mainCameraPos, const Quaternion& mainCameraRot) const { Vector3f resultPos = mainCameraPos + mainCameraRot.GetForward() * GetHalfShadowArea(); Quaternion resultRot = GetTransform().GetTransformedRot(); float worldTexelSize = (GetHalfShadowArea()*2)/((float)(1 << GetShadowInfo().GetShadowMapSizeAsPowerOf2())); Vector3f lightSpaceCameraPos = resultPos.Rotate(resultRot.Conjugate()); lightSpaceCameraPos.SetX(worldTexelSize * floor(lightSpaceCameraPos.GetX() / worldTexelSize)); lightSpaceCameraPos.SetY(worldTexelSize * floor(lightSpaceCameraPos.GetY() / worldTexelSize)); resultPos = lightSpaceCameraPos.Rotate(resultRot); return ShadowCameraTransform(resultPos, resultRot); }