diff --git a/SDK/include/NDK/Systems/RenderSystem.hpp b/SDK/include/NDK/Systems/RenderSystem.hpp index 522f1c775..0baae7684 100644 --- a/SDK/include/NDK/Systems/RenderSystem.hpp +++ b/SDK/include/NDK/Systems/RenderSystem.hpp @@ -8,6 +8,7 @@ #define NDK_SYSTEMS_RENDERSYSTEM_HPP #include +#include #include #include #include @@ -31,11 +32,14 @@ namespace Ndk private: void OnEntityRemoved(Entity* entity) override; void OnEntityValidation(Entity* entity, bool justAdded) override; + void UpdateShadowMaps(); EntityList m_cameras; EntityList m_drawables; EntityList m_lights; NzForwardRenderTechnique m_renderTechnique; + NzForwardRenderTechnique m_shadowTechnique; + NzRenderTexture m_shadowRT; }; } diff --git a/SDK/src/NDK/Systems/RenderSystem.cpp b/SDK/src/NDK/Systems/RenderSystem.cpp index 1f781e951..4f6f27f86 100644 --- a/SDK/src/NDK/Systems/RenderSystem.cpp +++ b/SDK/src/NDK/Systems/RenderSystem.cpp @@ -3,7 +3,9 @@ // For conditions of distribution and use, see copyright notice in Prerequesites.hpp #include +#include #include +#include #include #include #include @@ -17,6 +19,8 @@ namespace Ndk void RenderSystem::Update(float elapsedTime) { + UpdateShadowMaps(); + for (const Ndk::EntityHandle& camera : m_cameras) { CameraComponent& camComponent = camera->GetComponent(); @@ -25,10 +29,10 @@ namespace Ndk NzAbstractRenderQueue* renderQueue = m_renderTechnique.GetRenderQueue(); renderQueue->Clear(); - for (const Ndk::EntityHandle& light : m_drawables) + for (const Ndk::EntityHandle& drawable : m_drawables) { - GraphicsComponent& graphicsComponent = light->GetComponent(); - NodeComponent& drawableNode = light->GetComponent(); + GraphicsComponent& graphicsComponent = drawable->GetComponent(); + NodeComponent& drawableNode = drawable->GetComponent(); graphicsComponent.AddToRenderQueue(renderQueue); } @@ -36,9 +40,9 @@ namespace Ndk for (const Ndk::EntityHandle& light : m_lights) { LightComponent& lightComponent = light->GetComponent(); - NodeComponent& drawableNode = light->GetComponent(); + NodeComponent& lightNode = light->GetComponent(); - lightComponent.AddToRenderQueue(renderQueue, drawableNode.GetTransformMatrix()); + lightComponent.AddToRenderQueue(renderQueue, lightNode.GetTransformMatrix()); } NzColorBackground background; @@ -83,5 +87,55 @@ namespace Ndk m_lights.Remove(entity); } + void RenderSystem::UpdateShadowMaps() + { + if (!m_shadowRT.IsValid()) + m_shadowRT.Create(); + + for (const Ndk::EntityHandle& light : m_lights) + { + LightComponent& lightComponent = light->GetComponent(); + NodeComponent& lightNode = light->GetComponent(); + + if (!lightComponent.IsShadowCastingEnabled() || lightComponent.GetLightType() != nzLightType_Spot) + continue; + + /// HACKY + NzCamera lightPOV; + lightPOV.SetPosition(lightNode.GetPosition()); + lightPOV.SetFOV(lightComponent.GetOuterAngle()); + lightPOV.SetRotation(lightNode.GetRotation()); + lightPOV.SetZFar(1000.f); + lightPOV.SetTarget(&m_shadowRT); + + NzVector2ui shadowMapSize(lightComponent.GetShadowMap()->GetSize()); + + m_shadowRT.AttachTexture(nzAttachmentPoint_Depth, 0, lightComponent.GetShadowMap()); + + NzRenderer::SetMatrix(nzMatrixType_Projection, lightPOV.GetProjectionMatrix()); + NzRenderer::SetMatrix(nzMatrixType_View, lightPOV.GetViewMatrix()); + NzRenderer::SetTarget(&m_shadowRT); + NzRenderer::SetViewport(NzRecti(0, 0, shadowMapSize.x, shadowMapSize.y)); + + NzAbstractRenderQueue* renderQueue = m_renderTechnique.GetRenderQueue(); + renderQueue->Clear(); + + for (const Ndk::EntityHandle& drawable : m_drawables) + { + GraphicsComponent& graphicsComponent = drawable->GetComponent(); + NodeComponent& drawableNode = drawable->GetComponent(); + + graphicsComponent.AddToRenderQueue(renderQueue); + } + + NzSceneData sceneData; + sceneData.ambientColor = NzColor(0, 0, 0); + sceneData.background = nullptr; + sceneData.viewer = &lightPOV; + + m_renderTechnique.Draw(sceneData); + } + } + SystemIndex RenderSystem::systemIndex; } diff --git a/include/Nazara/Graphics/Light.hpp b/include/Nazara/Graphics/Light.hpp index 9a6a4235b..a28a86c17 100644 --- a/include/Nazara/Graphics/Light.hpp +++ b/include/Nazara/Graphics/Light.hpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include class NzLight; struct NzLightUniforms; @@ -19,7 +21,7 @@ class NAZARA_GRAPHICS_API NzLight : public NzRenderable { public: NzLight(nzLightType type = nzLightType_Point); - NzLight(const NzLight& light) = default; + inline NzLight(const NzLight& light); ~NzLight() = default; void AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatrix4f& transformMatrix) const override; @@ -29,37 +31,48 @@ class NAZARA_GRAPHICS_API NzLight : public NzRenderable bool Cull(const NzFrustumf& frustum, const NzMatrix4f& transformMatrix) const override; - float GetAmbientFactor() const; - float GetAttenuation() const; - NzColor GetColor() const; - float GetDiffuseFactor() const; - float GetInnerAngle() const; - float GetInnerAngleCosine() const; - float GetInvRadius() const; - nzLightType GetLightType() const; - float GetOuterAngle() const; - float GetOuterAngleCosine() const; - float GetOuterAngleTangent() const; - float GetRadius() const; + inline void EnableShadowCasting(bool castShadows); - void SetAmbientFactor(float factor); - void SetAttenuation(float attenuation); - void SetColor(const NzColor& color); - void SetDiffuseFactor(float factor); - void SetInnerAngle(float innerAngle); - void SetLightType(nzLightType type); - void SetOuterAngle(float outerAngle); - void SetRadius(float radius); + inline void EnsureShadowMapUpdate() const; + + inline float GetAmbientFactor() const; + inline float GetAttenuation() const; + inline NzColor GetColor() const; + inline float GetDiffuseFactor() const; + inline float GetInnerAngle() const; + inline float GetInnerAngleCosine() const; + inline float GetInvRadius() const; + inline nzLightType GetLightType() const; + inline float GetOuterAngle() const; + inline float GetOuterAngleCosine() const; + inline float GetOuterAngleTangent() const; + inline float GetRadius() const; + inline NzTextureRef GetShadowMap() const; + + inline bool IsShadowCastingEnabled() const; + + inline void SetAmbientFactor(float factor); + inline void SetAttenuation(float attenuation); + inline void SetColor(const NzColor& color); + inline void SetDiffuseFactor(float factor); + inline void SetInnerAngle(float innerAngle); + inline void SetLightType(nzLightType type); + inline void SetOuterAngle(float outerAngle); + inline void SetRadius(float radius); void UpdateBoundingVolume(const NzMatrix4f& transformMatrix) override; - NzLight& operator=(const NzLight& light) = default; + NzLight& operator=(const NzLight& light); private: void MakeBoundingVolume() const override; + void UpdateShadowMap() const; nzLightType m_type; NzColor m_color; + mutable NzTextureRef m_shadowMap; + bool m_shadowCastingEnabled; + mutable bool m_shadowMapUpdated; float m_ambientFactor; float m_attenuation; float m_diffuseFactor; diff --git a/include/Nazara/Graphics/Light.inl b/include/Nazara/Graphics/Light.inl index ecda520a4..d981e95bb 100644 --- a/include/Nazara/Graphics/Light.inl +++ b/include/Nazara/Graphics/Light.inl @@ -5,6 +5,40 @@ #include #include +inline NzLight::NzLight(const NzLight& light) : +NzRenderable(light), +m_type(light.m_type), +m_color(light.m_color), +m_shadowCastingEnabled(light.m_shadowCastingEnabled), +m_shadowMapUpdated(false), +m_ambientFactor(light.m_ambientFactor), +m_attenuation(light.m_attenuation), +m_diffuseFactor(light.m_diffuseFactor), +m_innerAngle(light.m_innerAngle), +m_innerAngleCosine(light.m_innerAngleCosine), +m_invRadius(light.m_invRadius), +m_outerAngle(light.m_outerAngle), +m_outerAngleCosine(light.m_outerAngleCosine), +m_outerAngleTangent(light.m_outerAngleTangent), +m_radius(light.m_radius) +{ +} + +inline void NzLight::EnableShadowCasting(bool castShadows) +{ + if (m_shadowCastingEnabled != castShadows) + { + m_shadowCastingEnabled = castShadows; + m_shadowMapUpdated = false; + } +} + +inline void NzLight::EnsureShadowMapUpdate() const +{ + if (!m_shadowMapUpdated) + UpdateShadowMap(); +} + inline float NzLight::GetAmbientFactor() const { return m_ambientFactor; @@ -45,6 +79,18 @@ inline float NzLight::GetRadius() const return m_radius; } +inline NzTextureRef NzLight::GetShadowMap() const +{ + EnsureShadowMapUpdate(); + + return m_shadowMap; +} + +inline bool NzLight::IsShadowCastingEnabled() const +{ + return m_shadowCastingEnabled; +} + inline void NzLight::SetAmbientFactor(float factor) { m_ambientFactor = factor; @@ -94,4 +140,26 @@ inline void NzLight::SetRadius(float radius) InvalidateBoundingVolume(); } +inline NzLight& NzLight::operator=(const NzLight& light) +{ + NzRenderable::operator=(light); + + m_ambientFactor = light.m_ambientFactor; + m_attenuation = light.m_attenuation; + m_color = light.m_color; + m_diffuseFactor = light.m_diffuseFactor; + m_innerAngle = light.m_innerAngle; + m_innerAngleCosine = light.m_innerAngleCosine; + m_invRadius = light.m_invRadius; + m_outerAngle = light.m_outerAngle; + m_outerAngleCosine = light.m_outerAngleCosine; + m_outerAngleTangent = light.m_outerAngleTangent; + m_radius = light.m_radius; + m_shadowCastingEnabled = light.m_shadowCastingEnabled; + m_shadowMapUpdated = false; + m_type = light.m_type; + + return *this; +} + #include diff --git a/src/Nazara/Graphics/Light.cpp b/src/Nazara/Graphics/Light.cpp index 35717498f..0bc491511 100644 --- a/src/Nazara/Graphics/Light.cpp +++ b/src/Nazara/Graphics/Light.cpp @@ -17,7 +17,9 @@ ///TODO: Scale ? NzLight::NzLight(nzLightType type) : -m_type(type) +m_type(type), +m_shadowCastingEnabled(false), +m_shadowMapUpdated(false) { SetAmbientFactor((type == nzLightType_Directional) ? 0.2f : 0.f); SetAttenuation(0.9f); @@ -177,3 +179,18 @@ void NzLight::MakeBoundingVolume() const break; } } + +void NzLight::UpdateShadowMap() const +{ + if (m_shadowCastingEnabled) + { + if (!m_shadowMap) + m_shadowMap = NzTexture::New(); + + m_shadowMap->Create(nzImageType_2D, nzPixelFormat_Depth16, 256, 256); + } + else + m_shadowMap.Reset(); + + m_shadowMapUpdated = true; +} diff --git a/src/Nazara/Renderer/RenderTexture.cpp b/src/Nazara/Renderer/RenderTexture.cpp index f2dc61bfc..c9dc2d611 100644 --- a/src/Nazara/Renderer/RenderTexture.cpp +++ b/src/Nazara/Renderer/RenderTexture.cpp @@ -148,6 +148,9 @@ bool NzRenderTexture::AttachBuffer(nzAttachmentPoint attachmentPoint, nzUInt8 in Unlock(); unsigned int attachIndex = attachmentIndex[attachmentPoint] + index; + if (attachIndex >= m_impl->attachments.size()) + m_impl->attachments.resize(attachIndex+1); + Attachment& attachment = m_impl->attachments[attachIndex]; attachment.attachmentPoint = attachmentPoint; attachment.buffer = buffer; @@ -286,6 +289,9 @@ bool NzRenderTexture::AttachTexture(nzAttachmentPoint attachmentPoint, nzUInt8 i Unlock(); unsigned int attachIndex = attachmentIndex[attachmentPoint] + index; + if (attachIndex >= m_impl->attachments.size()) + m_impl->attachments.resize(attachIndex+1); + Attachment& attachment = m_impl->attachments[attachIndex]; attachment.attachmentPoint = attachmentPoint; attachment.isBuffer = false;