diff --git a/include/Nazara/Graphics/ForwardRenderTechnique.hpp b/include/Nazara/Graphics/ForwardRenderTechnique.hpp index 179fcd863..de5c86e26 100644 --- a/include/Nazara/Graphics/ForwardRenderTechnique.hpp +++ b/include/Nazara/Graphics/ForwardRenderTechnique.hpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -21,8 +20,8 @@ class NAZARA_API NzForwardRenderTechnique : public NzAbstractRenderTechnique NzForwardRenderTechnique(); ~NzForwardRenderTechnique() = default; - void Clear(const NzScene* scene) const; - bool Draw(const NzScene* scene) const; + void Clear(const NzScene* scene) const override; + bool Draw(const NzScene* scene) const override; unsigned int GetMaxLightPassPerObject() const; NzAbstractRenderQueue* GetRenderQueue() override; @@ -36,11 +35,27 @@ class NAZARA_API NzForwardRenderTechnique : public NzAbstractRenderTechnique private: struct ShaderUniforms; + bool ChooseLights(const NzSpheref& object, bool includeDirectionalLights = true) const; void DrawBasicSprites(const NzScene* scene) const; void DrawBillboards(const NzScene* scene) const; void DrawOpaqueModels(const NzScene* scene) const; void DrawTransparentModels(const NzScene* scene) const; const ShaderUniforms* GetShaderUniforms(const NzShader* shader) const; + void SendLightUniforms(const NzShader* shader, const NzLightUniforms& uniforms, unsigned int uniformOffset, unsigned int index) const; + + static float ComputeDirectionalLightScore(const NzSpheref& object, const NzAbstractRenderQueue::DirectionalLight& light); + static float ComputePointLightScore(const NzSpheref& object, const NzAbstractRenderQueue::PointLight& light); + static float ComputeSpotLightScore(const NzSpheref& object, const NzAbstractRenderQueue::SpotLight& light); + static bool IsDirectionalLightSuitable(const NzSpheref& object, const NzAbstractRenderQueue::DirectionalLight& light); + static bool IsPointLightSuitable(const NzSpheref& object, const NzAbstractRenderQueue::PointLight& light); + static bool IsSpotLightSuitable(const NzSpheref& object, const NzAbstractRenderQueue::SpotLight& light); + + struct LightIndex + { + nzLightType type; + float score; + unsigned int index; + }; struct ShaderUniforms { @@ -58,10 +73,9 @@ class NAZARA_API NzForwardRenderTechnique : public NzAbstractRenderTechnique }; mutable std::unordered_map m_shaderUniforms; + mutable std::vector m_lights; NzBuffer m_vertexBuffer; mutable NzForwardRenderQueue m_renderQueue; - mutable NzLightManager m_directionalLights; - mutable NzLightManager m_lights; NzVertexBuffer m_billboardPointBuffer; NzVertexBuffer m_spriteBuffer; unsigned int m_maxLightPassPerObject; @@ -72,4 +86,6 @@ class NAZARA_API NzForwardRenderTechnique : public NzAbstractRenderTechnique static NzVertexDeclaration s_billboardVertexDeclaration; }; +#include + #endif // NAZARA_FORWARDRENDERTECHNIQUE_HPP diff --git a/include/Nazara/Graphics/ForwardRenderTechnique.inl b/include/Nazara/Graphics/ForwardRenderTechnique.inl new file mode 100644 index 000000000..c808f3312 --- /dev/null +++ b/include/Nazara/Graphics/ForwardRenderTechnique.inl @@ -0,0 +1,87 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +inline void NzForwardRenderTechnique::SendLightUniforms(const NzShader* shader, const NzLightUniforms& uniforms, unsigned int uniformOffset, unsigned int index) const +{ + if (index < m_lights.size()) + { + const LightIndex& lightIndex = m_lights[index]; + + shader->SendInteger(uniforms.locations.type + uniformOffset, lightIndex.type); //< Sends the light type + + switch (lightIndex.type) + { + case nzLightType_Directional: + { + const auto& light = m_renderQueue.directionalLights[lightIndex.index]; + + shader->SendColor(uniforms.locations.color + uniformOffset, light.color); + shader->SendVector(uniforms.locations.factors + uniformOffset, NzVector2f(light.ambientFactor, light.diffuseFactor)); + shader->SendVector(uniforms.locations.parameters1 + uniformOffset, NzVector4f(light.direction)); + break; + } + + case nzLightType_Point: + { + const auto& light = m_renderQueue.pointLights[lightIndex.index]; + + shader->SendColor(uniforms.locations.color + uniformOffset, light.color); + shader->SendVector(uniforms.locations.factors + uniformOffset, NzVector2f(light.ambientFactor, light.diffuseFactor)); + shader->SendVector(uniforms.locations.parameters1 + uniformOffset, NzVector4f(light.position, light.attenuation)); + shader->SendVector(uniforms.locations.parameters2 + uniformOffset, NzVector4f(0.f, 0.f, 0.f, light.invRadius)); + break; + } + + case nzLightType_Spot: + { + const auto& light = m_renderQueue.spotLights[lightIndex.index]; + + shader->SendColor(uniforms.locations.color + uniformOffset, light.color); + shader->SendVector(uniforms.locations.factors + uniformOffset, NzVector2f(light.ambientFactor, light.diffuseFactor)); + shader->SendVector(uniforms.locations.parameters1 + uniformOffset, NzVector4f(light.position, light.attenuation)); + shader->SendVector(uniforms.locations.parameters2 + uniformOffset, NzVector4f(light.direction, light.invRadius)); + shader->SendVector(uniforms.locations.parameters3 + uniformOffset, NzVector2f(light.innerAngleCosine, light.outerAngleCosine)); + break; + } + } + } + else + shader->SendInteger(uniforms.locations.type + uniformOffset, -1); //< Disable the light in the shader +} + +inline float NzForwardRenderTechnique::ComputeDirectionalLightScore(const NzSpheref& object, const NzAbstractRenderQueue::DirectionalLight& light) +{ + ///TODO: Compute a score depending on the light luminosity + return 0.f; +} + +inline float NzForwardRenderTechnique::ComputePointLightScore(const NzSpheref& object, const NzAbstractRenderQueue::PointLight& light) +{ + ///TODO: Compute a score depending on the light luminosity + return object.SquaredDistance(light.position); +} + +inline float NzForwardRenderTechnique::ComputeSpotLightScore(const NzSpheref& object, const NzAbstractRenderQueue::SpotLight& light) +{ + ///TODO: Compute a score depending on the light luminosity and spot direction + return object.SquaredDistance(light.position); +} + +inline bool NzForwardRenderTechnique::IsDirectionalLightSuitable(const NzSpheref& object, const NzAbstractRenderQueue::DirectionalLight& light) +{ + // Directional light are always suitables + return true; +} + +inline bool NzForwardRenderTechnique::IsPointLightSuitable(const NzSpheref& object, const NzAbstractRenderQueue::PointLight& light) +{ + // If the object is too far away from this point light, there is not way it could light it + return object.SquaredDistance(light.position) <= light.radius * light.radius; +} + +inline bool NzForwardRenderTechnique::IsSpotLightSuitable(const NzSpheref& object, const NzAbstractRenderQueue::SpotLight& light) +{ + ///TODO: Exclude spot lights based on their direction and outer angle? + return object.SquaredDistance(light.position) <= light.radius * light.radius; +} diff --git a/include/Nazara/Graphics/LightManager.hpp b/include/Nazara/Graphics/LightManager.hpp deleted file mode 100644 index 939421cae..000000000 --- a/include/Nazara/Graphics/LightManager.hpp +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (C) 2015 Jérôme Leclercq -// 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_LIGHTMANAGER_HPP -#define NAZARA_LIGHTMANAGER_HPP - -#include -#include - -class NzLight; - -class NAZARA_API NzLightManager -{ - public: - NzLightManager(); - NzLightManager(const NzLight** lights, unsigned int lightCount); - ~NzLightManager() = default; - - void AddLights(const NzLight** lights, unsigned int lightCount); - - void Clear(); - - unsigned int ComputeClosestLights(const NzVector3f& position, float squaredRadius, unsigned int maxResults); - - const NzLight* GetLight(unsigned int index) const; - unsigned int GetLightCount() const; - const NzLight* GetResult(unsigned int i) const; - - bool IsEmpty() const; - - void SetLights(const NzLight** lights, unsigned int lightCount); - - private: - struct Light - { - const NzLight* light; - unsigned int score; - }; - - std::vector> m_lights; - std::vector m_results; - unsigned int m_lightCount; -}; - -#endif // NAZARA_LIGHTMANAGER_HPP diff --git a/src/Nazara/Graphics/ForwardRenderTechnique.cpp b/src/Nazara/Graphics/ForwardRenderTechnique.cpp index bed2b9c40..3ccc4ce14 100644 --- a/src/Nazara/Graphics/ForwardRenderTechnique.cpp +++ b/src/Nazara/Graphics/ForwardRenderTechnique.cpp @@ -63,8 +63,6 @@ void NzForwardRenderTechnique::Clear(const NzScene* scene) const bool NzForwardRenderTechnique::Draw(const NzScene* scene) const { - m_directionalLights.SetLights(&m_renderQueue.directionalLights[0], m_renderQueue.directionalLights.size()); - m_lights.SetLights(&m_renderQueue.lights[0], m_renderQueue.lights.size()); m_renderQueue.Sort(scene->GetViewer()); if (!m_renderQueue.opaqueModels.empty()) @@ -106,6 +104,108 @@ void NzForwardRenderTechnique::SetMaxLightPassPerObject(unsigned int passCount) m_maxLightPassPerObject = passCount; } +bool NzForwardRenderTechnique::Initialize() +{ + try + { + NzErrorFlags flags(nzErrorFlag_ThrowException, true); + + s_quadIndexBuffer.Reset(false, s_maxQuads*6, nzDataStorage_Hardware, nzBufferUsage_Static); + + NzBufferMapper mapper(s_quadIndexBuffer, nzBufferAccess_WriteOnly); + nzUInt16* indices = static_cast(mapper.GetPointer()); + + for (unsigned int i = 0; i < s_maxQuads; ++i) + { + *indices++ = i*4 + 0; + *indices++ = i*4 + 2; + *indices++ = i*4 + 1; + + *indices++ = i*4 + 2; + *indices++ = i*4 + 3; + *indices++ = i*4 + 1; + } + + mapper.Unmap(); // Inutile de garder le buffer ouvert plus longtemps + + // Quad buffer (utilisé pour l'instancing de billboard et de sprites) + //Note: Les UV sont calculés dans le shader + s_quadVertexBuffer.Reset(NzVertexDeclaration::Get(nzVertexLayout_XY), 4, nzDataStorage_Hardware, nzBufferUsage_Static); + + float vertices[2*4] = { + -0.5f, -0.5f, + 0.5f, -0.5f, + -0.5f, 0.5f, + 0.5f, 0.5f, + }; + + s_quadVertexBuffer.FillRaw(vertices, 0, sizeof(vertices)); + + // Déclaration lors du rendu des billboards par sommet + s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_Color, nzComponentType_Color, NzOffsetOf(BillboardPoint, color)); + s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_Position, nzComponentType_Float3, NzOffsetOf(BillboardPoint, position)); + s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_TexCoord, nzComponentType_Float2, NzOffsetOf(BillboardPoint, uv)); + s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_Userdata0, nzComponentType_Float4, NzOffsetOf(BillboardPoint, size)); // Englobe sincos + + // Declaration utilisée lors du rendu des billboards par instancing + // L'avantage ici est la copie directe (std::memcpy) des données de la RenderQueue vers le buffer GPU + s_billboardInstanceDeclaration.EnableComponent(nzVertexComponent_InstanceData0, nzComponentType_Float3, NzOffsetOf(NzForwardRenderQueue::BillboardData, center)); + s_billboardInstanceDeclaration.EnableComponent(nzVertexComponent_InstanceData1, nzComponentType_Float4, NzOffsetOf(NzForwardRenderQueue::BillboardData, size)); // Englobe sincos + s_billboardInstanceDeclaration.EnableComponent(nzVertexComponent_InstanceData2, nzComponentType_Color, NzOffsetOf(NzForwardRenderQueue::BillboardData, color)); + } + catch (const std::exception& e) + { + NazaraError("Failed to initialise: " + NzString(e.what())); + return false; + } + + return true; +} + +void NzForwardRenderTechnique::Uninitialize() +{ + s_quadIndexBuffer.Reset(); + s_quadVertexBuffer.Reset(); +} + +bool NzForwardRenderTechnique::ChooseLights(const NzSpheref& object, bool includeDirectionalLights) const +{ + m_lights.clear(); + + // First step: add all the lights into a common list and compute their score, exlucing those who have no chance of lighting the object + // (Those who are too far away). + + if (includeDirectionalLights) + { + for (unsigned int i = 0; i < m_renderQueue.directionalLights.size(); ++i) + { + const auto& light = m_renderQueue.directionalLights[i]; + if (IsDirectionalLightSuitable(object, light)) + m_lights.push_back({nzLightType_Directional, ComputeDirectionalLightScore(object, light), i}); + } + } + + for (unsigned int i = 0; i < m_renderQueue.pointLights.size(); ++i) + { + const auto& light = m_renderQueue.pointLights[i]; + if (IsPointLightSuitable(object, light)) + m_lights.push_back({nzLightType_Point, ComputePointLightScore(object, light), i}); + } + + for (unsigned int i = 0; i < m_renderQueue.spotLights.size(); ++i) + { + const auto& light = m_renderQueue.spotLights[i]; + if (IsSpotLightSuitable(object, light)) + m_lights.push_back({nzLightType_Spot, ComputeSpotLightScore(object, light), i}); + } + + // Then, sort the lights according to their score + std::sort(m_lights.begin(), m_lights.end(), [](const LightIndex& light1, const LightIndex& light2) + { + return light1.score < light2.score; + }); +} + void NzForwardRenderTechnique::DrawBasicSprites(const NzScene* scene) const { NzAbstractViewer* viewer = scene->GetViewer(); @@ -211,70 +311,6 @@ void NzForwardRenderTechnique::DrawBasicSprites(const NzScene* scene) const } } -bool NzForwardRenderTechnique::Initialize() -{ - try - { - NzErrorFlags flags(nzErrorFlag_ThrowException, true); - - s_quadIndexBuffer.Reset(false, s_maxQuads*6, nzDataStorage_Hardware, nzBufferUsage_Static); - - NzBufferMapper mapper(s_quadIndexBuffer, nzBufferAccess_WriteOnly); - nzUInt16* indices = static_cast(mapper.GetPointer()); - - for (unsigned int i = 0; i < s_maxQuads; ++i) - { - *indices++ = i*4 + 0; - *indices++ = i*4 + 2; - *indices++ = i*4 + 1; - - *indices++ = i*4 + 2; - *indices++ = i*4 + 3; - *indices++ = i*4 + 1; - } - - mapper.Unmap(); // Inutile de garder le buffer ouvert plus longtemps - - // Quad buffer (utilisé pour l'instancing de billboard et de sprites) - //Note: Les UV sont calculés dans le shader - s_quadVertexBuffer.Reset(NzVertexDeclaration::Get(nzVertexLayout_XY), 4, nzDataStorage_Hardware, nzBufferUsage_Static); - - float vertices[2*4] = { - -0.5f, -0.5f, - 0.5f, -0.5f, - -0.5f, 0.5f, - 0.5f, 0.5f, - }; - - s_quadVertexBuffer.FillRaw(vertices, 0, sizeof(vertices)); - - // Déclaration lors du rendu des billboards par sommet - s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_Color, nzComponentType_Color, NzOffsetOf(BillboardPoint, color)); - s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_Position, nzComponentType_Float3, NzOffsetOf(BillboardPoint, position)); - s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_TexCoord, nzComponentType_Float2, NzOffsetOf(BillboardPoint, uv)); - s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_Userdata0, nzComponentType_Float4, NzOffsetOf(BillboardPoint, size)); // Englobe sincos - - // Declaration utilisée lors du rendu des billboards par instancing - // L'avantage ici est la copie directe (std::memcpy) des données de la RenderQueue vers le buffer GPU - s_billboardInstanceDeclaration.EnableComponent(nzVertexComponent_InstanceData0, nzComponentType_Float3, NzOffsetOf(NzForwardRenderQueue::BillboardData, center)); - s_billboardInstanceDeclaration.EnableComponent(nzVertexComponent_InstanceData1, nzComponentType_Float4, NzOffsetOf(NzForwardRenderQueue::BillboardData, size)); // Englobe sincos - s_billboardInstanceDeclaration.EnableComponent(nzVertexComponent_InstanceData2, nzComponentType_Color, NzOffsetOf(NzForwardRenderQueue::BillboardData, color)); - } - catch (const std::exception& e) - { - NazaraError("Failed to initialise: " + NzString(e.what())); - return false; - } - - return true; -} - -void NzForwardRenderTechnique::Uninitialize() -{ - s_quadIndexBuffer.Reset(); - s_quadVertexBuffer.Reset(); -} - void NzForwardRenderTechnique::DrawBillboards(const NzScene* scene) const { NzAbstractViewer* viewer = scene->GetViewer(); @@ -437,7 +473,8 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const // Nous utilisons de l'instancing que lorsqu'aucune lumière (autre que directionnelle) n'est active // Ceci car l'instancing n'est pas compatible avec la recherche des lumières les plus proches // (Le deferred shading n'a pas ce problème) - bool instancing = m_instancingEnabled && (!material->IsLightingEnabled() || m_lights.IsEmpty()) && matEntry.instancingEnabled; + bool noPointSpotLight = m_renderQueue.pointLights.empty() && m_renderQueue.spotLights.empty(); + bool instancing = m_instancingEnabled && (!material->IsLightingEnabled() || noPointSpotLight) && matEntry.instancingEnabled; // On commence par appliquer du matériau (et récupérer le shader ainsi activé) const NzShader* shader = material->Apply((instancing) ? nzShaderFlags_Instancing : 0); @@ -499,7 +536,7 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const // Avec l'instancing, impossible de sélectionner les lumières pour chaque objet // Du coup, il n'est activé que pour les lumières directionnelles - unsigned int lightCount = m_directionalLights.GetLightCount(); + unsigned int lightCount = m_renderQueue.directionalLights.size(); unsigned int lightIndex = 0; nzRendererComparison oldDepthFunc = NzRenderer::GetDepthFunc(); @@ -522,11 +559,9 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const NzRenderer::SetDepthFunc(nzRendererComparison_Equal); } - for (unsigned int i = 0; i < renderedLightCount; ++i) - m_directionalLights.GetLight(lightIndex++)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i); - - for (unsigned int i = renderedLightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) - NzLight::Disable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i); + // Sends the uniforms + for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) + SendLightUniforms(shader, shaderUniforms->lightUniforms, i*shaderUniforms->lightOffset, lightIndex++); } const NzMatrix4f* instanceMatrices = &instances[0]; @@ -558,20 +593,19 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const { for (const NzMatrix4f& matrix : instances) { - unsigned int directionalLightCount = m_directionalLights.GetLightCount(); - unsigned int otherLightCount = m_lights.ComputeClosestLights(matrix.GetTranslation() + squaredBoundingSphere.GetPosition(), squaredBoundingSphere.radius, m_maxLightPassPerObject*NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS - directionalLightCount); - unsigned int lightCount = directionalLightCount + otherLightCount; + // Choose the lights depending on an object position and apparent radius + ChooseLights(NzSpheref(matrix.GetTranslation() + squaredBoundingSphere.GetPosition(), squaredBoundingSphere.radius)); + + unsigned int lightCount = m_lights.size(); NzRenderer::SetMatrix(nzMatrixType_World, matrix); - unsigned int directionalLightIndex = 0; - unsigned int otherLightIndex = 0; + unsigned int lightIndex = 0; nzRendererComparison oldDepthFunc = NzRenderer::GetDepthFunc(); // Dans le cas où nous aurions à le changer unsigned int passCount = (lightCount == 0) ? 1 : (lightCount-1)/NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1; for (unsigned int pass = 0; pass < passCount; ++pass) { - unsigned int renderedLightCount = std::min(lightCount, NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U)); - lightCount -= renderedLightCount; + lightCount -= std::min(lightCount, NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U)); if (pass == 1) { @@ -584,18 +618,9 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const NzRenderer::SetDepthFunc(nzRendererComparison_Equal); } - // On active les lumières de cette passe-ci - for (unsigned int i = 0; i < renderedLightCount; ++i) - { - if (directionalLightIndex >= directionalLightCount) - m_lights.GetResult(otherLightIndex++)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i); - else - m_directionalLights.GetLight(directionalLightIndex++)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i); - } - - // On désactive l'éventuel surplus - for (unsigned int i = renderedLightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) - NzLight::Disable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i); + // Sends the light uniforms to the shader + for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) + SendLightUniforms(shader, shaderUniforms->lightUniforms, lightIndex++, shaderUniforms->lightOffset*i); // Et on passe à l'affichage drawFunc(meshData.primitiveMode, 0, indexCount); @@ -660,9 +685,10 @@ void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene) const // On envoie les lumières directionnelles s'il y a (Les mêmes pour tous) if (shaderUniforms->hasLightUniforms) { - lightCount = std::min(m_directionalLights.GetLightCount(), NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U)); + lightCount = std::min(m_renderQueue.directionalLights.size(), NazaraSuffixMacro(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS, U)); + for (unsigned int i = 0; i < lightCount; ++i) - m_directionalLights.GetLight(i)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i); + SendLightUniforms(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset * i, i); } lastShader = shader; @@ -693,22 +719,15 @@ void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene) const NzRenderer::SetIndexBuffer(indexBuffer); NzRenderer::SetVertexBuffer(vertexBuffer); - if (shaderUniforms->hasLightUniforms) + if (shaderUniforms->hasLightUniforms && lightCount < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS) { - // Calcul des lumières les plus proches - if (lightCount < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS && !m_lights.IsEmpty()) - { - NzVector3f position = matrix.GetTranslation() + modelData.squaredBoundingSphere.GetPosition(); - float radius = modelData.squaredBoundingSphere.radius; - unsigned int closestLightCount = m_lights.ComputeClosestLights(position, radius, NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS); - - unsigned int count = std::min(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS - lightCount, closestLightCount); - for (unsigned int i = 0; i < count; ++i) - m_lights.GetResult(i)->Enable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*(lightCount++)); - } + // Compute the closest lights + NzVector3f position = matrix.GetTranslation() + modelData.squaredBoundingSphere.GetPosition(); + float radius = modelData.squaredBoundingSphere.radius; + ChooseLights(NzSpheref(position, radius), false); for (unsigned int i = lightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) - NzLight::Disable(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i); + SendLightUniforms(shader, shaderUniforms->lightUniforms, shaderUniforms->lightOffset*i, i); } NzRenderer::SetMatrix(nzMatrixType_World, matrix); diff --git a/src/Nazara/Graphics/LightManager.cpp b/src/Nazara/Graphics/LightManager.cpp deleted file mode 100644 index d0f8b3bb6..000000000 --- a/src/Nazara/Graphics/LightManager.cpp +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Graphics module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include - -NzLightManager::NzLightManager() : -m_lightCount(0) -{ -} - -NzLightManager::NzLightManager(const NzLight** lights, unsigned int lightCount) -{ - SetLights(lights, lightCount); -} - -void NzLightManager::AddLights(const NzLight** lights, unsigned int lightCount) -{ - m_lights.push_back(std::make_pair(lights, lightCount)); - m_lightCount += lightCount; -} - -void NzLightManager::Clear() -{ - m_lights.clear(); - m_lightCount = 0; -} - -unsigned int NzLightManager::ComputeClosestLights(const NzVector3f& position, float squaredRadius, unsigned int maxResults) -{ - m_results.resize(maxResults); - for (Light& light : m_results) - { - light.light = nullptr; - light.score = std::numeric_limits::max(); // Nous jouons au Golf - } - - for (auto it = m_lights.begin(); it != m_lights.end(); ++it) - { - const NzLight** lights = it->first; - unsigned int lightCount = it->second; - - for (unsigned int j = 0; j < lightCount; ++j) - { - const NzLight* light = *lights++; - - unsigned int score = std::numeric_limits::max(); - switch (light->GetLightType()) - { - case nzLightType_Directional: - score = 0; // Lumière choisie d'office - break; - - case nzLightType_Point: - { - float lightRadius = light->GetRadius(); - - float squaredDistance = position.SquaredDistance(light->GetPosition()); - if (squaredDistance - squaredRadius <= lightRadius*lightRadius) - score = static_cast(squaredDistance*1000.f); - - break; - } - - case nzLightType_Spot: - { - float lightRadius = light->GetRadius(); - - ///TODO: Attribuer bonus/malus selon l'angle du spot ? - float squaredDistance = position.SquaredDistance(light->GetPosition()); - if (squaredDistance - squaredRadius <= lightRadius*lightRadius) - score = static_cast(squaredDistance*1000.f); - - break; - } - } - - if (score < m_results[0].score) - { - unsigned int k; - for (k = 1; k < maxResults; ++k) - { - if (score > m_results[k].score) - break; - } - - k--; // Position de la nouvelle lumière - - // Décalage - std::memcpy(&m_results[0], &m_results[1], k*sizeof(Light)); - - m_results[k].light = light; - m_results[k].score = score; - } - } - } - - unsigned int i; - for (i = 0; i < maxResults; ++i) - { - if (m_results[i].light) - break; - } - - return maxResults-i; -} - -const NzLight* NzLightManager::GetLight(unsigned int index) const -{ - #if NAZARA_GRAPHICS_SAFE - if (index >= m_lightCount) - { - NazaraError("Light index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_lightCount) + ')'); - return nullptr; - } - #endif - - for (unsigned int i = 0; i < m_lights.size(); ++i) - { - unsigned int lightCount = m_lights[i].second; - if (index > lightCount) - index -= lightCount; - else - { - const NzLight** lights = m_lights[i].first; - return lights[i]; - } - } - - #if NAZARA_GRAPHICS_SAFE - NazaraInternalError("Light not found"); - #else - NazaraError("Light not found"); - #endif - - return nullptr; -} - -unsigned int NzLightManager::GetLightCount() const -{ - return m_lightCount; -} - -const NzLight* NzLightManager::GetResult(unsigned int i) const -{ - return m_results[m_results.size()-i-1].light; -} - -bool NzLightManager::IsEmpty() const -{ - return m_lightCount == 0; -} - -void NzLightManager::SetLights(const NzLight** lights, unsigned int lightCount) -{ - Clear(); - AddLights(lights, lightCount); -}