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