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

Copyright © 2002-2003 by The OGRE Team
Last modified Fri May 14 23:22:19 2004