Adding full shadowmap support

This commit is contained in:
Michael Riegger
2021-04-27 14:08:54 -07:00
parent bbae3b6d48
commit 2eed8684b5
4 changed files with 83 additions and 28 deletions
@@ -23,6 +23,20 @@ namespace AZ
namespace Render
{
struct PointLightData
{
AZStd::array<float, 3> m_position = {{0.0f, 0.0f, 0.0f}};
float m_invAttenuationRadiusSquared =
0.0f; // Inverse of the distance at which this light no longer has an effect, squared. Also used for falloff calculations.
AZStd::array<float, 3> m_rgbIntensity = {{0.0f, 0.0f, 0.0f}};
float m_bulbRadius = 0.0f; // Radius of spherical light in meters.
static const int NumShadowFaces = 6;
AZStd::array<uint16_t, NumShadowFaces> m_shadowIndices = {{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}};
uint32_t m_padding;
};
//! PointLightFeatureProcessorInterface provides an interface to acquire, release, and update a point light.
class PointLightFeatureProcessorInterface
: public RPI::FeatureProcessor
@@ -53,6 +67,20 @@ namespace AZ
virtual void SetShadowsEnabled(LightHandle handle, bool enabled) = 0;
//! Sets the shadowmap size (width and height) of the light.
virtual void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) = 0;
//! Specifies filter method of shadows.
virtual void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) = 0;
//! Specifies the width of boundary between shadowed area and lit area in radians. The degree ofshadowed gradually changes on
//! the boundary. 0 disables softening.
virtual void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) = 0;
//! Sets sample count to predict boundary of shadow (up to 16). It will be clamped to be less than or equal to the filtering
//! sample count.
virtual void SetPredictionSampleCount(LightHandle handle, uint16_t count) = 0;
//! Sets sample count for filtering of shadow boundary (up to 64)
virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0;
//! Sets the shadowmap Pcf (percentage closer filtering) method.
virtual void SetPcfMethod(LightHandle handle, PcfMethod method) = 0;
//! Sets all of the the point data for the provided LightHandle.
virtual void SetPointData(LightHandle handle, const PointLightData& data) = 0;
};
} // namespace Render
} // namespace AZ
@@ -59,7 +59,7 @@ namespace AZ
void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) override;
void SetPredictionSampleCount(LightHandle handle, uint16_t count) override;
void SetFilteringSampleCount(LightHandle handle, uint16_t count) override;
void SetPcfMethod(LightHandle handle, PcfMethod method);
void SetPcfMethod(LightHandle handle, PcfMethod method) override;
void SetDiskData(LightHandle handle, const DiskLightData& data) override;
@@ -219,6 +219,15 @@ namespace AZ
}
}
void PointLightFeatureProcessor::SetPointData(LightHandle handle, const PointLightData& data)
{
AZ_Assert(handle.IsValid(), "Invalid LightHandle passed to PointLightFeatureProcessor::SetDiskData().");
m_pointLightData.GetData(handle.GetIndex()) = data;
m_deviceBufferNeedsUpdate = true;
UpdateShadow(handle);
}
void PointLightFeatureProcessor::UpdateShadow(LightHandle handle)
{
for (int i = 0; i < PointLightData::NumShadowFaces; ++i)
@@ -237,7 +246,7 @@ namespace AZ
desc.m_fieldOfViewYRadians = DegToRad(90.5f); // Make it slightly larger than 90 degrees to avoid artifacts on the boundary between 2 cubemap faces
desc.m_transform = Transform::CreateLookAt(position, position + m_directions[i]);
desc.m_aspectRatio = 1.0f;
desc.m_nearPlaneDistance = 0.1f;
desc.m_nearPlaneDistance = 0.0f;
const float invRadiusSquared = pointLight.m_invAttenuationRadiusSquared;
if (invRadiusSquared <= 0.f)
@@ -246,33 +255,59 @@ namespace AZ
return;
}
const float attenuationRadius = sqrtf(1.f / invRadiusSquared);
desc.m_farPlaneDistance = attenuationRadius;
desc.m_farPlaneDistance = attenuationRadius + pointLight.m_bulbRadius;
m_shadowFeatureProcessor->SetShadowProperties(shadowId, desc);
}
}
template<typename Functor, typename ParamType>
void PointLightFeatureProcessor::SetShadowSetting(LightHandle handle, Functor&& functor, ParamType&& param, const int lightIndex)
void PointLightFeatureProcessor::SetShadowSetting(LightHandle handle, Functor&& functor, ParamType&& param)
{
AZ_Assert(handle.IsValid(), "Invalid LightHandle passed to PointLightFeatureProcessor::SetShadowSetting().");
auto& light = m_pointLightData.GetData(handle.GetIndex());
ShadowId shadowId = ShadowId(light.m_shadowIndices[lightIndex]);
AZ_Assert(shadowId.IsValid(), "Attempting to set a shadow property when shadows are not enabled.");
if (shadowId.IsValid())
for (int lightIndex = 0; lightIndex < PointLightData::NumShadowFaces; ++lightIndex)
{
AZStd::invoke(AZStd::forward<Functor>(functor), m_shadowFeatureProcessor, shadowId, AZStd::forward<ParamType>(param));
ShadowId shadowId = ShadowId(light.m_shadowIndices[lightIndex]);
AZ_Assert(shadowId.IsValid(), "Attempting to set a shadow property when shadows are not enabled.");
if (shadowId.IsValid())
{
AZStd::invoke(AZStd::forward<Functor>(functor), m_shadowFeatureProcessor, shadowId, AZStd::forward<ParamType>(param));
}
}
}
void PointLightFeatureProcessor::SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize)
{
for (int i = 0; i < PointLightData::NumShadowFaces; ++i)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution, shadowmapSize, i);
}
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution, shadowmapSize);
}
void PointLightFeatureProcessor::SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowFilterMethod, method);
}
void PointLightFeatureProcessor::SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetSofteningBoundaryWidthAngle, boundaryWidthRadians);
}
void PointLightFeatureProcessor::SetPredictionSampleCount(LightHandle handle, uint16_t count)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPredictionSampleCount, count);
}
void PointLightFeatureProcessor::SetFilteringSampleCount(LightHandle handle, uint16_t count)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetFilteringSampleCount, count);
}
void PointLightFeatureProcessor::SetPcfMethod(LightHandle handle, PcfMethod method)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPcfMethod, method);
}
} // namespace Render
} // namespace AZ
@@ -25,20 +25,6 @@ namespace AZ
namespace Render
{
struct PointLightData
{
AZStd::array<float, 3> m_position = { { 0.0f, 0.0f, 0.0f } };
float m_invAttenuationRadiusSquared = 0.0f; // Inverse of the distance at which this light no longer has an effect, squared. Also used for falloff calculations.
AZStd::array<float, 3> m_rgbIntensity = { { 0.0f, 0.0f, 0.0f } };
float m_bulbRadius = 0.0f; // Radius of spherical light in meters.
static const int NumShadowFaces = 6;
AZStd::array<uint16_t, NumShadowFaces> m_shadowIndices = {{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}};
uint32_t m_padding;
};
class PointLightFeatureProcessor final
: public PointLightFeatureProcessorInterface
{
@@ -66,6 +52,12 @@ namespace AZ
void SetBulbRadius(LightHandle handle, float bulbRadius) override;
void SetShadowsEnabled(LightHandle handle, bool enabled) override;
void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override;
void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override;
void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) override;
void SetPredictionSampleCount(LightHandle handle, uint16_t count) override;
void SetFilteringSampleCount(LightHandle handle, uint16_t count) override;
void SetPcfMethod(LightHandle handle, PcfMethod method) override;
void SetPointData(LightHandle handle, const PointLightData& data) override;
const Data::Instance<RPI::Buffer> GetLightBuffer() const;
uint32_t GetLightCount()const;
@@ -78,7 +70,7 @@ namespace AZ
void UpdateShadow(LightHandle handle);
// Convenience function for forwarding requests to the ProjectedShadowFeatureProcessor
template<typename Functor, typename ParamType>
void SetShadowSetting(LightHandle handle, Functor&&, ParamType&& param, const int lightIndex);
void SetShadowSetting(LightHandle handle, Functor&&, ParamType&& param);
ProjectedShadowFeatureProcessor* m_shadowFeatureProcessor = nullptr;
IndexedDataVector<PointLightData> m_pointLightData;