Graphics: Implement point-light shadow-mapping
This commit is contained in:
parent
6731e07b54
commit
f8238a6e6c
|
|
@ -250,17 +250,18 @@ int main()
|
|||
|
||||
{
|
||||
auto& lightNode = registry.emplace<Nz::NodeComponent>(lightEntity3);
|
||||
lightNode.SetPosition(Nz::Vector3f::Backward() * 2.f);
|
||||
lightNode.SetRotation(Nz::EulerAnglesf(-45.f, 180.f, 0.f));
|
||||
//lightNode.SetPosition(Nz::Vector3f::Up() * 4.f);
|
||||
lightNode.SetPosition(Nz::Vector3f::Down() * 7.5f + Nz::Vector3f::Backward() * 2.5f);
|
||||
//lightNode.SetRotation(Nz::EulerAnglesf(-45.f, 180.f, 0.f));
|
||||
lightNode.SetParentJoint(bobEntity, "Spine2");
|
||||
|
||||
auto& cameraLight = registry.emplace<Nz::LightComponent>(lightEntity3);
|
||||
|
||||
auto& spotLight = cameraLight.AddLight<Nz::SpotLight>(0xFFFFFFFF);
|
||||
spotLight.UpdateColor(Nz::Color::Blue);
|
||||
spotLight.UpdateInnerAngle(Nz::DegreeAnglef(15.f));
|
||||
spotLight.UpdateOuterAngle(Nz::DegreeAnglef(20.f));
|
||||
spotLight.EnableShadowCasting(true);
|
||||
auto& pointLight = cameraLight.AddLight<Nz::PointLight>(0xFFFFFFFF);
|
||||
pointLight.UpdateColor(Nz::Color::Blue);
|
||||
pointLight.UpdateRadius(3.f);
|
||||
pointLight.EnableShadowCasting(true);
|
||||
pointLight.UpdateShadowMapSize(2048);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -521,9 +522,9 @@ int main()
|
|||
Nz::DebugDrawer& debugDrawer = renderSystem.GetFramePipeline().GetDebugDrawer();
|
||||
auto& lightNode = registry.get<Nz::NodeComponent>(lightEntity3);
|
||||
//debugDrawer.DrawLine(lightNode.GetPosition(Nz::CoordSys::Global), lightNode.GetForward() * 10.f, Nz::Color::Blue);
|
||||
/*Nz::Boxf test = spotLight->GetBoundingVolume().aabb;
|
||||
debugDrawer.DrawBox(test, Nz::Color::Blue);
|
||||
debugDrawer.DrawBox(floorBox, Nz::Color::Red);
|
||||
Nz::Vector3f pos = lightNode.GetPosition(Nz::CoordSys::Global);
|
||||
debugDrawer.DrawBox(Nz::Boxf(pos.x - 0.05f, pos.y - 0.05f, pos.z - 0.05f, 0.1f, 0.1f, 0.1f), Nz::Color::Blue);
|
||||
/*debugDrawer.DrawBox(floorBox, Nz::Color::Red);
|
||||
Nz::Boxf intersection;
|
||||
if (floorBox.Intersect(test, &intersection))
|
||||
debugDrawer.DrawBox(intersection, Nz::Color::Green);*/
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ namespace Nz
|
|||
bool HasAttachment(const std::vector<FramePass::Input>& inputs, std::size_t attachmentIndex) const;
|
||||
void RemoveDuplicatePasses();
|
||||
std::size_t ResolveAttachmentIndex(std::size_t attachmentIndex) const;
|
||||
void RegisterPassInput(std::size_t passIndex, std::size_t attachmentIndex);
|
||||
std::size_t RegisterTexture(std::size_t attachmentIndex);
|
||||
void ReorderPasses();
|
||||
void TraverseGraph(std::size_t passIndex);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <Nazara/Graphics/Config.hpp>
|
||||
#include <Nazara/Graphics/FramePassAttachment.hpp>
|
||||
#include <Nazara/Math/Rect.hpp>
|
||||
#include <Nazara/Renderer/Enums.hpp>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
|
@ -73,6 +74,7 @@ namespace Nz
|
|||
inline void SetDepthStencilInput(std::size_t attachmentId);
|
||||
inline void SetDepthStencilOutput(std::size_t attachmentId);
|
||||
inline void SetExecutionCallback(ExecutionCallback callback);
|
||||
inline void SetInputLayout(std::size_t inputIndex, TextureLayout layout);
|
||||
inline void SetReadInput(std::size_t inputIndex, bool doesRead);
|
||||
|
||||
FramePass& operator=(const FramePass&) = delete;
|
||||
|
|
@ -89,6 +91,7 @@ namespace Nz
|
|||
struct Input
|
||||
{
|
||||
std::size_t attachmentId;
|
||||
std::optional<TextureLayout> assumedLayout;
|
||||
bool doesRead = true;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -128,6 +128,12 @@ namespace Nz
|
|||
m_executionCallback = std::move(callback);
|
||||
}
|
||||
|
||||
inline void FramePass::SetInputLayout(std::size_t inputIndex, TextureLayout layout)
|
||||
{
|
||||
assert(inputIndex < m_inputs.size());
|
||||
m_inputs[inputIndex].assumedLayout = layout;
|
||||
}
|
||||
|
||||
inline void FramePass::SetReadInput(std::size_t inputIndex, bool doesRead)
|
||||
{
|
||||
assert(inputIndex < m_inputs.size());
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ namespace Nz
|
|||
m_position = position;
|
||||
|
||||
UpdateBoundingVolume();
|
||||
OnLightTransformInvalided(this);
|
||||
}
|
||||
|
||||
inline void PointLight::UpdateRadius(float radius)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_GRAPHICS_POINTLIGHTSHADOWDATA_HPP
|
||||
#define NAZARA_GRAPHICS_POINTLIGHTSHADOWDATA_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Graphics/Config.hpp>
|
||||
#include <Nazara/Graphics/DepthPipelinePass.hpp>
|
||||
#include <Nazara/Graphics/Light.hpp>
|
||||
#include <Nazara/Graphics/LightShadowData.hpp>
|
||||
#include <Nazara/Graphics/ShadowViewer.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class FramePipeline;
|
||||
class PointLight;
|
||||
|
||||
class NAZARA_GRAPHICS_API PointLightShadowData : public LightShadowData
|
||||
{
|
||||
public:
|
||||
PointLightShadowData(FramePipeline& pipeline, ElementRendererRegistry& elementRegistry, const PointLight& light);
|
||||
PointLightShadowData(const PointLightShadowData&) = delete;
|
||||
PointLightShadowData(PointLightShadowData&&) = delete;
|
||||
~PointLightShadowData() = default;
|
||||
|
||||
void PrepareRendering(RenderFrame& renderFrame) override;
|
||||
|
||||
void RegisterMaterialInstance(const MaterialInstance& matInstance) override;
|
||||
void RegisterPassInputs(FramePass& pass) override;
|
||||
void RegisterToFrameGraph(FrameGraph& frameGraph) override;
|
||||
|
||||
const Texture* RetrieveLightShadowmap(const BakedFrameGraph& bakedGraph) const override;
|
||||
|
||||
void UnregisterMaterialInstance(const MaterialInstance& matInstance) override;
|
||||
|
||||
PointLightShadowData& operator=(const PointLightShadowData&) = delete;
|
||||
PointLightShadowData& operator=(PointLightShadowData&&) = delete;
|
||||
|
||||
private:
|
||||
NazaraSlot(Light, OnLightShadowMapSettingChange, m_onLightShadowMapSettingChange);
|
||||
NazaraSlot(Light, OnLightTransformInvalided, m_onLightTransformInvalidated);
|
||||
|
||||
struct DirectionData
|
||||
{
|
||||
std::optional<DepthPipelinePass> depthPass;
|
||||
std::size_t attachmentIndex;
|
||||
ShadowViewer viewer;
|
||||
};
|
||||
|
||||
std::array<DirectionData, 6> m_directions;
|
||||
std::size_t m_cubeAttachmentIndex;
|
||||
FramePipeline& m_pipeline;
|
||||
const PointLight& m_light;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/PointLightShadowData.inl>
|
||||
|
||||
#endif // NAZARA_GRAPHICS_POINTLIGHTSHADOWDATA_HPP
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/PointLightShadowData.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/DebugOff.hpp>
|
||||
|
|
@ -16,7 +16,7 @@ namespace Nz
|
|||
class NAZARA_GRAPHICS_API ShadowViewer : public AbstractViewer
|
||||
{
|
||||
public:
|
||||
inline ShadowViewer(const Recti& viewport, UInt32 renderMask);
|
||||
ShadowViewer() = default;
|
||||
ShadowViewer(const ShadowViewer&) = delete;
|
||||
ShadowViewer(ShadowViewer&&) = delete;
|
||||
~ShadowViewer() = default;
|
||||
|
|
|
|||
|
|
@ -7,12 +7,6 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
inline ShadowViewer::ShadowViewer(const Recti& viewport, UInt32 renderMask) :
|
||||
m_renderMask(renderMask)
|
||||
{
|
||||
UpdateViewport(viewport);
|
||||
}
|
||||
|
||||
inline void ShadowViewer::UpdateRenderMask(UInt32 renderMask)
|
||||
{
|
||||
m_renderMask = renderMask;
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ namespace Nz::GL
|
|||
const Context& context = EnsureDeviceContext();
|
||||
|
||||
if (context.glObjectLabel)
|
||||
context.glObjectLabel(ObjectType, m_objectId, name.size(), name.data());
|
||||
context.glObjectLabel(ObjectType, m_objectId, SafeCast<GLsizei>(name.size()), name.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -712,9 +712,13 @@ namespace Nz
|
|||
std::size_t textureId = Retrieve(m_pending.attachmentToTextures, input.attachmentId);
|
||||
|
||||
TextureLayout& textureLayout = textureLayouts[textureId];
|
||||
assert(textureLayouts[textureId] != TextureLayout::Undefined);
|
||||
|
||||
textureLayout = TextureLayout::ColorInput;
|
||||
if (!input.assumedLayout)
|
||||
{
|
||||
assert(textureLayouts[textureId] != TextureLayout::Undefined);
|
||||
textureLayout = TextureLayout::ColorInput;
|
||||
}
|
||||
else
|
||||
textureLayout = *input.assumedLayout;
|
||||
};
|
||||
|
||||
auto RegisterColorOutput = [&](const FramePass::Output& output, bool shouldLoad)
|
||||
|
|
@ -949,7 +953,21 @@ namespace Nz
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void FrameGraph::RegisterPassInput(std::size_t passIndex, std::size_t attachmentIndex)
|
||||
{
|
||||
auto it = m_pending.attachmentWriteList.find(attachmentIndex);
|
||||
if (it != m_pending.attachmentWriteList.end())
|
||||
{
|
||||
const PassList& dependencyPassList = it->second;
|
||||
for (std::size_t dependencyPass : dependencyPassList)
|
||||
{
|
||||
if (dependencyPass != passIndex)
|
||||
TraverseGraph(dependencyPass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t FrameGraph::RegisterTexture(std::size_t attachmentIndex)
|
||||
{
|
||||
if (auto it = m_pending.attachmentToTextures.find(attachmentIndex); it != m_pending.attachmentToTextures.end())
|
||||
|
|
@ -1126,31 +1144,9 @@ namespace Nz
|
|||
|
||||
const FramePass& framePass = m_framePasses[passIndex];
|
||||
for (const auto& input : framePass.GetInputs())
|
||||
{
|
||||
auto it = m_pending.attachmentWriteList.find(input.attachmentId);
|
||||
if (it != m_pending.attachmentWriteList.end())
|
||||
{
|
||||
const PassList& dependencyPassList = it->second;
|
||||
for (std::size_t dependencyPass : dependencyPassList)
|
||||
{
|
||||
if (dependencyPass != passIndex)
|
||||
TraverseGraph(dependencyPass);
|
||||
}
|
||||
}
|
||||
}
|
||||
RegisterPassInput(passIndex, input.attachmentId);
|
||||
|
||||
if (std::size_t dsInput = framePass.GetDepthStencilInput(); dsInput != FramePass::InvalidAttachmentId)
|
||||
{
|
||||
auto it = m_pending.attachmentWriteList.find(dsInput);
|
||||
if (it != m_pending.attachmentWriteList.end())
|
||||
{
|
||||
const PassList& dependencyPassList = it->second;
|
||||
for (std::size_t dependencyPass : dependencyPassList)
|
||||
{
|
||||
if (dependencyPass != passIndex)
|
||||
TraverseGraph(dependencyPass);
|
||||
}
|
||||
}
|
||||
}
|
||||
RegisterPassInput(passIndex, dsInput);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <Nazara/Graphics/PointLight.hpp>
|
||||
#include <Nazara/Graphics/Enums.hpp>
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <Nazara/Graphics/PointLightShadowData.hpp>
|
||||
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
|
||||
#include <Nazara/Math/Vector2.hpp>
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
|
|
@ -26,13 +27,14 @@ namespace Nz
|
|||
AccessByOffset<UInt32&>(data, lightOffset.lightMemberOffsets.type) = UnderlyingCast(BasicLightType::Point);
|
||||
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.color) = Vector4f(m_color.r, m_color.g, m_color.b, m_color.a);
|
||||
AccessByOffset<Vector2f&>(data, lightOffset.lightMemberOffsets.factor) = Vector2f(m_ambientFactor, m_diffuseFactor);
|
||||
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter1) = Vector4f(m_position.x, m_position.y, m_position.z, m_invRadius);
|
||||
AccessByOffset<Vector2f&>(data, lightOffset.lightMemberOffsets.shadowMapSize) = Vector2f(-1.f, -1.f);
|
||||
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter1) = Vector4f(m_position.x, m_position.y, m_position.z, 0.f);
|
||||
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter2) = Vector4f(m_radius, m_invRadius, 0.f, 0.f);
|
||||
AccessByOffset<Vector2f&>(data, lightOffset.lightMemberOffsets.shadowMapSize) = (IsShadowCaster()) ? Vector2f(1.f / GetShadowMapSize()) : Vector2f(-1.f, -1.f);
|
||||
}
|
||||
|
||||
std::unique_ptr<LightShadowData> PointLight::InstanciateShadowData(FramePipeline& pipeline, ElementRendererRegistry& elementRegistry) const
|
||||
{
|
||||
return nullptr; //< TODO
|
||||
return std::make_unique<PointLightShadowData>(pipeline, elementRegistry, *this);
|
||||
}
|
||||
|
||||
void PointLight::UpdateTransform(const Vector3f& position, const Quaternionf& /*rotation*/, const Vector3f& /*scale*/)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,150 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/PointLightShadowData.hpp>
|
||||
#include <Nazara/Graphics/BakedFrameGraph.hpp>
|
||||
#include <Nazara/Graphics/FrameGraph.hpp>
|
||||
#include <Nazara/Graphics/FramePipeline.hpp>
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <Nazara/Graphics/PointLight.hpp>
|
||||
#include <Nazara/Math/Quaternion.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
// TODO: Make it constexpr
|
||||
std::array s_dirRotations = {
|
||||
Quaternionf::RotationBetween(Vector3f::Forward(), Vector3f::UnitX()),
|
||||
Quaternionf::RotationBetween(Vector3f::Forward(), -Vector3f::UnitX()),
|
||||
Quaternionf::RotationBetween(Vector3f::Forward(), Vector3f::UnitY()),
|
||||
Quaternionf::RotationBetween(Vector3f::Forward(), -Vector3f::UnitY()),
|
||||
Quaternionf::Identity(),
|
||||
Quaternionf(0.f, 0.f, 1.f, 0.f)
|
||||
};
|
||||
|
||||
constexpr std::array<std::string_view, 6> s_dirNames = {
|
||||
"Point-light shadow mapping +X",
|
||||
"Point-light shadow mapping -X",
|
||||
"Point-light shadow mapping +Y",
|
||||
"Point-light shadow mapping -Y",
|
||||
"Point-light shadow mapping +Z",
|
||||
"Point-light shadow mapping -Z"
|
||||
};
|
||||
}
|
||||
|
||||
PointLightShadowData::PointLightShadowData(FramePipeline& pipeline, ElementRendererRegistry& elementRegistry, const PointLight& light) :
|
||||
m_pipeline(pipeline),
|
||||
m_light(light)
|
||||
{
|
||||
m_onLightShadowMapSettingChange.Connect(m_light.OnLightShadowMapSettingChange, [this](Light* /*light*/, PixelFormat /*newPixelFormat*/, UInt32 newSize)
|
||||
{
|
||||
for (DirectionData& direction : m_directions)
|
||||
direction.viewer.UpdateViewport(Recti(0, 0, SafeCast<int>(newSize), SafeCast<int>(newSize)));
|
||||
});
|
||||
|
||||
m_onLightTransformInvalidated.Connect(m_light.OnLightTransformInvalided, [this]([[maybe_unused]] Light* light)
|
||||
{
|
||||
assert(&m_light == light);
|
||||
|
||||
for (std::size_t i = 0; i < m_directions.size(); ++i)
|
||||
{
|
||||
DirectionData& direction = m_directions[i];
|
||||
|
||||
ViewerInstance& viewerInstance = direction.viewer.GetViewerInstance();
|
||||
viewerInstance.UpdateEyePosition(m_light.GetPosition());
|
||||
viewerInstance.UpdateViewMatrix(Matrix4f::TransformInverse(m_light.GetPosition(), s_dirRotations[i]));
|
||||
|
||||
m_pipeline.QueueTransfer(&viewerInstance);
|
||||
}
|
||||
});
|
||||
|
||||
std::size_t shadowPassIndex = Graphics::Instance()->GetMaterialPassRegistry().GetPassIndex("ShadowPass");
|
||||
|
||||
UInt32 shadowMapSize = light.GetShadowMapSize();
|
||||
for (std::size_t i = 0; i < m_directions.size(); ++i)
|
||||
{
|
||||
ShadowViewer& viewer = m_directions[i].viewer;
|
||||
|
||||
viewer.UpdateRenderMask(0xFFFFFFFF);
|
||||
viewer.UpdateViewport(Recti(0, 0, SafeCast<int>(shadowMapSize), SafeCast<int>(shadowMapSize)));
|
||||
|
||||
ViewerInstance& viewerInstance = viewer.GetViewerInstance();
|
||||
viewerInstance.UpdateProjectionMatrix(Matrix4f::Perspective(RadianAnglef(HalfPi<float>), 1.f, 0.01f, m_light.GetRadius()));
|
||||
viewerInstance.UpdateEyePosition(m_light.GetPosition());
|
||||
viewerInstance.UpdateViewMatrix(Matrix4f::TransformInverse(m_light.GetPosition(), s_dirRotations[i]));
|
||||
|
||||
m_pipeline.QueueTransfer(&viewerInstance);
|
||||
|
||||
m_directions[i].depthPass.emplace(m_pipeline, elementRegistry, &viewer, shadowPassIndex, std::string(s_dirNames[i]));
|
||||
}
|
||||
|
||||
m_pipeline.ForEachRegisteredMaterialInstance([this](const MaterialInstance& matInstance)
|
||||
{
|
||||
for (DirectionData& direction : m_directions)
|
||||
direction.depthPass->RegisterMaterialInstance(matInstance);
|
||||
});
|
||||
}
|
||||
|
||||
void PointLightShadowData::PrepareRendering(RenderFrame& renderFrame)
|
||||
{
|
||||
for (DirectionData& direction : m_directions)
|
||||
{
|
||||
const Matrix4f& viewProjMatrix = direction.viewer.GetViewerInstance().GetViewProjMatrix();
|
||||
|
||||
Frustumf frustum = Frustumf::Extract(viewProjMatrix);
|
||||
|
||||
std::size_t visibilityHash = 5U;
|
||||
const auto& visibleRenderables = m_pipeline.FrustumCull(frustum, 0xFFFFFFFF, visibilityHash);
|
||||
|
||||
direction.depthPass->Prepare(renderFrame, frustum, visibleRenderables, visibilityHash);
|
||||
}
|
||||
}
|
||||
|
||||
void PointLightShadowData::RegisterMaterialInstance(const MaterialInstance& matInstance)
|
||||
{
|
||||
for (DirectionData& direction : m_directions)
|
||||
direction.depthPass->RegisterMaterialInstance(matInstance);
|
||||
}
|
||||
|
||||
void PointLightShadowData::RegisterPassInputs(FramePass& pass)
|
||||
{
|
||||
std::size_t cubeInputIndex = pass.AddInput(m_cubeAttachmentIndex);
|
||||
pass.SetInputLayout(cubeInputIndex, TextureLayout::ColorInput);
|
||||
|
||||
for (DirectionData& direction : m_directions)
|
||||
pass.AddInput(direction.attachmentIndex);
|
||||
}
|
||||
|
||||
void PointLightShadowData::RegisterToFrameGraph(FrameGraph& frameGraph)
|
||||
{
|
||||
UInt32 shadowMapSize = m_light.GetShadowMapSize();
|
||||
|
||||
m_cubeAttachmentIndex = frameGraph.AddAttachmentCube({
|
||||
"Point-light shadowmap",
|
||||
m_light.GetShadowMapFormat(),
|
||||
FramePassAttachmentSize::Fixed,
|
||||
shadowMapSize, shadowMapSize,
|
||||
});
|
||||
|
||||
for (std::size_t i = 0; i < m_directions.size(); ++i)
|
||||
{
|
||||
DirectionData& direction = m_directions[i];
|
||||
direction.attachmentIndex = frameGraph.AddAttachmentCubeFace(m_cubeAttachmentIndex, static_cast<CubemapFace>(i));
|
||||
direction.depthPass->RegisterToFrameGraph(frameGraph, direction.attachmentIndex);
|
||||
}
|
||||
}
|
||||
|
||||
const Texture* PointLightShadowData::RetrieveLightShadowmap(const BakedFrameGraph& bakedGraph) const
|
||||
{
|
||||
return bakedGraph.GetAttachmentTexture(m_cubeAttachmentIndex).get();
|
||||
}
|
||||
|
||||
void PointLightShadowData::UnregisterMaterialInstance(const MaterialInstance& matInstance)
|
||||
{
|
||||
for (DirectionData& direction : m_directions)
|
||||
direction.depthPass->UnregisterMaterialInstance(matInstance);
|
||||
}
|
||||
}
|
||||
|
|
@ -98,7 +98,7 @@ external
|
|||
[tag("SkeletalData")] skeletalData: uniform[SkeletalData],
|
||||
[tag("LightData")] lightData: uniform[LightData],
|
||||
[tag("ShadowMaps2D")] shadowMaps2D: array[depth_sampler2D[f32], MaxLightCount],
|
||||
[tag("ShadowMapsCube")] shadowMapsCube: array[depth_sampler_cube[f32], MaxLightCount]
|
||||
[tag("ShadowMapsCube")] shadowMapsCube: array[sampler_cube[f32], MaxLightCount]
|
||||
}
|
||||
|
||||
struct VertToFrag
|
||||
|
|
@ -118,6 +118,11 @@ struct FragOut
|
|||
[location(0)] RenderTarget0: vec4[f32]
|
||||
}
|
||||
|
||||
fn LinearizeDepth(depth: f32, zNear: f32, zFar: f32) -> f32
|
||||
{
|
||||
return zNear * zFar / (zFar + depth * (zNear - zFar));
|
||||
}
|
||||
|
||||
[entry(frag), cond(!DepthPass || AlphaTest)]
|
||||
fn main(input: VertToFrag) -> FragOut
|
||||
{
|
||||
|
|
@ -189,25 +194,60 @@ fn main(input: VertToFrag) -> FragOut
|
|||
else if (light.type == PointLight)
|
||||
{
|
||||
let lightPos = light.parameter1.xyz;
|
||||
let lightInvRadius = light.parameter1.w;
|
||||
let lightRadius = light.parameter2.x;
|
||||
let lightInvRadius = light.parameter2.y;
|
||||
|
||||
let lightToPos = input.worldPos - lightPos;
|
||||
let dist = length(lightToPos);
|
||||
let lightToPosNorm = lightToPos / max(dist, 0.0001);
|
||||
|
||||
let attenuationFactor = max(1.0 - dist * lightInvRadius, 0.0);
|
||||
|
||||
lightAmbient += attenuationFactor * light.color.rgb * lightAmbientFactor * settings.AmbientColor.rgb;
|
||||
|
||||
let lambert = max(dot(normal, -lightToPosNorm), 0.0);
|
||||
|
||||
lightDiffuse += attenuationFactor * lambert * light.color.rgb * lightDiffuseFactor;
|
||||
|
||||
let reflection = reflect(lightToPosNorm, normal);
|
||||
let specFactor = max(dot(reflection, eyeVec), 0.0);
|
||||
specFactor = pow(specFactor, settings.Shininess);
|
||||
|
||||
lightSpecular += attenuationFactor * specFactor * light.color.rgb;
|
||||
let shadowFactor = 1.0;
|
||||
if (light.invShadowMapSize.x > 0.0)
|
||||
{
|
||||
shadowFactor = 0.0;
|
||||
|
||||
let sampleDir = vec3[f32](lightToPosNorm.x, lightToPosNorm.y, -lightToPosNorm.z);
|
||||
|
||||
const sampleCount = 4;
|
||||
const offset = 0.005;
|
||||
const bias = 0.05;
|
||||
|
||||
const invSampleCount = 1.0 / f32(sampleCount);
|
||||
const start = vec3[f32](offset * 0.5, offset * 0.5, offset * 0.5);
|
||||
const shadowContribution = 1.0 / f32(sampleCount * sampleCount * sampleCount);
|
||||
|
||||
[unroll]
|
||||
for x in 0 -> sampleCount
|
||||
{
|
||||
[unroll]
|
||||
for y in 0 -> sampleCount
|
||||
{
|
||||
[unroll]
|
||||
for z in 0 -> sampleCount
|
||||
{
|
||||
let dirOffset = vec3[f32](f32(x), f32(y), f32(z)) * invSampleCount * offset - start;
|
||||
let sampleDir = sampleDir + dirOffset;
|
||||
|
||||
let depth = shadowMapsCube[i].Sample(sampleDir).r;
|
||||
depth = LinearizeDepth(depth, 0.01, lightRadius);
|
||||
|
||||
if (depth > dist - bias)
|
||||
shadowFactor += shadowContribution;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lightAmbient += attenuationFactor * light.color.rgb * lightAmbientFactor * settings.AmbientColor.rgb;
|
||||
lightDiffuse += shadowFactor * attenuationFactor * lambert * light.color.rgb * lightDiffuseFactor;
|
||||
lightSpecular += shadowFactor * attenuationFactor * specFactor * light.color.rgb;
|
||||
}
|
||||
else if (light.type == SpotLight)
|
||||
{
|
||||
|
|
@ -233,10 +273,11 @@ fn main(input: VertToFrag) -> FragOut
|
|||
let specFactor = max(dot(reflection, eyeVec), 0.0);
|
||||
specFactor = pow(specFactor, settings.Shininess);
|
||||
|
||||
let shadowFactor = 0.0;
|
||||
let shadowFactor = 1.0;
|
||||
if (light.invShadowMapSize.x > 0.0)
|
||||
{
|
||||
let shadowCoords = input.lightProjPos[i].xyz / input.lightProjPos[i].w;
|
||||
shadowFactor = 0.0;
|
||||
[unroll]
|
||||
for x in -1 -> 2
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ namespace Nz
|
|||
{
|
||||
SpotLightShadowData::SpotLightShadowData(FramePipeline& pipeline, ElementRendererRegistry& elementRegistry, const SpotLight& light) :
|
||||
m_pipeline(pipeline),
|
||||
m_light(light),
|
||||
m_viewer(Recti(0, 0, 1, 1), 0xFFFFFFFF)
|
||||
m_light(light)
|
||||
{
|
||||
UInt32 shadowMapSize = light.GetShadowMapSize();
|
||||
m_viewer.UpdateRenderMask(0xFFFFFFFF);
|
||||
m_viewer.UpdateViewport(Recti(0, 0, SafeCast<int>(shadowMapSize), SafeCast<int>(shadowMapSize)));
|
||||
|
||||
ViewerInstance& viewerInstance = m_viewer.GetViewerInstance();
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ namespace Nz
|
|||
auto& bindingEntry = m_bindingCache.emplace_back();
|
||||
bindingEntry.bindingIndex = bindingIndex;
|
||||
bindingEntry.content = ShaderBinding::TextureBindings {
|
||||
SafeCast<UInt32>(renderState.shadowMaps2D.size()), &m_textureBindingCache[textureBindingBaseIndex]
|
||||
SafeCast<UInt32>(renderState.shadowMapsCube.size()), &m_textureBindingCache[textureBindingBaseIndex]
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
void OpenGLShaderBinding::UpdateDebugName(std::string_view name)
|
||||
void OpenGLShaderBinding::UpdateDebugName(std::string_view /*name*/)
|
||||
{
|
||||
// No OpenGL object to name
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue