rendering: formalize main light shadow params
This commit is contained in:
@@ -25,6 +25,21 @@ Shader "Builtin Forward Lit"
|
||||
float4 spotAnglesAndFlags;
|
||||
};
|
||||
|
||||
struct ShadowMapMetrics
|
||||
{
|
||||
float2 inverseMapSize;
|
||||
float worldTexelSize;
|
||||
float padding;
|
||||
};
|
||||
|
||||
struct ShadowSamplingData
|
||||
{
|
||||
float enabled;
|
||||
float receiverDepthBias;
|
||||
float normalBiasScale;
|
||||
float shadowStrength;
|
||||
};
|
||||
|
||||
cbuffer LightingConstants
|
||||
{
|
||||
float4 gMainLightDirectionAndIntensity;
|
||||
@@ -42,8 +57,8 @@ Shader "Builtin Forward Lit"
|
||||
cbuffer ShadowReceiverConstants
|
||||
{
|
||||
float4x4 gWorldToShadowMatrix;
|
||||
float4 gShadowBiasAndTexelSize;
|
||||
float4 gShadowOptions;
|
||||
ShadowMapMetrics gShadowMapMetrics;
|
||||
ShadowSamplingData gShadowSampling;
|
||||
};
|
||||
|
||||
Texture2D BaseColorTexture;
|
||||
@@ -83,12 +98,13 @@ Shader "Builtin Forward Lit"
|
||||
#ifndef XC_MAIN_LIGHT_SHADOWS
|
||||
return 1.0f;
|
||||
#else
|
||||
if (gShadowOptions.x < 0.5f) {
|
||||
if (gShadowSampling.enabled < 0.5f) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
const float nDotL = saturate(dot(normalize(normalWS), normalize(lightDirectionWS)));
|
||||
const float normalBiasWorld = gShadowOptions.y * gShadowOptions.z * (1.0f - nDotL);
|
||||
const float normalBiasWorld =
|
||||
gShadowMapMetrics.worldTexelSize * gShadowSampling.normalBiasScale * (1.0f - nDotL);
|
||||
const float3 shadowPositionWS = positionWS + normalize(normalWS) * normalBiasWorld;
|
||||
const float4 shadowClip = mul(gWorldToShadowMatrix, float4(shadowPositionWS, 1.0f));
|
||||
if (shadowClip.w <= 0.0f) {
|
||||
@@ -109,7 +125,7 @@ Shader "Builtin Forward Lit"
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
const float receiverDepth = shadowNdc.z * 0.5f + 0.5f - gShadowBiasAndTexelSize.x;
|
||||
const float receiverDepth = shadowNdc.z * 0.5f + 0.5f - gShadowSampling.receiverDepthBias;
|
||||
#else
|
||||
if (shadowUv.x < 0.0f || shadowUv.x > 1.0f ||
|
||||
shadowUv.y < 0.0f || shadowUv.y > 1.0f ||
|
||||
@@ -117,9 +133,9 @@ Shader "Builtin Forward Lit"
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
const float receiverDepth = shadowNdc.z - gShadowBiasAndTexelSize.x;
|
||||
const float receiverDepth = shadowNdc.z - gShadowSampling.receiverDepthBias;
|
||||
#endif
|
||||
const float2 shadowTexelSize = gShadowBiasAndTexelSize.yz;
|
||||
const float2 shadowTexelSize = gShadowMapMetrics.inverseMapSize;
|
||||
float visibility = 0.0f;
|
||||
[unroll]
|
||||
for (int offsetY = -1; offsetY <= 1; ++offsetY) {
|
||||
@@ -139,7 +155,7 @@ Shader "Builtin Forward Lit"
|
||||
}
|
||||
|
||||
visibility *= (1.0f / 9.0f);
|
||||
const float shadowStrength = saturate(gShadowBiasAndTexelSize.w);
|
||||
const float shadowStrength = saturate(gShadowSampling.shadowStrength);
|
||||
return lerp(1.0f - shadowStrength, 1.0f, visibility);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEngine/Core/Math/Vector2.h>
|
||||
#include <XCEngine/Core/Math/Vector3.h>
|
||||
#include <XCEngine/Core/Math/Vector4.h>
|
||||
#include <XCEngine/Rendering/FrameData/RenderCameraData.h>
|
||||
@@ -50,11 +51,32 @@ struct RenderAdditionalLightData {
|
||||
float spotAngle = 0.0f;
|
||||
};
|
||||
|
||||
struct RenderDirectionalShadowMapMetrics {
|
||||
Math::Vector2 inverseMapSize = Math::Vector2::Zero();
|
||||
float worldTexelSize = 0.0f;
|
||||
float padding = 0.0f;
|
||||
};
|
||||
|
||||
static_assert(
|
||||
sizeof(RenderDirectionalShadowMapMetrics) == sizeof(float) * 4u,
|
||||
"RenderDirectionalShadowMapMetrics must stay float4-sized for GPU constant layout");
|
||||
|
||||
struct RenderDirectionalShadowSamplingData {
|
||||
float enabled = 0.0f;
|
||||
float receiverDepthBias = 0.0f;
|
||||
float normalBiasScale = 0.0f;
|
||||
float shadowStrength = 0.0f;
|
||||
};
|
||||
|
||||
static_assert(
|
||||
sizeof(RenderDirectionalShadowSamplingData) == sizeof(float) * 4u,
|
||||
"RenderDirectionalShadowSamplingData must stay float4-sized for GPU constant layout");
|
||||
|
||||
struct RenderDirectionalShadowData {
|
||||
bool enabled = false;
|
||||
Math::Matrix4x4 viewProjection = Math::Matrix4x4::Identity();
|
||||
Math::Vector4 shadowParams = Math::Vector4::Zero();
|
||||
Math::Vector4 shadowOptions = Math::Vector4::Zero();
|
||||
RenderDirectionalShadowMapMetrics mapMetrics = {};
|
||||
RenderDirectionalShadowSamplingData sampling = {};
|
||||
RHI::RHIResourceView* shadowMap = nullptr;
|
||||
|
||||
bool IsValid() const {
|
||||
|
||||
@@ -91,8 +91,8 @@ private:
|
||||
|
||||
struct ShadowReceiverConstants {
|
||||
Math::Matrix4x4 worldToShadow = Math::Matrix4x4::Identity();
|
||||
Math::Vector4 shadowBiasAndTexelSize = Math::Vector4::Zero();
|
||||
Math::Vector4 shadowOptions = Math::Vector4::Zero();
|
||||
RenderDirectionalShadowMapMetrics shadowMapMetrics = {};
|
||||
RenderDirectionalShadowSamplingData shadowSampling = {};
|
||||
};
|
||||
|
||||
struct SkyboxConstants {
|
||||
|
||||
@@ -12,6 +12,9 @@ class Scene;
|
||||
|
||||
namespace Rendering {
|
||||
|
||||
// Planning-only knobs for fitting the single main-light shadow camera to the
|
||||
// current view. Receiver-side bias/filtering parameters live in runtime shadow
|
||||
// data and are not configured here.
|
||||
struct DirectionalShadowPlanningSettings {
|
||||
uint32_t mapDimension = 1024u;
|
||||
float minFocusDistance = 5.0f;
|
||||
|
||||
@@ -19,6 +19,10 @@ namespace Rendering {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr float kDirectionalShadowReceiverDepthBias = 0.0015f;
|
||||
constexpr float kDirectionalShadowNormalBiasScale = 1.5f;
|
||||
constexpr float kDirectionalShadowStrength = 0.85f;
|
||||
|
||||
std::shared_ptr<const RenderPipelineAsset> CreateDefaultPipelineAsset() {
|
||||
static const std::shared_ptr<const RenderPipelineAsset> s_defaultPipelineAsset =
|
||||
std::make_shared<Pipelines::BuiltinForwardPipelineAsset>();
|
||||
@@ -386,16 +390,14 @@ RenderDirectionalShadowData BuildDirectionalShadowData(
|
||||
: (plan.orthographicHalfExtent > Math::EPSILON && plan.mapWidth > 0u
|
||||
? (plan.orthographicHalfExtent * 2.0f) / static_cast<float>(plan.mapWidth)
|
||||
: 0.0f);
|
||||
shadowData.shadowParams = Math::Vector4(
|
||||
0.0015f,
|
||||
shadowData.mapMetrics.inverseMapSize = Math::Vector2(
|
||||
1.0f / static_cast<float>(plan.mapWidth),
|
||||
1.0f / static_cast<float>(plan.mapHeight),
|
||||
0.85f);
|
||||
shadowData.shadowOptions = Math::Vector4(
|
||||
1.0f,
|
||||
texelWorldSize,
|
||||
1.5f,
|
||||
0.0f);
|
||||
1.0f / static_cast<float>(plan.mapHeight));
|
||||
shadowData.mapMetrics.worldTexelSize = texelWorldSize;
|
||||
shadowData.sampling.enabled = 1.0f;
|
||||
shadowData.sampling.receiverDepthBias = kDirectionalShadowReceiverDepthBias;
|
||||
shadowData.sampling.normalBiasScale = kDirectionalShadowNormalBiasScale;
|
||||
shadowData.sampling.shadowStrength = kDirectionalShadowStrength;
|
||||
return shadowData;
|
||||
}
|
||||
|
||||
|
||||
@@ -714,17 +714,12 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
|
||||
visibleItem.localToWorld.Inverse()
|
||||
};
|
||||
const LightingConstants lightingConstants = BuildLightingConstants(sceneData.lighting);
|
||||
const ShadowReceiverConstants shadowReceiverConstants = {
|
||||
sceneData.lighting.HasMainDirectionalShadow()
|
||||
? sceneData.lighting.mainDirectionalShadow.viewProjection
|
||||
: Math::Matrix4x4::Identity(),
|
||||
sceneData.lighting.HasMainDirectionalShadow()
|
||||
? sceneData.lighting.mainDirectionalShadow.shadowParams
|
||||
: Math::Vector4::Zero(),
|
||||
sceneData.lighting.HasMainDirectionalShadow()
|
||||
? sceneData.lighting.mainDirectionalShadow.shadowOptions
|
||||
: Math::Vector4::Zero()
|
||||
};
|
||||
ShadowReceiverConstants shadowReceiverConstants = {};
|
||||
if (sceneData.lighting.HasMainDirectionalShadow()) {
|
||||
shadowReceiverConstants.worldToShadow = sceneData.lighting.mainDirectionalShadow.viewProjection;
|
||||
shadowReceiverConstants.shadowMapMetrics = sceneData.lighting.mainDirectionalShadow.mapMetrics;
|
||||
shadowReceiverConstants.shadowSampling = sceneData.lighting.mainDirectionalShadow.sampling;
|
||||
}
|
||||
|
||||
const Resources::Material* material = ResolveMaterial(visibleItem);
|
||||
const ResolvedShaderPass resolvedShaderPass = ResolveSurfaceShaderPass(sceneData, material);
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
|
||||
namespace XCEngine {
|
||||
@@ -134,12 +133,8 @@ DirectionalShadowRenderPlan BuildDirectionalShadowRenderPlan(
|
||||
const Components::LightComponent& light,
|
||||
const DirectionalShadowPlanningSettings& shadowSettings,
|
||||
float viewportAspect) {
|
||||
std::fprintf(stderr, "[shadow-debug] enter BuildDirectionalShadowRenderPlan\n");
|
||||
std::fflush(stderr);
|
||||
DirectionalShadowRenderPlan plan = {};
|
||||
if (!light.GetCastsShadows()) {
|
||||
std::fprintf(stderr, "[shadow-debug] early out: light shadows disabled\n");
|
||||
std::fflush(stderr);
|
||||
return plan;
|
||||
}
|
||||
|
||||
@@ -173,8 +168,6 @@ DirectionalShadowRenderPlan BuildDirectionalShadowRenderPlan(
|
||||
shadowSettings.maxFocusDistance);
|
||||
const float sliceNear = std::max(camera.GetNearClipPlane(), 0.1f);
|
||||
const float sliceFar = std::max(sliceNear + 0.1f, shadowDistance);
|
||||
std::fprintf(stderr, "[shadow-debug] built slice distances\n");
|
||||
std::fflush(stderr);
|
||||
|
||||
std::array<Math::Vector3, 8> frustumCorners = {};
|
||||
if (camera.GetProjectionType() == Components::CameraProjectionType::Perspective) {
|
||||
@@ -216,8 +209,6 @@ DirectionalShadowRenderPlan BuildDirectionalShadowRenderPlan(
|
||||
focusPoint += corner;
|
||||
}
|
||||
focusPoint /= static_cast<float>(frustumCorners.size());
|
||||
std::fprintf(stderr, "[shadow-debug] built frustum corners\n");
|
||||
std::fflush(stderr);
|
||||
|
||||
Math::Bounds frustumWorldBounds(frustumCorners[0], Math::Vector3::Zero());
|
||||
for (size_t index = 1; index < frustumCorners.size(); ++index) {
|
||||
@@ -241,8 +232,6 @@ DirectionalShadowRenderPlan BuildDirectionalShadowRenderPlan(
|
||||
shadowWorldPosition,
|
||||
shadowRotation,
|
||||
Math::Vector3::One()).Inverse();
|
||||
std::fprintf(stderr, "[shadow-debug] built light view matrix\n");
|
||||
std::fflush(stderr);
|
||||
|
||||
float minX = std::numeric_limits<float>::max();
|
||||
float maxX = std::numeric_limits<float>::lowest();
|
||||
@@ -251,14 +240,10 @@ DirectionalShadowRenderPlan BuildDirectionalShadowRenderPlan(
|
||||
float minZ = std::numeric_limits<float>::max();
|
||||
float maxZ = std::numeric_limits<float>::lowest();
|
||||
ExpandLightSpaceBounds(view, frustumCorners, minX, maxX, minY, maxY, minZ, maxZ);
|
||||
std::fprintf(stderr, "[shadow-debug] expanded frustum bounds\n");
|
||||
std::fflush(stderr);
|
||||
|
||||
const uint32_t cullingMask = camera.GetCullingMask();
|
||||
const std::vector<Components::MeshFilterComponent*> meshFilters =
|
||||
scene.FindObjectsOfType<Components::MeshFilterComponent>();
|
||||
std::fprintf(stderr, "[shadow-debug] mesh filter count=%zu\n", meshFilters.size());
|
||||
std::fflush(stderr);
|
||||
for (Components::MeshFilterComponent* meshFilter : meshFilters) {
|
||||
if (meshFilter == nullptr ||
|
||||
!meshFilter->IsEnabled() ||
|
||||
@@ -300,8 +285,6 @@ DirectionalShadowRenderPlan BuildDirectionalShadowRenderPlan(
|
||||
|
||||
ExpandLightSpaceBounds(view, worldCorners, minX, maxX, minY, maxY, minZ, maxZ);
|
||||
}
|
||||
std::fprintf(stderr, "[shadow-debug] finished mesh bounds expansion\n");
|
||||
std::fflush(stderr);
|
||||
|
||||
minX -= shadowSettings.boundsPadding;
|
||||
maxX += shadowSettings.boundsPadding;
|
||||
@@ -349,8 +332,6 @@ DirectionalShadowRenderPlan BuildDirectionalShadowRenderPlan(
|
||||
maxY,
|
||||
minZ,
|
||||
maxZ);
|
||||
std::fprintf(stderr, "[shadow-debug] built orthographic projection\n");
|
||||
std::fflush(stderr);
|
||||
|
||||
plan.enabled = true;
|
||||
plan.lightDirection = lightDirection;
|
||||
@@ -369,8 +350,6 @@ DirectionalShadowRenderPlan BuildDirectionalShadowRenderPlan(
|
||||
plan.cameraData.clearFlags = RenderClearFlags::Depth;
|
||||
plan.cameraData.viewportWidth = plan.mapWidth;
|
||||
plan.cameraData.viewportHeight = plan.mapHeight;
|
||||
std::fprintf(stderr, "[shadow-debug] leave BuildDirectionalShadowRenderPlan\n");
|
||||
std::fflush(stderr);
|
||||
return plan;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user