Graphics/Light: Update to Renderable

Former-commit-id: 6766d036eb4c79fd0d5cdb718b06d6e4812ac660
This commit is contained in:
Lynix 2015-05-26 14:16:15 +02:00
parent e1a25a8885
commit 6f06383ab0
2 changed files with 47 additions and 153 deletions

View File

@ -10,24 +10,24 @@
#include <Nazara/Prerequesites.hpp> #include <Nazara/Prerequesites.hpp>
#include <Nazara/Core/Color.hpp> #include <Nazara/Core/Color.hpp>
#include <Nazara/Graphics/Enums.hpp> #include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Graphics/SceneNode.hpp> #include <Nazara/Graphics/Renderable.hpp>
class NzShader; class NzShader;
struct NzLightUniforms; struct NzLightUniforms;
class NAZARA_API NzLight : public NzSceneNode class NAZARA_API NzLight : public NzRenderable
{ {
public: public:
NzLight(nzLightType type = nzLightType_Point); NzLight(nzLightType type = nzLightType_Point);
NzLight(const NzLight& light); NzLight(const NzLight& light) = default;
~NzLight() = default; ~NzLight() = default;
void AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const override; void AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatrix4f& transformMatrix) const override;
NzLight* Clone() const; NzLight* Clone() const;
NzLight* Create() const; NzLight* Create() const;
void Enable(const NzShader* shader, const NzLightUniforms& uniforms, int offset = 0) const; bool Cull(const NzFrustumf& frustum, const NzBoundingVolumef& volume, const NzMatrix4f& transformMatrix) const override;
float GetAmbientFactor() const; float GetAmbientFactor() const;
float GetAttenuation() const; float GetAttenuation() const;
@ -37,9 +37,6 @@ class NAZARA_API NzLight : public NzSceneNode
nzLightType GetLightType() const; nzLightType GetLightType() const;
float GetOuterAngle() const; float GetOuterAngle() const;
float GetRadius() const; float GetRadius() const;
nzSceneNodeType GetSceneNodeType() const;
bool IsDrawable() const;
void SetAmbientFactor(float factor); void SetAmbientFactor(float factor);
void SetAttenuation(float attenuation); void SetAttenuation(float attenuation);
@ -50,16 +47,12 @@ class NAZARA_API NzLight : public NzSceneNode
void SetOuterAngle(float outerAngle); void SetOuterAngle(float outerAngle);
void SetRadius(float radius); void SetRadius(float radius);
NzLight& operator=(const NzLight& light); void UpdateBoundingVolume(NzBoundingVolumef* boundingVolume, const NzMatrix4f& transformMatrix) const;
static void Disable(const NzShader* program, const NzLightUniforms& uniforms, int offset = 0); NzLight& operator=(const NzLight& light) = default;
private: private:
bool FrustumCull(const NzFrustumf& frustum) const override;
void MakeBoundingVolume() const override; void MakeBoundingVolume() const override;
void Register() override;
void Unregister() override;
void UpdateBoundingVolume() const;
nzLightType m_type; nzLightType m_type;
NzColor m_color; NzColor m_color;

View File

@ -28,23 +28,25 @@ m_radius(5.f)
{ {
} }
NzLight::NzLight(const NzLight& light) : void NzLight::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatrix4f& transformMatrix) const
NzSceneNode(light),
m_type(light.m_type),
m_color(light.m_color),
m_ambientFactor(light.m_ambientFactor),
m_attenuation(light.m_attenuation),
m_diffuseFactor(light.m_diffuseFactor),
m_innerAngle(light.m_innerAngle),
m_outerAngle(light.m_outerAngle),
m_radius(light.m_radius)
{ {
SetParent(light.GetParent()); switch (m_type)
} {
case nzLightType_Directional:
renderQueue->AddDirectionalLight(m_color, m_ambientFactor, m_diffuseFactor, transformMatrix.Transform(NzVector3f::Forward(), 0.f));
break;
void NzLight::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const case nzLightType_Point:
{ renderQueue->AddPointLight(m_color, m_ambientFactor, m_diffuseFactor, transformMatrix.GetTranslation(), m_radius, m_attenuation);
renderQueue->AddLight(this);
case nzLightType_Spot:
renderQueue->AddSpotLight(m_color, m_ambientFactor, m_diffuseFactor, transformMatrix.GetTranslation(), transformMatrix.Transform(NzVector3f::Forward(), 0.f), m_radius, m_attenuation, m_innerAngle, m_outerAngle);
break;
default:
NazaraError("Invalid light type (0x" + NzString::Number(m_type, 16) + ')');
break;
}
} }
NzLight* NzLight::Clone() const NzLight* NzLight::Clone() const
@ -57,57 +59,22 @@ NzLight* NzLight::Create() const
return new NzLight; return new NzLight;
} }
void NzLight::Enable(const NzShader* shader, const NzLightUniforms& uniforms, int offset) const bool NzLight::Cull(const NzFrustumf& frustum, const NzBoundingVolumef& volume, const NzMatrix4f& transformMatrix) const
{ {
/*
struct Light
{
int type;
vec4 color;
vec2 factors;
vec4 parameters1;
vec4 parameters2;
vec2 parameters3;
};
Directional
-P1: vec3 direction
Point
-P1: vec3 position + float attenuation
-P2: vec3 NON-USED + float invRadius
Spot
-P1: vec3 position + float attenuation
-P2: vec3 direction + float invRadius
-P3: float cosInnerAngle + float cosOuterAngle
*/
shader->SendInteger(uniforms.locations.type + offset, m_type);
shader->SendColor(uniforms.locations.color + offset, m_color);
shader->SendVector(uniforms.locations.factors + offset, NzVector2f(m_ambientFactor, m_diffuseFactor));
if (!m_derivedUpdated)
UpdateDerived();
switch (m_type) switch (m_type)
{ {
case nzLightType_Directional: case nzLightType_Directional:
shader->SendVector(uniforms.locations.parameters1 + offset, NzVector4f(m_derivedRotation * NzVector3f::Forward())); return true; // Always visible
break;
case nzLightType_Point: case nzLightType_Point:
shader->SendVector(uniforms.locations.parameters1 + offset, NzVector4f(m_derivedPosition, m_attenuation)); return frustum.Contains(NzSpheref(transformMatrix.GetTranslation(), m_radius)); // A sphere test is much faster (and precise)
shader->SendVector(uniforms.locations.parameters2 + offset, NzVector4f(0.f, 0.f, 0.f, 1.f/m_radius));
break;
case nzLightType_Spot: case nzLightType_Spot:
shader->SendVector(uniforms.locations.parameters1 + offset, NzVector4f(m_derivedPosition, m_attenuation)); return frustum.Contains(volume);
shader->SendVector(uniforms.locations.parameters2 + offset, NzVector4f(m_derivedRotation * NzVector3f::Forward(), 1.f/m_radius));
shader->SendVector(uniforms.locations.parameters3 + offset, NzVector2f(std::cos(NzDegreeToRadian(m_innerAngle)), std::cos(NzDegreeToRadian(m_outerAngle))));
break;
} }
NazaraError("Invalid light type (0x" + NzString::Number(m_type, 16) + ')');
return false;
} }
float NzLight::GetAmbientFactor() const float NzLight::GetAmbientFactor() const
@ -150,16 +117,6 @@ float NzLight::GetRadius() const
return m_radius; return m_radius;
} }
nzSceneNodeType NzLight::GetSceneNodeType() const
{
return nzSceneNodeType_Light;
}
bool NzLight::IsDrawable() const
{
return true;
}
void NzLight::SetAmbientFactor(float factor) void NzLight::SetAmbientFactor(float factor)
{ {
m_ambientFactor = factor; m_ambientFactor = factor;
@ -194,61 +151,37 @@ void NzLight::SetOuterAngle(float outerAngle)
{ {
m_outerAngle = outerAngle; m_outerAngle = outerAngle;
m_boundingVolume.MakeNull(); InvalidateBoundingVolume();
m_boundingVolumeUpdated = false;
} }
void NzLight::SetRadius(float radius) void NzLight::SetRadius(float radius)
{ {
m_radius = radius; m_radius = radius;
m_boundingVolume.MakeNull(); InvalidateBoundingVolume();
m_boundingVolumeUpdated = false;
} }
NzLight& NzLight::operator=(const NzLight& light) void NzLight::UpdateBoundingVolume(NzBoundingVolumef* boundingVolume, const NzMatrix4f& transformMatrix) const
{ {
NzSceneNode::operator=(light); NazaraAssert(boundingVolume, "Invalid bounding volume");
m_ambientFactor = light.m_ambientFactor;
m_attenuation = light.m_attenuation;
m_boundingVolume = light.m_boundingVolume;
m_boundingVolumeUpdated = light.m_boundingVolumeUpdated;
m_color = light.m_color;
m_diffuseFactor = light.m_diffuseFactor;
m_innerAngle = light.m_innerAngle;
m_outerAngle = light.m_outerAngle;
m_radius = light.m_radius;
m_type = light.m_type;
return *this;
}
void NzLight::Disable(const NzShader* shader, const NzLightUniforms& uniforms, int offset)
{
shader->SendInteger(uniforms.locations.type + offset, -1);
}
bool NzLight::FrustumCull(const NzFrustumf& frustum) const
{
switch (m_type) switch (m_type)
{ {
case nzLightType_Directional: case nzLightType_Directional:
return true; // Toujours visible break; // Nothing to do (bounding volume should be infinite)
case nzLightType_Point: case nzLightType_Point:
if (!m_derivedUpdated) boundingVolume->Update(transformMatrix.GetTranslation()); // The bounding volume only needs to be shifted
UpdateDerived(); break;
// Un test sphérique est bien plus rapide et précis que celui de la bounding box
return frustum.Contains(NzSpheref(m_derivedPosition, m_radius));
case nzLightType_Spot: case nzLightType_Spot:
return NzSceneNode::FrustumCull(frustum); boundingVolume->Update(transformMatrix);
} break;
NazaraError("Invalid light type (0x" + NzString::Number(m_type, 16) + ')'); default:
return false; NazaraError("Invalid light type (0x" + NzString::Number(m_type, 16) + ')');
break;
}
} }
void NzLight::MakeBoundingVolume() const void NzLight::MakeBoundingVolume() const
@ -261,7 +194,7 @@ void NzLight::MakeBoundingVolume() const
case nzLightType_Point: case nzLightType_Point:
{ {
NzVector3f radius(m_radius); NzVector3f radius(m_radius); ///FIXME: Incorrect
m_boundingVolume.Set(-radius, radius); m_boundingVolume.Set(-radius, radius);
break; break;
} }
@ -289,41 +222,9 @@ void NzLight::MakeBoundingVolume() const
m_boundingVolume.Set(box); m_boundingVolume.Set(box);
break; break;
} }
}
}
void NzLight::Register() default:
{ NazaraError("Invalid light type (0x" + NzString::Number(m_type, 16) + ')');
}
void NzLight::Unregister()
{
}
void NzLight::UpdateBoundingVolume() const
{
if (m_boundingVolume.IsNull())
MakeBoundingVolume();
switch (m_type)
{
case nzLightType_Directional:
break;
case nzLightType_Point:
if (!m_derivedUpdated)
UpdateDerived();
m_boundingVolume.Update(NzMatrix4f::Translate(m_derivedPosition)); // Notre BoundingBox ne changera que selon la position
break;
case nzLightType_Spot:
if (!m_derivedUpdated)
UpdateDerived();
m_boundingVolume.Update(NzMatrix4f::Transform(m_derivedPosition, m_derivedRotation));
break; break;
} }
m_boundingVolumeUpdated = true;
} }