Graphics/ForwardShading: Remake light selection

Former-commit-id: f7e761411e88513d1772b55f09ac4bd3a1d065a7
This commit is contained in:
Lynix
2015-05-31 22:13:49 +02:00
parent eba7cfc538
commit 4a87481311
5 changed files with 234 additions and 320 deletions

View File

@@ -11,7 +11,6 @@
#include <Nazara/Graphics/AbstractRenderTechnique.hpp>
#include <Nazara/Graphics/ForwardRenderQueue.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/LightManager.hpp>
#include <Nazara/Utility/IndexBuffer.hpp>
#include <Nazara/Utility/VertexBuffer.hpp>
@@ -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<const NzShader*, ShaderUniforms> m_shaderUniforms;
mutable std::vector<LightIndex> 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 <Nazara/Graphics/ForwardRenderTechnique.inl>
#endif // NAZARA_FORWARDRENDERTECHNIQUE_HPP

View File

@@ -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;
}

View File

@@ -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 <Nazara/Prerequesites.hpp>
#include <Nazara/Math/Vector3.hpp>
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<std::pair<const NzLight**, unsigned int>> m_lights;
std::vector<Light> m_results;
unsigned int m_lightCount;
};
#endif // NAZARA_LIGHTMANAGER_HPP