Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreLight.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://www.ogre3d.org/
00006 
00007 Copyright © 2000-2002 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 #include "OgreStableHeaders.h"
00026 #include "OgreLight.h"
00027 
00028 #include "OgreException.h"
00029 #include "OgreSceneNode.h"
00030 #include "OgreCamera.h"
00031 
00032 
00033 namespace Ogre {
00034     String Light::msMovableType = "Light";
00035 
00036     //-----------------------------------------------------------------------
00037     Light::Light()
00038     {
00039         // Default to point light, white diffuse light, linear attenuation, fair range
00040         mLightType = LT_POINT;
00041         mDiffuse = ColourValue::White;
00042         mSpecular = ColourValue::Black;
00043         mRange = 5000;
00044         mAttenuationConst = 1.0f;
00045         mAttenuationLinear = 0.0f;
00046         mAttenuationQuad = 0.0f;
00047 
00048         // Center in world, direction irrelevant but set anyway
00049         mPosition = mDerivedPosition = Vector3::ZERO;
00050         mDirection = mDerivedPosition = Vector3::UNIT_Z;
00051         mParentNode = NULL;
00052 
00053         mLocalTransformDirty = false;
00054 
00055     }
00056     //-----------------------------------------------------------------------
00057     Light::Light(const String& name)
00058     {
00059         mName = name;
00060 
00061         // Default to point light, white diffuse light, linear attenuation, fair range
00062         mLightType = LT_POINT;
00063         mDiffuse = ColourValue::White;
00064         mSpecular = ColourValue::Black;
00065         mRange = 100000;
00066         mAttenuationConst = 1.0f;
00067         mAttenuationLinear = 0.0f;
00068         mAttenuationQuad = 0.0f;
00069 
00070         // Center in world, direction irrelevant but set anyway
00071         mPosition = Vector3::ZERO;
00072         mDirection = Vector3::UNIT_Z;
00073 
00074         // Default some spot values
00075         mSpotInner = Degree(30.0f);
00076         mSpotOuter = Degree(40.0f);
00077         mSpotFalloff = 1.0f;
00078         mParentNode = NULL;
00079 
00080 
00081     }
00082     //-----------------------------------------------------------------------
00083     Light::~Light()
00084     {
00085     }
00086     //-----------------------------------------------------------------------
00087     const String& Light::getName(void) const
00088     {
00089         return mName;
00090 
00091     }
00092     //-----------------------------------------------------------------------
00093     void Light::setType(LightTypes type)
00094     {
00095         mLightType = type;
00096     }
00097     //-----------------------------------------------------------------------
00098     Light::LightTypes Light::getType(void) const
00099     {
00100         return mLightType;
00101     }
00102     //-----------------------------------------------------------------------
00103     void Light::setPosition(Real x, Real y, Real z)
00104     {
00105         mPosition.x = x;
00106         mPosition.y = y;
00107         mPosition.z = z;
00108         mLocalTransformDirty = true;
00109 
00110     }
00111     //-----------------------------------------------------------------------
00112     void Light::setPosition(const Vector3& vec)
00113     {
00114         mPosition = vec;
00115         mLocalTransformDirty = true;
00116     }
00117     //-----------------------------------------------------------------------
00118     const Vector3& Light::getPosition(void) const
00119     {
00120         return mPosition;
00121     }
00122     //-----------------------------------------------------------------------
00123     void Light::setDirection(Real x, Real y, Real z)
00124     {
00125         mDirection.x = x;
00126         mDirection.y = y;
00127         mDirection.z = z;
00128         mLocalTransformDirty = true;
00129     }
00130     //-----------------------------------------------------------------------
00131     void Light::setDirection(const Vector3& vec)
00132     {
00133         mDirection = vec;
00134         mLocalTransformDirty = true;
00135     }
00136     //-----------------------------------------------------------------------
00137     const Vector3& Light::getDirection(void) const
00138     {
00139         return mDirection;
00140     }
00141     //-----------------------------------------------------------------------
00142     void Light::setSpotlightRange(const Radian& innerAngle, const Radian& outerAngle, Real falloff)
00143     {
00144 
00145         if (mLightType != LT_SPOTLIGHT)
00146             Except(9999,
00147                 "setSpotlightRange is only valid for spotlights.",
00148                 "Light::setSpotlightRange");
00149 
00150         mSpotInner =innerAngle;
00151         mSpotOuter = outerAngle;
00152         mSpotFalloff = falloff;
00153     }
00154     //-----------------------------------------------------------------------
00155     const Radian& Light::getSpotlightInnerAngle(void) const
00156     {
00157         return mSpotInner;
00158     }
00159     //-----------------------------------------------------------------------
00160     const Radian& Light::getSpotlightOuterAngle(void) const
00161     {
00162         return mSpotOuter;
00163     }
00164     //-----------------------------------------------------------------------
00165     Real Light::getSpotlightFalloff(void) const
00166     {
00167         return mSpotFalloff;
00168     }
00169     //-----------------------------------------------------------------------
00170     void Light::setDiffuseColour(Real red, Real green, Real blue)
00171     {
00172         mDiffuse.r = red;
00173         mDiffuse.b = blue;
00174         mDiffuse.g = green;
00175     }
00176     //-----------------------------------------------------------------------
00177     void Light::setDiffuseColour(const ColourValue& colour)
00178     {
00179         mDiffuse = colour;
00180     }
00181     //-----------------------------------------------------------------------
00182     const ColourValue& Light::getDiffuseColour(void) const
00183     {
00184         return mDiffuse;
00185     }
00186     //-----------------------------------------------------------------------
00187     void Light::setSpecularColour(Real red, Real green, Real blue)
00188     {
00189         mSpecular.r = red;
00190         mSpecular.b = blue;
00191         mSpecular.g = green;
00192     }
00193     //-----------------------------------------------------------------------
00194     void Light::setSpecularColour(const ColourValue& colour)
00195     {
00196         mSpecular = colour;
00197     }
00198     //-----------------------------------------------------------------------
00199     const ColourValue& Light::getSpecularColour(void) const
00200     {
00201         return mSpecular;
00202     }
00203     //-----------------------------------------------------------------------
00204     void Light::setAttenuation(Real range, Real constant,
00205                         Real linear, Real quadratic)
00206     {
00207         mRange = range;
00208         mAttenuationConst = constant;
00209         mAttenuationLinear = linear;
00210         mAttenuationQuad = quadratic;
00211     }
00212     //-----------------------------------------------------------------------
00213     Real Light::getAttenuationRange(void) const
00214     {
00215         return mRange;
00216     }
00217     //-----------------------------------------------------------------------
00218     Real Light::getAttenuationConstant(void) const
00219     {
00220         return mAttenuationConst;
00221     }
00222     //-----------------------------------------------------------------------
00223     Real Light::getAttenuationLinear(void) const
00224     {
00225         return mAttenuationLinear;
00226     }
00227     //-----------------------------------------------------------------------
00228     Real Light::getAttenuationQuadric(void) const
00229     {
00230         return mAttenuationQuad;
00231     }
00232     //-----------------------------------------------------------------------
00233     void Light::update(void) const
00234     {
00235         if (mParentNode)
00236         {
00237             if (!(mParentNode->_getDerivedOrientation() == mLastParentOrientation &&
00238                 mParentNode->_getDerivedPosition() == mLastParentPosition)
00239                 || mLocalTransformDirty)
00240             {
00241                 // Ok, we're out of date with SceneNode we're attached to
00242                 mLastParentOrientation = mParentNode->_getDerivedOrientation();
00243                 mLastParentPosition = mParentNode->_getDerivedPosition();
00244                 mDerivedDirection = mLastParentOrientation * mDirection;
00245                 mDerivedPosition = (mLastParentOrientation * mPosition) + mLastParentPosition;
00246             }
00247         }
00248         else
00249         {
00250             mDerivedPosition = mPosition;
00251             mDerivedDirection = mDirection;
00252         }
00253 
00254         mLocalTransformDirty = false;
00255 
00256     }
00257     //-----------------------------------------------------------------------
00258     void Light::_notifyCurrentCamera(Camera* cam)
00259     {
00260         // Do nothing
00261     }
00262     //-----------------------------------------------------------------------
00263     const AxisAlignedBox& Light::getBoundingBox(void) const
00264     {
00265         // Null, lights are not visible
00266         static AxisAlignedBox box;
00267         return box;
00268     }
00269     //-----------------------------------------------------------------------
00270     void Light::_updateRenderQueue(RenderQueue* queue)
00271     {
00272         // Do nothing
00273     }
00274     //-----------------------------------------------------------------------
00275     const String& Light::getMovableType(void) const
00276     {
00277         return msMovableType;
00278     }
00279     //-----------------------------------------------------------------------
00280     const Vector3& Light::getDerivedPosition(void) const
00281     {
00282         update();
00283         return mDerivedPosition;
00284     }
00285     //-----------------------------------------------------------------------
00286     const Vector3& Light::getDerivedDirection(void) const
00287     {
00288         update();
00289         return mDerivedDirection;
00290     }
00291     //-----------------------------------------------------------------------
00292     void Light::setVisible(bool visible)
00293     {
00294         MovableObject::setVisible(visible);
00295     }
00296     //-----------------------------------------------------------------------
00297     Vector4 Light::getAs4DVector(void) const
00298     {
00299         Vector4 ret;
00300         if (mLightType == Light::LT_DIRECTIONAL)
00301         {
00302             ret = -(getDerivedDirection()); // negate direction as 'position'
00303             ret.w = 0.0; // infinite distance
00304         }   
00305         else
00306         {
00307             ret = getDerivedPosition();
00308             ret.w = 1.0;
00309         }
00310         return ret;
00311     }
00312     //-----------------------------------------------------------------------
00313     const PlaneBoundedVolume& Light::_getNearClipVolume(const Camera* const cam) const
00314     {
00315         // First check if the light is close to the near plane, since
00316         // in this case we have to build a degenerate clip volume
00317         mNearClipVolume.planes.clear();
00318         mNearClipVolume.outside = Plane::NEGATIVE_SIDE;
00319 
00320         Real n = cam->getNearClipDistance();
00321         // Homogenous position
00322         Vector4 lightPos = getAs4DVector();
00323         // 3D version (not the same as _getDerivedPosition, is -direction for
00324         // directional lights)
00325         Vector3 lightPos3 = Vector3(lightPos.x, lightPos.y, lightPos.z);
00326 
00327         // Get eye-space light position
00328         // use 4D vector so directional lights still work
00329         Vector4 eyeSpaceLight = cam->getViewMatrix() * lightPos;
00330         Matrix4 eyeToWorld = cam->getViewMatrix().inverse();
00331         // Find distance to light, project onto -Z axis
00332         Real d = eyeSpaceLight.dotProduct(
00333             Vector4(0, 0, -1, -n) );
00334         #define THRESHOLD 1e-6
00335         if (d > THRESHOLD || d < -THRESHOLD)
00336         {
00337             // light is not too close to the near plane
00338             // First find the worldspace positions of the corners of the viewport
00339             const Vector3 *corner = cam->getWorldSpaceCorners();
00340             // Iterate over world points and form side planes
00341             Vector3 normal;
00342             Vector3 lightDir;
00343             for (unsigned int i = 0; i < 4; ++i)
00344             {
00345                 // Figure out light dir
00346                 lightDir = lightPos3 - (corner[i] * lightPos.w);
00347                 // Cross with anticlockwise corner, therefore normal points in
00348                 normal = (corner[i] - corner[(i-1)%4])
00349                     .crossProduct(lightDir);
00350                 normal.normalise();
00351                 if (d < THRESHOLD)
00352                 {
00353                     // invert normal
00354                     normal = -normal;
00355                 }
00356                 // NB last param to Plane constructor is negated because it's -d
00357                 mNearClipVolume.planes.push_back(
00358                     Plane(normal, normal.dotProduct(corner[i])));
00359 
00360             }
00361 
00362             // Now do the near plane plane
00363             if (d > THRESHOLD)
00364             {
00365                 // In front of near plane
00366                 // remember the -d negation in plane constructor
00367                 normal = eyeToWorld * -Vector3::UNIT_Z;
00368                 normal.normalise();
00369                 mNearClipVolume.planes.push_back(
00370                     Plane(normal, -normal.dotProduct(cam->getDerivedPosition())));
00371             }
00372             else
00373             {
00374                 // Behind near plane
00375                 // remember the -d negation in plane constructor
00376                 normal = eyeToWorld * Vector3::UNIT_Z;
00377                 normal.normalise();
00378                 mNearClipVolume.planes.push_back(
00379                     Plane(normal, -normal.dotProduct(cam->getDerivedPosition())));
00380             }
00381 
00382             // Finally, for a point/spot light we can add a sixth plane
00383             // This prevents false positives from behind the light
00384             if (mLightType != LT_DIRECTIONAL)
00385             {
00386                 // Direction from light to centre point of viewport 
00387                 normal = (eyeToWorld * Vector3(0,0,-n)) - lightPos3;
00388                 normal.normalise();
00389                 // remember the -d negation in plane constructor
00390                 mNearClipVolume.planes.push_back(
00391                     Plane(normal, normal.dotProduct(lightPos3)));
00392 
00393             }
00394 
00395 
00396         }
00397         else
00398         {
00399             // light is close to being on the near plane
00400             // degenerate volume including the entire scene 
00401             // we will always require light / dark caps
00402             mNearClipVolume.planes.push_back(Plane(Vector3::UNIT_Z, -n));
00403             mNearClipVolume.planes.push_back(Plane(-Vector3::UNIT_Z, n));
00404         }
00405 
00406         return mNearClipVolume;
00407 
00408     }
00409     //-----------------------------------------------------------------------
00410     const PlaneBoundedVolumeList& Light::_getFrustumClipVolumes(const Camera* const cam) const
00411     {
00412 
00413         // Homogenous light position
00414         Vector4 lightPos = getAs4DVector();
00415         // 3D version (not the same as _getDerivedPosition, is -direction for
00416         // directional lights)
00417         Vector3 lightPos3 = Vector3(lightPos.x, lightPos.y, lightPos.z);
00418 
00419         const Vector3 *clockwiseVerts[4];
00420 
00421         Matrix4 eyeToWorld = cam->getViewMatrix().inverse();
00422         // Get worldspace frustum corners
00423         const Vector3* corners = cam->getWorldSpaceCorners();
00424 
00425         bool infiniteViewDistance = (cam->getFarClipDistance() == 0);
00426 
00427         mFrustumClipVolumes.clear();
00428         for (unsigned short n = 0; n < 6; ++n)
00429         {
00430             // Skip far plane if infinite view frustum
00431             if (infiniteViewDistance && n == FRUSTUM_PLANE_FAR)
00432                 continue;
00433 
00434             const Plane& plane = cam->getFrustumPlane(n);
00435             Vector4 planeVec(plane.normal.x, plane.normal.y, plane.normal.z, plane.d);
00436             // planes face inwards, we need to know if light is on negative side
00437             Real d = planeVec.dotProduct(lightPos);
00438             if (d < -1e-06)
00439             {
00440                 // Ok, this is a valid one
00441                 // clockwise verts mean we can cross-product and always get normals
00442                 // facing into the volume we create
00443 
00444                 mFrustumClipVolumes.push_back(PlaneBoundedVolume());
00445                 PlaneBoundedVolume& vol = mFrustumClipVolumes[mFrustumClipVolumes.size() - 1];
00446                 switch(n)
00447                 {
00448                 case(FRUSTUM_PLANE_NEAR):
00449                     clockwiseVerts[0] = corners + 3;
00450                     clockwiseVerts[1] = corners + 2;
00451                     clockwiseVerts[2] = corners + 1;
00452                     clockwiseVerts[3] = corners + 0;
00453                     break;
00454                 case(FRUSTUM_PLANE_FAR):
00455                     clockwiseVerts[0] = corners + 7;
00456                     clockwiseVerts[1] = corners + 6;
00457                     clockwiseVerts[2] = corners + 5;
00458                     clockwiseVerts[3] = corners + 4;
00459                     break;
00460                 case(FRUSTUM_PLANE_LEFT):
00461                     clockwiseVerts[0] = corners + 2;
00462                     clockwiseVerts[1] = corners + 6;
00463                     clockwiseVerts[2] = corners + 5;
00464                     clockwiseVerts[3] = corners + 1;
00465                     break;
00466                 case(FRUSTUM_PLANE_RIGHT):
00467                     clockwiseVerts[0] = corners + 7;
00468                     clockwiseVerts[1] = corners + 3;
00469                     clockwiseVerts[2] = corners + 0;
00470                     clockwiseVerts[3] = corners + 4;
00471                     break;
00472                 case(FRUSTUM_PLANE_TOP):
00473                     clockwiseVerts[0] = corners + 0;
00474                     clockwiseVerts[1] = corners + 1;
00475                     clockwiseVerts[2] = corners + 5;
00476                     clockwiseVerts[3] = corners + 4;
00477                     break;
00478                 case(FRUSTUM_PLANE_BOTTOM):
00479                     clockwiseVerts[0] = corners + 7;
00480                     clockwiseVerts[1] = corners + 6;
00481                     clockwiseVerts[2] = corners + 2;
00482                     clockwiseVerts[3] = corners + 3;
00483                     break;
00484                 };
00485 
00486                 // Build a volume
00487                 // Iterate over world points and form side planes
00488                 Vector3 normal;
00489                 Vector3 lightDir;
00490                 for (unsigned int i = 0; i < 4; ++i)
00491                 {
00492                     // Figure out light dir
00493                     lightDir = lightPos3 - (*(clockwiseVerts[i]) * lightPos.w);
00494                     Vector3 edgeDir = *(clockwiseVerts[i]) - *(clockwiseVerts[(i-1)%4]);
00495                     // Cross with anticlockwise corner, therefore normal points in
00496                     normal = edgeDir.crossProduct(lightDir);
00497                     normal.normalise();
00498                     // NB last param to Plane constructor is negated because it's -d
00499                     vol.planes.push_back(
00500                         Plane(normal, normal.dotProduct(*(clockwiseVerts[i]))));
00501 
00502                 }
00503 
00504                 // Now do the near plane (this is the plane of the side we're 
00505                 // talking about, with the normal inverted (d is already interpreted as -ve)
00506                 vol.planes.push_back( Plane(-plane.normal, plane.d) );
00507 
00508                 // Finally, for a point/spot light we can add a sixth plane
00509                 // This prevents false positives from behind the light
00510                 if (mLightType != LT_DIRECTIONAL)
00511                 {
00512                     // re-use our own plane normal
00513                     // remember the -d negation in plane constructor
00514                     vol.planes.push_back(
00515                         Plane(plane.normal, 
00516                             plane.normal.dotProduct(lightPos3)));
00517 
00518                 }
00519 
00520 
00521             }
00522         }
00523         return mFrustumClipVolumes;
00524     }
00525 
00526 
00527 
00528 
00529 } // Namespace

Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:30 2004