Added lights bounding box

Former-commit-id: 9ab45181c8b0586e9d4040d48d756683e88dd8fe
This commit is contained in:
Lynix 2013-03-13 17:10:58 +01:00
parent 1e57c00fa1
commit 593fec134d
2 changed files with 110 additions and 8 deletions

View File

@ -47,17 +47,18 @@ class NAZARA_API NzLight : public NzSceneNode
NzLight& operator=(const NzLight& light); NzLight& operator=(const NzLight& light);
private: private:
void Invalidate();
void Register(); void Register();
void Unregister(); void Unregister();
void UpdateFrustum(); void UpdateBoundingBox() const;
bool VisibilityTest(const NzFrustumf& frustum); bool VisibilityTest(const NzFrustumf& frustum);
nzLightType m_type; nzLightType m_type;
NzBoundingBoxf m_boundingBox; mutable NzBoundingBoxf m_boundingBox;
NzColor m_ambientColor; NzColor m_ambientColor;
NzColor m_diffuseColor; NzColor m_diffuseColor;
NzColor m_specularColor; NzColor m_specularColor;
bool m_boundingBoxUpdated; mutable bool m_boundingBoxUpdated;
float m_attenuation; float m_attenuation;
float m_innerAngle; float m_innerAngle;
float m_outerAngle; float m_outerAngle;

View File

@ -5,6 +5,7 @@
#include <Nazara/3D/Light.hpp> #include <Nazara/3D/Light.hpp>
#include <Nazara/Core/Error.hpp> #include <Nazara/Core/Error.hpp>
#include <Nazara/Math/Basic.hpp> #include <Nazara/Math/Basic.hpp>
#include <Nazara/Math/Sphere.hpp>
#include <Nazara/Renderer/Renderer.hpp> #include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/Shader.hpp> #include <Nazara/Renderer/Shader.hpp>
#include <cstring> #include <cstring>
@ -130,8 +131,10 @@ void NzLight::Apply(const NzShader* shader, unsigned int lightUnit) const
const NzBoundingBoxf& NzLight::GetBoundingBox() const const NzBoundingBoxf& NzLight::GetBoundingBox() const
{ {
static NzBoundingBoxf dummy(nzExtend_Null); if (!m_boundingBoxUpdated)
return dummy; UpdateBoundingBox();
return m_boundingBox;
} }
NzColor NzLight::GetAmbientColor() const NzColor NzLight::GetAmbientColor() const
@ -202,11 +205,17 @@ void NzLight::SetInnerAngle(float innerAngle)
void NzLight::SetOuterAngle(float outerAngle) void NzLight::SetOuterAngle(float outerAngle)
{ {
m_outerAngle = outerAngle; m_outerAngle = outerAngle;
m_boundingBox.MakeNull();
m_boundingBoxUpdated = false;
} }
void NzLight::SetRadius(float radius) void NzLight::SetRadius(float radius)
{ {
m_radius = radius; m_radius = radius;
m_boundingBox.MakeNull();
m_boundingBoxUpdated = false;
} }
void NzLight::SetSpecularColor(const NzColor& specular) void NzLight::SetSpecularColor(const NzColor& specular)
@ -221,6 +230,13 @@ NzLight& NzLight::operator=(const NzLight& light)
return *this; return *this;
} }
void NzLight::Invalidate()
{
NzSceneNode::Invalidate();
m_boundingBoxUpdated = false;
}
void NzLight::Register() void NzLight::Register()
{ {
} }
@ -229,10 +245,95 @@ void NzLight::Unregister()
{ {
} }
void NzLight::UpdateBoundingBox() const
{
if (m_boundingBox.IsNull())
{
switch (m_type)
{
case nzLightType_Directional:
m_boundingBox.MakeInfinite();
m_boundingBoxUpdated = true;
return; // Rien d'autre à faire
case nzLightType_Point:
{
NzVector3f radius(m_radius);
m_boundingBox.Set(-radius, radius);
break;
}
case nzLightType_Spot:
{
// On forme un cube sur l'origine
NzCubef cube(NzVector3f::Zero());
// On calcule le reste des points
float height = m_radius;
NzVector3f base(NzVector3f::Forward()*height);
// Il nous faut maintenant le rayon du cercle projeté à cette distance
// Tangente = Opposé/Adjaçent <=> Opposé = Adjaçent*Tangente
float radius = height*std::tan(NzDegreeToRadian(m_outerAngle));
NzVector3f lExtend = NzVector3f::Left()*radius;
NzVector3f uExtend = NzVector3f::Up()*radius;
// Et on ajoute ensuite les quatres extrêmités de la pyramide
cube.ExtendTo(base + lExtend + uExtend);
cube.ExtendTo(base + lExtend - uExtend);
cube.ExtendTo(base - lExtend + uExtend);
cube.ExtendTo(base - lExtend - uExtend);
m_boundingBox.Set(cube);
break;
}
}
}
switch (m_type)
{
case nzLightType_Directional:
break;
case nzLightType_Point:
if (!m_derivedUpdated)
UpdateDerived();
m_boundingBox.Update(NzMatrix4f::Translate(m_derivedPosition)); // Notre BoundingBox ne changera que selon la position
break;
case nzLightType_Spot:
if (!m_transformMatrixUpdated)
UpdateTransformMatrix();
m_boundingBox.Update(m_transformMatrix);
break;
}
m_boundingBoxUpdated = true;
}
bool NzLight::VisibilityTest(const NzFrustumf& frustum) bool NzLight::VisibilityTest(const NzFrustumf& frustum)
{ {
NazaraUnused(frustum); switch (m_type)
{
case nzLightType_Directional:
return true; // Toujours visible
///FIXME: Pour l'instant toujours visible case nzLightType_Point:
return true; // Toujours visible if (!m_derivedUpdated)
UpdateDerived();
// 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:
if (!m_boundingBoxUpdated)
UpdateBoundingBox();
return frustum.Contains(m_boundingBox);
}
NazaraError("Invalid light type (0x" + NzString::Number(m_type, 16) + ')');
return false;
} }