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