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