refactor: formalize directional shadow planning settings
This commit is contained in:
@@ -12,8 +12,24 @@ class Scene;
|
||||
|
||||
namespace Rendering {
|
||||
|
||||
struct DirectionalShadowPlanningSettings {
|
||||
uint32_t mapDimension = 1024u;
|
||||
float minFocusDistance = 5.0f;
|
||||
float maxFocusDistance = 64.0f;
|
||||
float perspectiveFocusFactor = 1.0f;
|
||||
float orthographicFocusFactor = 2.0f;
|
||||
float minDepthRange = 20.0f;
|
||||
float boundsPadding = 1.0f;
|
||||
float minDepthPadding = 2.0f;
|
||||
};
|
||||
|
||||
class SceneRenderRequestPlanner {
|
||||
public:
|
||||
SceneRenderRequestPlanner() = default;
|
||||
|
||||
void SetDirectionalShadowPlanningSettings(const DirectionalShadowPlanningSettings& settings);
|
||||
const DirectionalShadowPlanningSettings& GetDirectionalShadowPlanningSettings() const;
|
||||
|
||||
std::vector<Components::CameraComponent*> CollectCameras(
|
||||
const Components::Scene& scene,
|
||||
Components::CameraComponent* overrideCamera) const;
|
||||
@@ -23,6 +39,9 @@ public:
|
||||
Components::CameraComponent* overrideCamera,
|
||||
const RenderContext& context,
|
||||
const RenderSurface& surface) const;
|
||||
|
||||
private:
|
||||
DirectionalShadowPlanningSettings m_directionalShadowPlanningSettings = {};
|
||||
};
|
||||
|
||||
} // namespace Rendering
|
||||
|
||||
@@ -20,14 +20,41 @@ namespace Rendering {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint32_t kDirectionalShadowMapDimension = 1024;
|
||||
constexpr float kMinShadowFocusDistance = 5.0f;
|
||||
constexpr float kMaxShadowFocusDistance = 64.0f;
|
||||
constexpr float kPerspectiveShadowFocusFactor = 1.0f;
|
||||
constexpr float kOrthographicShadowFocusFactor = 2.0f;
|
||||
constexpr float kMinShadowDepthRange = 20.0f;
|
||||
constexpr float kShadowBoundsPadding = 1.0f;
|
||||
constexpr float kMinShadowDepthPadding = 2.0f;
|
||||
DirectionalShadowPlanningSettings SanitizeDirectionalShadowPlanningSettings(
|
||||
const DirectionalShadowPlanningSettings& settings) {
|
||||
DirectionalShadowPlanningSettings sanitized = settings;
|
||||
const DirectionalShadowPlanningSettings defaults = {};
|
||||
|
||||
if (sanitized.mapDimension == 0u) {
|
||||
sanitized.mapDimension = defaults.mapDimension;
|
||||
}
|
||||
if (sanitized.minFocusDistance <= Math::EPSILON) {
|
||||
sanitized.minFocusDistance = defaults.minFocusDistance;
|
||||
}
|
||||
if (sanitized.maxFocusDistance < sanitized.minFocusDistance) {
|
||||
sanitized.maxFocusDistance = (settings.maxFocusDistance >= defaults.minFocusDistance)
|
||||
? settings.maxFocusDistance
|
||||
: defaults.maxFocusDistance;
|
||||
sanitized.maxFocusDistance = std::max(sanitized.maxFocusDistance, sanitized.minFocusDistance);
|
||||
}
|
||||
if (sanitized.perspectiveFocusFactor <= Math::EPSILON) {
|
||||
sanitized.perspectiveFocusFactor = defaults.perspectiveFocusFactor;
|
||||
}
|
||||
if (sanitized.orthographicFocusFactor <= Math::EPSILON) {
|
||||
sanitized.orthographicFocusFactor = defaults.orthographicFocusFactor;
|
||||
}
|
||||
if (sanitized.minDepthRange <= Math::EPSILON) {
|
||||
sanitized.minDepthRange = defaults.minDepthRange;
|
||||
}
|
||||
if (sanitized.boundsPadding < 0.0f) {
|
||||
sanitized.boundsPadding = defaults.boundsPadding;
|
||||
}
|
||||
if (sanitized.minDepthPadding < 0.0f) {
|
||||
sanitized.minDepthPadding = defaults.minDepthPadding;
|
||||
}
|
||||
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
bool ShouldPlanDirectionalShadowForCamera(
|
||||
const Components::CameraComponent& camera,
|
||||
@@ -102,6 +129,7 @@ DirectionalShadowRenderPlan BuildDirectionalShadowRenderPlan(
|
||||
const Components::Scene& scene,
|
||||
const Components::CameraComponent& camera,
|
||||
const Components::LightComponent& light,
|
||||
const DirectionalShadowPlanningSettings& shadowSettings,
|
||||
float viewportAspect) {
|
||||
DirectionalShadowRenderPlan plan = {};
|
||||
if (!light.GetCastsShadows()) {
|
||||
@@ -129,13 +157,13 @@ DirectionalShadowRenderPlan BuildDirectionalShadowRenderPlan(
|
||||
|
||||
const float shadowDistance = camera.GetProjectionType() == Components::CameraProjectionType::Perspective
|
||||
? std::clamp(
|
||||
camera.GetFarClipPlane() * kPerspectiveShadowFocusFactor,
|
||||
kMinShadowFocusDistance,
|
||||
kMaxShadowFocusDistance)
|
||||
camera.GetFarClipPlane() * shadowSettings.perspectiveFocusFactor,
|
||||
shadowSettings.minFocusDistance,
|
||||
shadowSettings.maxFocusDistance)
|
||||
: std::clamp(
|
||||
camera.GetOrthographicSize() * kOrthographicShadowFocusFactor,
|
||||
kMinShadowFocusDistance,
|
||||
kMaxShadowFocusDistance);
|
||||
camera.GetOrthographicSize() * shadowSettings.orthographicFocusFactor,
|
||||
shadowSettings.minFocusDistance,
|
||||
shadowSettings.maxFocusDistance);
|
||||
const float sliceNear = std::max(camera.GetNearClipPlane(), 0.1f);
|
||||
const float sliceFar = std::max(sliceNear + 0.1f, shadowDistance);
|
||||
|
||||
@@ -185,7 +213,7 @@ DirectionalShadowRenderPlan BuildDirectionalShadowRenderPlan(
|
||||
frustumWorldBounds.Encapsulate(frustumCorners[index]);
|
||||
}
|
||||
|
||||
const float shadowViewDistance = std::max(sliceFar, kMinShadowDepthRange * 0.5f);
|
||||
const float shadowViewDistance = std::max(sliceFar, shadowSettings.minDepthRange * 0.5f);
|
||||
const Math::Vector3 shadowWorldPosition =
|
||||
focusPoint + lightDirection * shadowViewDistance;
|
||||
|
||||
@@ -256,17 +284,24 @@ DirectionalShadowRenderPlan BuildDirectionalShadowRenderPlan(
|
||||
ExpandLightSpaceBounds(view, worldCorners, minX, maxX, minY, maxY, minZ, maxZ);
|
||||
}
|
||||
|
||||
minX -= kShadowBoundsPadding;
|
||||
maxX += kShadowBoundsPadding;
|
||||
minY -= kShadowBoundsPadding;
|
||||
maxY += kShadowBoundsPadding;
|
||||
minZ -= kMinShadowDepthPadding;
|
||||
maxZ += kMinShadowDepthPadding;
|
||||
minX -= shadowSettings.boundsPadding;
|
||||
maxX += shadowSettings.boundsPadding;
|
||||
minY -= shadowSettings.boundsPadding;
|
||||
maxY += shadowSettings.boundsPadding;
|
||||
minZ -= shadowSettings.minDepthPadding;
|
||||
maxZ += shadowSettings.minDepthPadding;
|
||||
|
||||
const float shadowHalfExtent = std::max(
|
||||
std::max(std::abs(minX), std::abs(maxX)),
|
||||
std::max(std::abs(minY), std::abs(maxY)));
|
||||
const float shadowDepthRange = std::max(maxZ - minZ, kMinShadowDepthRange);
|
||||
const float unclampedShadowDepthRange = maxZ - minZ;
|
||||
if (unclampedShadowDepthRange < shadowSettings.minDepthRange) {
|
||||
const float centerZ = (minZ + maxZ) * 0.5f;
|
||||
const float halfDepthRange = shadowSettings.minDepthRange * 0.5f;
|
||||
minZ = centerZ - halfDepthRange;
|
||||
maxZ = centerZ + halfDepthRange;
|
||||
}
|
||||
|
||||
const Math::Matrix4x4 projection = Math::Matrix4x4::Orthographic(
|
||||
minX,
|
||||
maxX,
|
||||
@@ -281,8 +316,8 @@ DirectionalShadowRenderPlan BuildDirectionalShadowRenderPlan(
|
||||
plan.orthographicHalfExtent = shadowHalfExtent;
|
||||
plan.nearClipPlane = minZ;
|
||||
plan.farClipPlane = maxZ;
|
||||
plan.mapWidth = kDirectionalShadowMapDimension;
|
||||
plan.mapHeight = kDirectionalShadowMapDimension;
|
||||
plan.mapWidth = shadowSettings.mapDimension;
|
||||
plan.mapHeight = shadowSettings.mapDimension;
|
||||
plan.cameraData.view = view.Transpose();
|
||||
plan.cameraData.projection = projection.Transpose();
|
||||
plan.cameraData.viewProjection = (projection * view).Transpose();
|
||||
@@ -296,6 +331,15 @@ DirectionalShadowRenderPlan BuildDirectionalShadowRenderPlan(
|
||||
|
||||
} // namespace
|
||||
|
||||
void SceneRenderRequestPlanner::SetDirectionalShadowPlanningSettings(
|
||||
const DirectionalShadowPlanningSettings& settings) {
|
||||
m_directionalShadowPlanningSettings = SanitizeDirectionalShadowPlanningSettings(settings);
|
||||
}
|
||||
|
||||
const DirectionalShadowPlanningSettings& SceneRenderRequestPlanner::GetDirectionalShadowPlanningSettings() const {
|
||||
return m_directionalShadowPlanningSettings;
|
||||
}
|
||||
|
||||
std::vector<Components::CameraComponent*> SceneRenderRequestPlanner::CollectCameras(
|
||||
const Components::Scene& scene,
|
||||
Components::CameraComponent* overrideCamera) const {
|
||||
@@ -355,8 +399,12 @@ std::vector<CameraRenderRequest> SceneRenderRequestPlanner::BuildRequests(
|
||||
? static_cast<float>(surface.GetRenderAreaWidth()) /
|
||||
static_cast<float>(surface.GetRenderAreaHeight())
|
||||
: 1.0f;
|
||||
request.directionalShadow =
|
||||
BuildDirectionalShadowRenderPlan(scene, *camera, *mainDirectionalLight, viewportAspect);
|
||||
request.directionalShadow = BuildDirectionalShadowRenderPlan(
|
||||
scene,
|
||||
*camera,
|
||||
*mainDirectionalLight,
|
||||
m_directionalShadowPlanningSettings,
|
||||
viewportAspect);
|
||||
if (request.directionalShadow.IsValid()) {
|
||||
request.shadowCaster.clearFlags = RenderClearFlags::Depth;
|
||||
request.shadowCaster.hasCameraDataOverride = true;
|
||||
|
||||
Reference in New Issue
Block a user