Initial pointlight shadow work

This commit is contained in:
Michael Riegger
2021-04-24 00:28:43 -07:00
parent 00873788cb
commit f508c4a4b5
7 changed files with 107 additions and 1 deletions
@@ -73,6 +73,8 @@ partial ShaderResourceGroup ViewSrg
float m_invAttenuationRadiusSquared; // For a radius at which this light no longer has an effect, 1 / radius^2.
float3 m_rgbIntensityCandelas;
float m_bulbRadius;
uint m_shadowIndex;
uint m_padding[3];
};
StructuredBuffer<PointLight> m_pointLights;
@@ -63,6 +63,8 @@ partial ShaderResourceGroup RayTracingSceneSrg
float m_invAttenuationRadiusSquared;
float3 m_rgbIntensity;
float m_bulbRadius;
uint m_shadowIndex;
uint m_padding[3];
};
StructuredBuffer<PointLight> m_pointLights;
@@ -59,6 +59,8 @@ ShaderResourceGroup PassSrg : SRG_PerPass
float m_invAttenuationRadiusSquared; // For a radius at which this light no longer has an effect, 1 / radius^2.
float3 m_rgbIntensityCandelas;
float m_bulbRadius;
uint m_shadowIndex;
uint m_padding[3];
};
struct DiskLight
@@ -14,6 +14,7 @@
#include <Atom/RPI.Public/FeatureProcessor.h>
#include <Atom/Feature/CoreLights/PhotometricValue.h>
#include <Atom/Feature/CoreLights/ShadowConstants.h>
namespace AZ
{
@@ -48,6 +49,8 @@ namespace AZ
virtual void SetAttenuationRadius(LightHandle handle, float attenuationRadius) = 0;
//! Sets the bulb radius for the provided LightHandle. Values greater than zero effectively make it a spherical light.
virtual void SetBulbRadius(LightHandle handle, float bulbRadius) = 0;
//! Sets if shadows are enabled
virtual void SetShadowsEnabled(LightHandle handle, bool enabled) = 0;
};
} // namespace Render
} // namespace AZ
@@ -84,7 +84,7 @@ namespace AZ
template <typename Functor, typename ParamType>
void SetShadowSetting(LightHandle handle, Functor&&, ParamType&& param);
ProjectedShadowFeatureProcessor* m_shadowFeatureProcessor;
ProjectedShadowFeatureProcessor* m_shadowFeatureProcessor = nullptr;
IndexedDataVector<DiskLightData> m_diskLightData;
GpuBufferHandler m_lightBufferHandler;
@@ -54,6 +54,7 @@ namespace AZ
desc.m_elementCountSrgName = "m_pointLightCount";
desc.m_elementSize = sizeof(PointLightData);
desc.m_srgLayout = RPI::RPISystemInterface::Get()->GetViewSrgAsset()->GetLayout();
m_shadowFeatureProcessor = GetParentScene()->GetFeatureProcessor<ProjectedShadowFeatureProcessor>();
m_lightBufferHandler = GpuBufferHandler(desc);
}
@@ -83,6 +84,11 @@ namespace AZ
{
if (handle.IsValid())
{
ShadowId shadowId = ShadowId(m_pointLightData.GetData(handle.GetIndex()).m_shadowIndex);
if (shadowId.IsValid())
{
m_shadowFeatureProcessor->ReleaseShadow(shadowId);
}
m_pointLightData.RemoveIndex(handle.GetIndex());
m_deviceBufferNeedsUpdate = true;
handle.Reset();
@@ -177,5 +183,86 @@ namespace AZ
return m_lightBufferHandler.GetElementCount();
}
void PointLightFeatureProcessor::SetShadowsEnabled(LightHandle handle, bool enabled)
{
auto& light = m_pointLightData.GetData(handle.GetIndex());
ShadowId shadowId = ShadowId(light.m_shadowIndex);
if (shadowId.IsValid() && enabled == false)
{
// Disable shadows
m_shadowFeatureProcessor->ReleaseShadow(shadowId);
shadowId.Reset();
light.m_shadowIndex = shadowId.GetIndex();
m_deviceBufferNeedsUpdate = true;
}
else if (shadowId.IsNull() && enabled == true)
{
// Enable shadows
light.m_shadowIndex = m_shadowFeatureProcessor->AcquireShadow().GetIndex();
UpdateShadow(handle);
m_deviceBufferNeedsUpdate = true;
}
}
void PointLightFeatureProcessor::UpdateShadow(LightHandle handle)
{
const auto& pointLight = m_pointLightData.GetData(handle.GetIndex());
ShadowId shadowId = ShadowId(pointLight.m_shadowIndex);
if (shadowId.IsNull())
{
// Early out if shadows are disabled.
return;
}
ProjectedShadowFeatureProcessorInterface::ProjectedShadowDescriptor desc =
m_shadowFeatureProcessor->GetShadowProperties(shadowId);
Vector3 position = Vector3::CreateFromFloat3(pointLight.m_position.data());
constexpr float SmallAngle = 0.01f;
desc.m_fieldOfViewYRadians = 1.57f;
// To handle bulb radius, set the position of the shadow caster behind the actual light depending on the radius of the bulb
//
// \ /
// \ /
// \_____/ <-- position of light itself (and forward plane of shadow casting view)
// . .
// . .
// * <-- position of shadow casting view
//
desc.m_transform = Transform::CreateLookAt(position, AZ::Vector3::CreateZero());
desc.m_aspectRatio = 1.0f;
desc.m_nearPlaneDistance = 0.1f;
const float invRadiusSquared = pointLight.m_invAttenuationRadiusSquared;
if (invRadiusSquared <= 0.f)
{
AZ_Assert(false, "Attenuation radius have to be set before use the light.");
return;
}
const float attenuationRadius = sqrtf(1.f / invRadiusSquared);
desc.m_farPlaneDistance = attenuationRadius;
m_shadowFeatureProcessor->SetShadowProperties(shadowId, desc);
}
template<typename Functor, typename ParamType>
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_shadowIndex);
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));
}
}
} // namespace Render
} // namespace AZ
@@ -16,6 +16,7 @@
#include <Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h>
#include <Atom/Feature/Utils/GpuBufferHandler.h>
#include <CoreLights/IndexedDataVector.h>
#include <Shadows/ProjectedShadowFeatureProcessor.h>
namespace AZ
{
@@ -31,6 +32,8 @@ namespace AZ
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.
uint32_t m_shadowIndex;
uint32_t m_padding[3];
};
class PointLightFeatureProcessor final
@@ -58,14 +61,21 @@ namespace AZ
void SetPosition(LightHandle handle, const AZ::Vector3& lightPosition) override;
void SetAttenuationRadius(LightHandle handle, float attenuationRadius) override;
void SetBulbRadius(LightHandle handle, float bulbRadius) override;
void SetShadowsEnabled(LightHandle handle, bool enabled) override;
const Data::Instance<RPI::Buffer> GetLightBuffer() const;
uint32_t GetLightCount()const;
private:
PointLightFeatureProcessor(const PointLightFeatureProcessor&) = delete;
using ShadowId = ProjectedShadowFeatureProcessor::ShadowId;
static constexpr const char* FeatureProcessorName = "PointLightFeatureProcessor";
void UpdateShadow(LightHandle handle);
// Convenience function for forwarding requests to the ProjectedShadowFeatureProcessor
template<typename Functor, typename ParamType>
void SetShadowSetting(LightHandle handle, Functor&&, ParamType&& param);
ProjectedShadowFeatureProcessor* m_shadowFeatureProcessor = nullptr;
IndexedDataVector<PointLightData> m_pointLightData;
GpuBufferHandler m_lightBufferHandler;