Page MenuHomePhorge

Light.cpp
No OneTemporary

Size
18 KB
Referenced Files
None
Subscribers
None

Light.cpp

/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/
Copyright (c) 2000-2009 Torus Knot Software Ltd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include <echo/Graphics/Light.h>
#include <echo/Graphics/Node.h>
#include <echo/Graphics/Camera.h>
namespace Echo
{
//-----------------------------------------------------------------------
Light::Light() :
mLightType(LightTypes::POINT),
mPosition(Vector3::ZERO),
mDiffuse(Colour()),
mSpecular(Colour(0, 0, 0, 1.0f)),
mDirection(Vector3::UNIT_Z),
mSpotOuter(Degree(40.0f)),
mSpotInner(Degree(30.0f)),
mSpotFalloff(1.0f),
mRange(100000),
mAttenuationConst(1.0f),
mAttenuationLinear(0.0f),
mAttenuationQuad(0.0f),
mPowerScale(1.0f),
mIndexInFrame(0),
mOwnShadowFarDist(false),
mShadowFarDist(0),
mShadowFarDistSquared(0),
mShadowNearClipDist(-1),
mShadowFarClipDist(-1),
mDerivedPosition(Vector3::ZERO),
mDerivedDirection(Vector3::UNIT_Z),
mDerivedCamRelativePosition(Vector3::ZERO),
mDerivedCamRelativeDirty(false),
mCameraToBeRelativeTo(0),
mDerivedTransformDirty(false)
{ }
Light::Light(const std::string& name) :
mLightType(LightTypes::POINT),
mPosition(Vector3::ZERO),
mDiffuse(Colour()),
mSpecular(Colour(0.0f, 0.0f, 0.0f, 1.0f)),
mDirection(Vector3::UNIT_Z),
mSpotOuter(Degree(40.0f)),
mSpotInner(Degree(30.0f)),
mSpotFalloff(1.0f),
mRange(100000),
mAttenuationConst(1.0f),
mAttenuationLinear(0.0f),
mAttenuationQuad(0.0f),
mPowerScale(1.0f),
mIndexInFrame(0),
mOwnShadowFarDist(false),
mShadowFarDist(0),
mShadowFarDistSquared(0),
mShadowNearClipDist(-1),
mShadowFarClipDist(-1),
mDerivedPosition(Vector3::ZERO),
mDerivedDirection(Vector3::UNIT_Z),
mDerivedCamRelativeDirty(false),
mCameraToBeRelativeTo(0),
mDerivedTransformDirty(false)
{ }
//-----------------------------------------------------------------------
Light::~Light() { }
//-----------------------------------------------------------------------
void Light::SetType(LightType type)
{
mLightType = type;
}
//-----------------------------------------------------------------------
Light::LightType Light::GetType(void) const
{
return mLightType;
}
//-----------------------------------------------------------------------
void Light::SetPosition(f32 x, f32 y, f32 z)
{
mPosition.x = x;
mPosition.y = y;
mPosition.z = z;
mDerivedTransformDirty = true;
mDerivedCamRelativeDirty = true;
}
//-----------------------------------------------------------------------
void Light::SetPosition(const Vector3& vec)
{
mPosition = vec;
mDerivedTransformDirty = true;
mDerivedCamRelativeDirty = true;
}
//-----------------------------------------------------------------------
const Vector3& Light::GetPosition(void) const
{
return mPosition;
}
//-----------------------------------------------------------------------
void Light::SetDirection(f32 x, f32 y, f32 z)
{
mDirection.x = x;
mDirection.y = y;
mDirection.z = z;
mDerivedTransformDirty = true;
}
//-----------------------------------------------------------------------
void Light::SetDirection(const Vector3& vec)
{
mDirection = vec;
mDerivedTransformDirty = true;
}
//-----------------------------------------------------------------------
const Vector3& Light::GetDirection(void) const
{
return mDirection;
}
//-----------------------------------------------------------------------
void Light::setSpotlightRange(const Radian& innerAngle, const Radian& outerAngle, f32 falloff)
{
assert(mLightType == LightTypes::SPOTLIGHT);
mSpotInner = innerAngle;
mSpotOuter = outerAngle;
mSpotFalloff = falloff;
}
//-----------------------------------------------------------------------
void Light::setSpotlightInnerAngle(const Radian& val)
{
mSpotInner = val;
}
//-----------------------------------------------------------------------
void Light::setSpotlightOuterAngle(const Radian& val)
{
mSpotOuter = val;
}
//-----------------------------------------------------------------------
void Light::setSpotlightFalloff(f32 val)
{
mSpotFalloff = val;
}
//-----------------------------------------------------------------------
const Radian& Light::getSpotlightInnerAngle(void) const
{
return mSpotInner;
}
//-----------------------------------------------------------------------
const Radian& Light::getSpotlightOuterAngle(void) const
{
return mSpotOuter;
}
//-----------------------------------------------------------------------
f32 Light::getSpotlightFalloff(void) const
{
return mSpotFalloff;
}
//-----------------------------------------------------------------------
void Light::SetDiffuseColour(f32 red, f32 green, f32 blue)
{
mDiffuse.mRed = red;
mDiffuse.mBlue = blue;
mDiffuse.mGreen = green;
}
//-----------------------------------------------------------------------
void Light::SetDiffuseColour(const Colour& colour)
{
mDiffuse = colour;
}
//-----------------------------------------------------------------------
const Colour& Light::GetDiffuseColour(void) const
{
return mDiffuse;
}
//-----------------------------------------------------------------------
void Light::SetSpecularColour(f32 red, f32 green, f32 blue)
{
mSpecular.mRed = red;
mSpecular.mBlue = blue;
mSpecular.mGreen = green;
}
//-----------------------------------------------------------------------
void Light::SetSpecularColour(const Colour& colour)
{
mSpecular = colour;
}
//-----------------------------------------------------------------------
const Colour& Light::GetSpecularColour(void) const
{
return mSpecular;
}
//-----------------------------------------------------------------------
void Light::SetAttenuation(f32 range, f32 constant,
f32 linear, f32 quadratic)
{
mRange = range;
mAttenuationConst = constant;
mAttenuationLinear = linear;
mAttenuationQuad = quadratic;
}
//-----------------------------------------------------------------------
f32 Light::GetAttenuationRange(void) const
{
return mRange;
}
//-----------------------------------------------------------------------
f32 Light::GetAttenuationConstant(void) const
{
return mAttenuationConst;
}
//-----------------------------------------------------------------------
f32 Light::GetAttenuationLinear(void) const
{
return mAttenuationLinear;
}
//-----------------------------------------------------------------------
f32 Light::GetAttenuationQuadric(void) const
{
return mAttenuationQuad;
}
//-----------------------------------------------------------------------
void Light::setPowerScale(f32 power)
{
mPowerScale = power;
}
//-----------------------------------------------------------------------
f32 Light::getPowerScale(void) const
{
return mPowerScale;
}
//-----------------------------------------------------------------------
void Light::update(void) const
{
if(mDerivedTransformDirty)
{
mDerivedPosition = mPosition;
mDerivedDirection = mDirection;
mDerivedTransformDirty = false;
}
if(mCameraToBeRelativeTo && mDerivedCamRelativeDirty)
{
mDerivedCamRelativePosition = mDerivedPosition - mCameraToBeRelativeTo->GetDerivedPosition();
mDerivedCamRelativeDirty = false;
}
}
const AxisAlignedBox& Light::getBoundingBox(void) const
{
// Null, lights are not visible
static AxisAlignedBox box;
return box;
}
const Vector3& Light::getDerivedPosition(bool cameraRelative) const
{
update();
if(cameraRelative && mCameraToBeRelativeTo)
{
return mDerivedCamRelativePosition;
} else
{
return mDerivedPosition;
}
}
//-----------------------------------------------------------------------
const Vector3& Light::getDerivedDirection(void) const
{
update();
return mDerivedDirection;
}
//-----------------------------------------------------------------------
void Light::setVisible(bool visible)
{
//MovableObject::setVisible(visible);
}
//-----------------------------------------------------------------------
Vector4 Light::getAs4DVector(bool cameraRelativeIfSet) const
{
Vector4 ret;
if(mLightType == LightTypes::DIRECTIONAL)
{
ret = -(getDerivedDirection()); // negate direction as 'position'
ret.w = 0.0; // infinite distance
} else
{
ret = getDerivedPosition(cameraRelativeIfSet);
ret.w = 1.0;
}
return ret;
}
//-----------------------------------------------------------------------
const PlaneBoundedVolume& Light::_getNearClipVolume(const Camera * const cam) const
{
// First check if the light is close to the near plane, since
// in this case we have to build a degenerate clip volume
mNearClipVolume.planes.clear();
mNearClipVolume.outside = Plane::NEGATIVE_SIDE;
f32 n = cam->GetNearPlane();
// Homogenous position
Vector4 lightPos = getAs4DVector();
// 3D version (not the same as _getDerivedPosition, is -direction for
// directional lights)
Vector3 lightPos3 = Vector3(lightPos.x, lightPos.y, lightPos.z);
// Get eye-space light position
// use 4D vector so directional lights still work
Vector4 eyeSpaceLight = cam->GetViewMatrix() * lightPos;
// Find distance to light, project onto -Z axis
f32 d = eyeSpaceLight.dotProduct(
Vector4(0, 0, -1, -n));
#define THRESHOLD 1e-6
if(d > THRESHOLD || d < -THRESHOLD)
{
// light is not too close to the near plane
// First find the worldspace positions of the corners of the viewport
const Vector3 *corner = cam->GetWorldSpaceCorners();
int winding = (d < 0) ^ cam->IsReflected() ? +1 : -1;
// Iterate over world points and form side planes
Vector3 normal;
Vector3 lightDir;
for(unsigned int i = 0; i < 4; ++i)
{
// Figure out light dir
lightDir = lightPos3 - (corner[i] * lightPos.w);
// Cross with anticlockwise corner, therefore normal points in
normal = (corner[i] - corner[(i + winding) % 4]).Cross(lightDir);
normal.Normalise();
mNearClipVolume.planes.push_back(Plane(normal, corner[i]));
}
// Now do the near plane plane
normal = cam->GetFrustumPlane(FrustumPlanes::NEAR).normal;
if(d < 0)
{
// Behind near plane
normal = -normal;
}
const Vector3& cameraPos = cam->GetDerivedPosition();
mNearClipVolume.planes.push_back(Plane(normal, cameraPos));
// Finally, for a point/spot light we can add a sixth plane
// This prevents false positives from behind the light
if(mLightType != LightTypes::DIRECTIONAL)
{
// Direction from light perpendicular to near plane
mNearClipVolume.planes.push_back(Plane(-normal, lightPos3));
}
} else
{
// light is close to being on the near plane
// degenerate volume including the entire scene
// we will always require light / dark caps
mNearClipVolume.planes.push_back(Plane(Vector3::UNIT_Z, -n));
mNearClipVolume.planes.push_back(Plane(-Vector3::UNIT_Z, n));
}
return mNearClipVolume;
}
//-----------------------------------------------------------------------
const PlaneBoundedVolumeList& Light::_getFrustumClipVolumes(const Camera * const cam) const
{
// Homogenous light position
Vector4 lightPos = getAs4DVector();
// 3D version (not the same as _getDerivedPosition, is -direction for
// directional lights)
Vector3 lightPos3 = Vector3(lightPos.x, lightPos.y, lightPos.z);
const Vector3 * clockwiseVerts[4];
// Get worldspace frustum corners
const Vector3* corners = cam->GetWorldSpaceCorners();
int windingPt0 = cam->IsReflected() ? 1 : 0;
int windingPt1 = cam->IsReflected() ? 0 : 1;
bool infiniteViewDistance = (cam->GetFarPlane() == 0);
Vector3 notSoFarCorners[4];
if(infiniteViewDistance)
{
Vector3 camPosition = cam->GetRealPosition();
notSoFarCorners[0] = corners[0] + corners[0] - camPosition;
notSoFarCorners[1] = corners[1] + corners[1] - camPosition;
notSoFarCorners[2] = corners[2] + corners[2] - camPosition;
notSoFarCorners[3] = corners[3] + corners[3] - camPosition;
}
mFrustumClipVolumes.clear();
for(unsigned short n = 0; n < 6; ++n)
{
// Skip far plane if infinite view frustum
if(infiniteViewDistance && n == FrustumPlanes::FAR)
continue;
const Plane& plane = cam->GetFrustumPlane(n);
Vector4 planeVec(plane.normal.x, plane.normal.y, plane.normal.z, plane.d);
// planes face inwards, we need to know if light is on negative side
f32 d = planeVec.dotProduct(lightPos);
if(d < -1e-06)
{
// Ok, this is a valid one
// clockwise verts mean we can cross-product and always get normals
// facing into the volume we create
mFrustumClipVolumes.push_back(PlaneBoundedVolume());
PlaneBoundedVolume& vol = mFrustumClipVolumes.back();
switch(n)
{
case(FrustumPlanes::NEAR):
clockwiseVerts[0] = corners + 3;
clockwiseVerts[1] = corners + 2;
clockwiseVerts[2] = corners + 1;
clockwiseVerts[3] = corners + 0;
break;
case(FrustumPlanes::FAR):
clockwiseVerts[0] = corners + 7;
clockwiseVerts[1] = corners + 6;
clockwiseVerts[2] = corners + 5;
clockwiseVerts[3] = corners + 4;
break;
case(FrustumPlanes::LEFT):
clockwiseVerts[0] = infiniteViewDistance ? notSoFarCorners + 1 : corners + 5;
clockwiseVerts[1] = corners + 1;
clockwiseVerts[2] = corners + 2;
clockwiseVerts[3] = infiniteViewDistance ? notSoFarCorners + 2 : corners + 6;
break;
case(FrustumPlanes::RIGHT):
clockwiseVerts[0] = infiniteViewDistance ? notSoFarCorners + 3 : corners + 7;
clockwiseVerts[1] = corners + 3;
clockwiseVerts[2] = corners + 0;
clockwiseVerts[3] = infiniteViewDistance ? notSoFarCorners + 0 : corners + 4;
break;
case(FrustumPlanes::TOP):
clockwiseVerts[0] = infiniteViewDistance ? notSoFarCorners + 0 : corners + 4;
clockwiseVerts[1] = corners + 0;
clockwiseVerts[2] = corners + 1;
clockwiseVerts[3] = infiniteViewDistance ? notSoFarCorners + 1 : corners + 5;
break;
case(FrustumPlanes::BOTTOM):
clockwiseVerts[0] = infiniteViewDistance ? notSoFarCorners + 2 : corners + 6;
clockwiseVerts[1] = corners + 2;
clockwiseVerts[2] = corners + 3;
clockwiseVerts[3] = infiniteViewDistance ? notSoFarCorners + 3 : corners + 7;
break;
};
// Build a volume
// Iterate over world points and form side planes
Vector3 normal;
Vector3 lightDir;
unsigned int infiniteViewDistanceInt = infiniteViewDistance ? 1 : 0;
for(unsigned int i = 0; i < 4 - infiniteViewDistanceInt; ++i)
{
// Figure out light dir
lightDir = lightPos3 - (*(clockwiseVerts[i]) * lightPos.w);
Vector3 edgeDir = *(clockwiseVerts[(i + windingPt1) % 4]) - *(clockwiseVerts[(i + windingPt0) % 4]);
// Cross with anticlockwise corner, therefore normal points in
normal = edgeDir.Cross(lightDir);
normal.Normalise();
vol.planes.push_back(Plane(normal, *(clockwiseVerts[i])));
}
// Now do the near plane (this is the plane of the side we're
// talking about, with the normal inverted (d is already interpreted as -ve)
vol.planes.push_back(Plane(-plane.normal, plane.d));
// Finally, for a point/spot light we can add a sixth plane
// This prevents false positives from behind the light
if(mLightType != LightTypes::DIRECTIONAL)
{
// re-use our own plane normal
vol.planes.push_back(Plane(plane.normal, lightPos3));
}
}
}
return mFrustumClipVolumes;
}
void Light::_calcTempSquareDist(const Vector3& worldPos)
{
if(mLightType == LightTypes::DIRECTIONAL)
{
tempSquareDist = 0;
} else
{
tempSquareDist =
(worldPos - getDerivedPosition()).LengthSquared();
}
}
void Light::setShadowFarDistance(f32 distance)
{
mOwnShadowFarDist = true;
mShadowFarDist = distance;
mShadowFarDistSquared = distance * distance;
}
//-----------------------------------------------------------------------
void Light::resetShadowFarDistance(void)
{
mOwnShadowFarDist = false;
}
//-----------------------------------------------------------------------
f32 Light::getShadowFarDistance(void) const
{
return mShadowFarDist;
}
//-----------------------------------------------------------------------
f32 Light::getShadowFarDistanceSquared(void) const
{
return mShadowFarDistSquared;
}
//---------------------------------------------------------------------
void Light::_setCameraRelative(Camera* cam)
{
mCameraToBeRelativeTo = cam;
mDerivedCamRelativeDirty = true;
}
//---------------------------------------------------------------------
f32 Light::_deriveShadowNearClipDistance(const Camera* maincam) const
{
if(mShadowNearClipDist > 0)
return mShadowNearClipDist;
else
return maincam->GetNearPlane();
}
//---------------------------------------------------------------------
f32 Light::_deriveShadowFarClipDistance(const Camera* maincam) const
{
if(mShadowFarClipDist >= 0)
return mShadowFarClipDist;
else
{
if(mLightType == LightTypes::DIRECTIONAL)
return 0;
else
return mRange;
}
}
//-----------------------------------------------------------------------
void Light::setCustomParameter(u16 index, const Vector4 &value)
{
mCustomParameters[index] = value;
}
//-----------------------------------------------------------------------
const Vector4 &Light::getCustomParameter(u16 index) const
{
CustomParameterMap::const_iterator i = mCustomParameters.find(index);
if(i != mCustomParameters.end())
{
return i->second;
} else
{
assert(0);
}
}
}

File Metadata

Mime Type
text/x-c++
Expires
Wed, Jan 15, 11:46 PM (12 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
72096
Default Alt Text
Light.cpp (18 KB)

Event Timeline