00001 /* 00002 ----------------------------------------------------------------------------- 00003 This source file is part of OGRE 00004 (Object-oriented Graphics Rendering Engine) 00005 For the latest info, see http://ogre.sourceforge.net/ 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 "OgreFrustum.h" 00027 00028 #include "OgreMath.h" 00029 #include "OgreMatrix3.h" 00030 #include "OgreSceneNode.h" 00031 #include "OgreSphere.h" 00032 #include "OgreLogManager.h" 00033 #include "OgreException.h" 00034 #include "OgreRoot.h" 00035 #include "OgreCamera.h" 00036 #include "OgreHardwareBufferManager.h" 00037 #include "OgreHardwareVertexBuffer.h" 00038 #include "OgreHardwareIndexBuffer.h" 00039 #include "OgreMaterialManager.h" 00040 #include "OgreRenderSystem.h" 00041 00042 namespace Ogre { 00043 00044 String Frustum::msMovableType = "Frustum"; 00045 const Real Frustum::INFINITE_FAR_PLANE_ADJUST = 0.00001; 00046 //----------------------------------------------------------------------- 00047 Frustum::Frustum() 00048 { 00049 // Reasonable defaults to Frustum params 00050 mFOVy = Math::RadiansToAngleUnits(Math::PI/4.0); 00051 mNearDist = 100.0f; 00052 mFarDist = 100000.0f; 00053 mAspect = 1.33333333333333f; 00054 mProjType = PT_PERSPECTIVE; 00055 00056 mRecalcFrustum = true; 00057 mRecalcView = true; 00058 00059 // Init matrices 00060 mViewMatrix = Matrix4::ZERO; 00061 mProjMatrix = Matrix4::ZERO; 00062 mReflectMatrix = Matrix4::ZERO; 00063 00064 // Initialise vertex & index data 00065 mVertexData.vertexDeclaration->addElement(0, 0, VET_FLOAT3, VES_POSITION); 00066 mVertexData.vertexCount = 32; 00067 mVertexData.vertexStart = 0; 00068 mVertexData.vertexBufferBinding->setBinding( 0, 00069 HardwareBufferManager::getSingleton().createVertexBuffer( 00070 sizeof(Real)*3, 32, HardwareBuffer::HBU_DYNAMIC) ); 00071 00072 // Initialise material 00073 mMaterial = static_cast<Material*>( 00074 MaterialManager::getSingleton().getByName("BaseWhiteNoLighting")); 00075 00076 // Default to not visible 00077 mVisible = false; 00078 00079 // no reflection 00080 mReflect = false; 00081 00082 mParentNode = 0; 00083 00084 updateView(); 00085 } 00086 00087 //----------------------------------------------------------------------- 00088 Frustum::~Frustum() 00089 { 00090 // Do nothing 00091 } 00092 00093 //----------------------------------------------------------------------- 00094 void Frustum::setFOVy(Real fov) 00095 { 00096 mFOVy = fov; 00097 invalidateFrustum(); 00098 } 00099 00100 //----------------------------------------------------------------------- 00101 Real Frustum::getFOVy(void) const 00102 { 00103 return mFOVy; 00104 } 00105 00106 00107 //----------------------------------------------------------------------- 00108 void Frustum::setFarClipDistance(Real farPlane) 00109 { 00110 mFarDist = farPlane; 00111 invalidateFrustum(); 00112 } 00113 00114 //----------------------------------------------------------------------- 00115 Real Frustum::getFarClipDistance(void) const 00116 { 00117 return mFarDist; 00118 } 00119 00120 //----------------------------------------------------------------------- 00121 void Frustum::setNearClipDistance(Real nearPlane) 00122 { 00123 if (nearPlane <= 0) 00124 Except(Exception::ERR_INVALIDPARAMS, "Near clip distance must be greater than zero.", 00125 "Frustum::setNearClipDistance"); 00126 mNearDist = nearPlane; 00127 invalidateFrustum(); 00128 } 00129 00130 //----------------------------------------------------------------------- 00131 Real Frustum::getNearClipDistance(void) const 00132 { 00133 return mNearDist; 00134 } 00135 00136 //----------------------------------------------------------------------- 00137 const Matrix4& Frustum::getProjectionMatrix(void) const 00138 { 00139 00140 updateFrustum(); 00141 00142 return mProjMatrix; 00143 } 00144 //----------------------------------------------------------------------- 00145 const Matrix4& Frustum::getStandardProjectionMatrix(void) const 00146 { 00147 00148 updateFrustum(); 00149 00150 return mStandardProjMatrix; 00151 } 00152 //----------------------------------------------------------------------- 00153 const Matrix4& Frustum::getViewMatrix(void) const 00154 { 00155 updateView(); 00156 00157 return mViewMatrix; 00158 00159 } 00160 00161 //----------------------------------------------------------------------- 00162 const Plane& Frustum::getFrustumPlane(unsigned short plane) const 00163 { 00164 // Make any pending updates to the calculated frustum 00165 updateView(); 00166 00167 return mFrustumPlanes[plane]; 00168 00169 } 00170 00171 //----------------------------------------------------------------------- 00172 bool Frustum::isVisible(const AxisAlignedBox& bound, FrustumPlane* culledBy) const 00173 { 00174 // Null boxes always invisible 00175 if (bound.isNull()) return false; 00176 00177 // Make any pending updates to the calculated frustum 00178 updateView(); 00179 00180 // Get corners of the box 00181 const Vector3* pCorners = bound.getAllCorners(); 00182 00183 00184 // For each plane, see if all points are on the negative side 00185 // If so, object is not visible 00186 for (int plane = 0; plane < 6; ++plane) 00187 { 00188 // Skip far plane if infinite view frustum 00189 if (mFarDist == 0 && plane == FRUSTUM_PLANE_FAR) 00190 continue; 00191 00192 if (mFrustumPlanes[plane].getSide(pCorners[0]) == Plane::NEGATIVE_SIDE && 00193 mFrustumPlanes[plane].getSide(pCorners[1]) == Plane::NEGATIVE_SIDE && 00194 mFrustumPlanes[plane].getSide(pCorners[2]) == Plane::NEGATIVE_SIDE && 00195 mFrustumPlanes[plane].getSide(pCorners[3]) == Plane::NEGATIVE_SIDE && 00196 mFrustumPlanes[plane].getSide(pCorners[4]) == Plane::NEGATIVE_SIDE && 00197 mFrustumPlanes[plane].getSide(pCorners[5]) == Plane::NEGATIVE_SIDE && 00198 mFrustumPlanes[plane].getSide(pCorners[6]) == Plane::NEGATIVE_SIDE && 00199 mFrustumPlanes[plane].getSide(pCorners[7]) == Plane::NEGATIVE_SIDE) 00200 { 00201 // ALL corners on negative side therefore out of view 00202 if (culledBy) 00203 *culledBy = (FrustumPlane)plane; 00204 return false; 00205 } 00206 00207 } 00208 00209 return true; 00210 } 00211 00212 //----------------------------------------------------------------------- 00213 bool Frustum::isVisible(const Vector3& vert, FrustumPlane* culledBy) const 00214 { 00215 // Make any pending updates to the calculated frustum 00216 updateView(); 00217 00218 // For each plane, see if all points are on the negative side 00219 // If so, object is not visible 00220 for (int plane = 0; plane < 6; ++plane) 00221 { 00222 // Skip far plane if infinite view frustum 00223 if (mFarDist == 0 && plane == FRUSTUM_PLANE_FAR) 00224 continue; 00225 00226 if (mFrustumPlanes[plane].getSide(vert) == Plane::NEGATIVE_SIDE) 00227 { 00228 // ALL corners on negative side therefore out of view 00229 if (culledBy) 00230 *culledBy = (FrustumPlane)plane; 00231 return false; 00232 } 00233 00234 } 00235 00236 return true; 00237 } 00238 00239 //----------------------------------------------------------------------- 00240 bool Frustum::isVisible(const Sphere& sphere, FrustumPlane* culledBy) const 00241 { 00242 // Make any pending updates to the calculated frustum 00243 updateView(); 00244 00245 // For each plane, see if sphere is on negative side 00246 // If so, object is not visible 00247 for (int plane = 0; plane < 6; ++plane) 00248 { 00249 // Skip far plane if infinite view frustum 00250 if (mFarDist == 0 && plane == FRUSTUM_PLANE_FAR) 00251 continue; 00252 00253 // If the distance from sphere center to plane is negative, and 'more negative' 00254 // than the radius of the sphere, sphere is outside frustum 00255 if (mFrustumPlanes[plane].getDistance(sphere.getCenter()) < -sphere.getRadius()) 00256 { 00257 // ALL corners on negative side therefore out of view 00258 if (culledBy) 00259 *culledBy = (FrustumPlane)plane; 00260 return false; 00261 } 00262 00263 } 00264 00265 return true; 00266 } 00267 //----------------------------------------------------------------------- 00268 void Frustum::updateFrustum(void) const 00269 { 00270 if (mRecalcFrustum) 00271 { 00272 // Common calcs 00273 Real thetaY = Math::AngleUnitsToRadians(mFOVy * 0.5f); 00274 Real tanThetaY = Math::Tan(thetaY); 00275 Real tanThetaX = tanThetaY * mAspect; 00276 Real vpTop = tanThetaY * mNearDist; 00277 Real vpRight = tanThetaX * mNearDist; 00278 Real vpBottom = -vpTop; 00279 Real vpLeft = -vpRight; 00280 Real fNSqr = mNearDist * mNearDist; 00281 Real fLSqr = vpRight * vpRight; 00282 Real fRSqr = fLSqr; 00283 Real fTSqr = vpTop * vpTop; 00284 Real fBSqr = fTSqr; 00285 Real fInvLength = 1.0 / Math::Sqrt( fNSqr + fLSqr ); 00286 00287 // Recalc if frustum params changed 00288 if (mProjType == PT_PERSPECTIVE) 00289 { 00290 00291 // PERSPECTIVE transform, API specific 00292 Root::getSingleton().getRenderSystem()->_makeProjectionMatrix(mFOVy, 00293 mAspect, mNearDist, mFarDist, mProjMatrix); 00294 00295 // PERSPECTIVE transform, API specific for Gpu Programs 00296 Root::getSingleton().getRenderSystem()->_makeProjectionMatrix(mFOVy, 00297 mAspect, mNearDist, mFarDist, mStandardProjMatrix, true); 00298 00299 // Calculate co-efficients for the frustum planes 00300 // Special-cased for L = -R and B = -T i.e. viewport centered 00301 // on direction vector. 00302 // Taken from ideas in WildMagic 0.2 http://www.magic-software.com 00303 mCoeffL[0] = mNearDist * fInvLength; 00304 mCoeffL[1] = -vpLeft * fInvLength; 00305 00306 fInvLength = 1.0 / Math::Sqrt( fNSqr + fRSqr ); 00307 mCoeffR[0] = -mNearDist * fInvLength; 00308 mCoeffR[1] = vpRight * fInvLength; 00309 00310 fInvLength = 1.0 / Math::Sqrt( fNSqr + fBSqr ); 00311 mCoeffB[0] = mNearDist * fInvLength; 00312 mCoeffB[1] = -vpBottom * fInvLength; 00313 00314 fInvLength = 1.0 / Math::Sqrt( fNSqr + fTSqr ); 00315 mCoeffT[0] = -mNearDist * fInvLength; 00316 mCoeffT[1] = vpTop * fInvLength; 00317 } 00318 else if (mProjType == PT_ORTHOGRAPHIC) 00319 { 00320 // ORTHOGRAPHIC projection, API specific 00321 Root::getSingleton().getRenderSystem()->_makeOrthoMatrix(mFOVy, 00322 mAspect, mNearDist, mFarDist, mProjMatrix); 00323 00324 // ORTHOGRAPHIC projection, non-API specific 00325 Root::getSingleton().getRenderSystem()->_makeOrthoMatrix(mFOVy, 00326 mAspect, mNearDist, mFarDist, mStandardProjMatrix, true); 00327 00328 00329 // Calculate co-efficients for the frustum planes 00330 // Special-cased for L = -R and B = -T i.e. viewport centered 00331 // on direction vector. 00332 // Taken from ideas in WildMagic 0.2 http://www.magic-software.com 00333 00334 // TODO: shouldn't this be changed for ortho? 00335 mCoeffL[0] = mNearDist * fInvLength; 00336 mCoeffL[1] = -vpLeft * fInvLength; 00337 00338 fInvLength = 1.0 / Math::Sqrt( fNSqr + fRSqr ); 00339 mCoeffR[0] = -mNearDist * fInvLength; 00340 mCoeffR[1] = vpRight * fInvLength; 00341 00342 fInvLength = 1.0 / Math::Sqrt( fNSqr + fBSqr ); 00343 mCoeffB[0] = mNearDist * fInvLength; 00344 mCoeffB[1] = -vpBottom * fInvLength; 00345 00346 fInvLength = 1.0 / Math::Sqrt( fNSqr + fTSqr ); 00347 mCoeffT[0] = -mNearDist * fInvLength; 00348 mCoeffT[1] = vpTop * fInvLength; 00349 00350 } 00351 00352 00353 // Calculate bounding box (local) 00354 // Box is from 0, down -Z, max dimensions as determined from far plane 00355 // If infinite view frustum just pick a far value 00356 Real farDist = (mFarDist == 0) ? 100000 : mFarDist; 00357 Real farTop = tanThetaY * (mProjType == PT_ORTHOGRAPHIC? mNearDist : farDist); 00358 Real farRight = tanThetaX * (mProjType == PT_ORTHOGRAPHIC? mNearDist : farDist); 00359 Real farBottom = -farTop; 00360 Real farLeft = -farRight; 00361 Vector3 min(-farRight, -farTop, 0); 00362 Vector3 max(farRight, farTop, -farDist); 00363 mBoundingBox.setExtents(min, max); 00364 00365 // Calculate vertex positions (local) 00366 // 0 is the origin 00367 // 1, 2, 3, 4 are the points on the near plane, top left first, clockwise 00368 // 5, 6, 7, 8 are the points on the far plane, top left first, clockwise 00369 HardwareVertexBufferSharedPtr vbuf = mVertexData.vertexBufferBinding->getBuffer(0); 00370 Real* pReal = static_cast<Real*>(vbuf->lock(HardwareBuffer::HBL_DISCARD)); 00371 00372 // near plane (remember frustum is going in -Z direction) 00373 *pReal++ = vpLeft; *pReal++ = vpTop; *pReal++ = -mNearDist; 00374 *pReal++ = vpRight; *pReal++ = vpTop; *pReal++ = -mNearDist; 00375 00376 *pReal++ = vpRight; *pReal++ = vpTop; *pReal++ = -mNearDist; 00377 *pReal++ = vpRight; *pReal++ = vpBottom; *pReal++ = -mNearDist; 00378 00379 *pReal++ = vpRight; *pReal++ = vpBottom; *pReal++ = -mNearDist; 00380 *pReal++ = vpLeft; *pReal++ = vpBottom; *pReal++ = -mNearDist; 00381 00382 *pReal++ = vpLeft; *pReal++ = vpBottom; *pReal++ = -mNearDist; 00383 *pReal++ = vpLeft; *pReal++ = vpTop; *pReal++ = -mNearDist; 00384 00385 // far plane (remember frustum is going in -Z direction) 00386 *pReal++ = farLeft; *pReal++ = farTop; *pReal++ = -farDist; 00387 *pReal++ = farRight; *pReal++ = farTop; *pReal++ = -farDist; 00388 00389 *pReal++ = farRight; *pReal++ = farTop; *pReal++ = -farDist; 00390 *pReal++ = farRight; *pReal++ = farBottom; *pReal++ = -farDist; 00391 00392 *pReal++ = farRight; *pReal++ = farBottom; *pReal++ = -farDist; 00393 *pReal++ = farLeft; *pReal++ = farBottom; *pReal++ = -farDist; 00394 00395 *pReal++ = farLeft; *pReal++ = farBottom; *pReal++ = -farDist; 00396 *pReal++ = farLeft; *pReal++ = farTop; *pReal++ = -farDist; 00397 00398 // Sides of the pyramid 00399 *pReal++ = 0.0f; *pReal++ = 0.0f; *pReal++ = 0.0f; 00400 *pReal++ = vpLeft; *pReal++ = vpTop; *pReal++ = -mNearDist; 00401 00402 *pReal++ = 0.0f; *pReal++ = 0.0f; *pReal++ = 0.0f; 00403 *pReal++ = vpRight; *pReal++ = vpTop; *pReal++ = -mNearDist; 00404 00405 *pReal++ = 0.0f; *pReal++ = 0.0f; *pReal++ = 0.0f; 00406 *pReal++ = vpRight; *pReal++ = vpBottom; *pReal++ = -mNearDist; 00407 00408 *pReal++ = 0.0f; *pReal++ = 0.0f; *pReal++ = 0.0f; 00409 *pReal++ = vpLeft; *pReal++ = vpBottom; *pReal++ = -mNearDist; 00410 00411 // Sides of the box 00412 00413 *pReal++ = vpLeft; *pReal++ = vpTop; *pReal++ = -mNearDist; 00414 *pReal++ = farLeft; *pReal++ = farTop; *pReal++ = -farDist; 00415 00416 *pReal++ = vpRight; *pReal++ = vpTop; *pReal++ = -mNearDist; 00417 *pReal++ = farRight; *pReal++ = farTop; *pReal++ = -farDist; 00418 00419 *pReal++ = vpRight; *pReal++ = vpBottom; *pReal++ = -mNearDist; 00420 *pReal++ = farRight; *pReal++ = farBottom; *pReal++ = -farDist; 00421 00422 *pReal++ = vpLeft; *pReal++ = vpBottom; *pReal++ = -mNearDist; 00423 *pReal++ = farLeft; *pReal++ = farBottom; *pReal++ = -farDist; 00424 00425 00426 vbuf->unlock(); 00427 00428 mRecalcFrustum = false; 00429 } 00430 } 00431 00432 //----------------------------------------------------------------------- 00433 bool Frustum::isViewOutOfDate(void) const 00434 { 00435 // Attached to node? 00436 if (mParentNode) 00437 { 00438 if (!mRecalcView && mParentNode->_getDerivedOrientation() == mLastParentOrientation && 00439 mParentNode->_getDerivedPosition() == mLastParentPosition) 00440 { 00441 return false; 00442 } 00443 else 00444 { 00445 // Ok, we're out of date with SceneNode we're attached to 00446 mLastParentOrientation = mParentNode->_getDerivedOrientation(); 00447 mLastParentPosition = mParentNode->_getDerivedPosition(); 00448 return true; 00449 } 00450 } 00451 return mRecalcView; 00452 } 00453 00454 //----------------------------------------------------------------------- 00455 bool Frustum::isFrustumOutOfDate(void) const 00456 { 00457 return mRecalcFrustum; 00458 } 00459 00460 //----------------------------------------------------------------------- 00461 void Frustum::updateView(void) const 00462 { 00463 if (isViewOutOfDate()) 00464 { 00465 // ---------------------- 00466 // Update the view matrix 00467 // ---------------------- 00468 00469 // View matrix is: 00470 // 00471 // [ Lx Uy Dz Tx ] 00472 // [ Lx Uy Dz Ty ] 00473 // [ Lx Uy Dz Tz ] 00474 // [ 0 0 0 1 ] 00475 // 00476 // Where T = -(Transposed(Rot) * Pos) 00477 00478 // This is most efficiently done using 3x3 Matrices 00479 00480 // Get orientation from quaternion 00481 00482 Matrix3 rot; 00483 const Quaternion& orientation = getOrientationForViewUpdate(); 00484 const Vector3& position = getPositionForViewUpdate(); 00485 orientation.ToRotationMatrix(rot); 00486 Vector3 left = rot.GetColumn(0); 00487 Vector3 up = rot.GetColumn(1); 00488 Vector3 direction = rot.GetColumn(2); 00489 00490 00491 // Make the translation relative to new axes 00492 Matrix3 rotT = rot.Transpose(); 00493 Vector3 trans = -rotT * position; 00494 00495 // Make final matrix 00496 mViewMatrix = Matrix4::IDENTITY; 00497 mViewMatrix = rotT; // fills upper 3x3 00498 mViewMatrix[0][3] = trans.x; 00499 mViewMatrix[1][3] = trans.y; 00500 mViewMatrix[2][3] = trans.z; 00501 00502 // Deal with reflections 00503 if (mReflect) 00504 { 00505 mViewMatrix = mViewMatrix * mReflectMatrix; 00506 } 00507 00508 // ------------------------- 00509 // Update the frustum planes 00510 // ------------------------- 00511 updateFrustum(); 00512 // Use Frustum view direction for frustum, which is -Z not Z as for matrix calc 00513 Vector3 camDirection = orientation* -Vector3::UNIT_Z; 00514 // Calc distance along direction to position 00515 Real fDdE = camDirection.dotProduct(position); 00516 00517 // left plane 00518 mFrustumPlanes[FRUSTUM_PLANE_LEFT].normal = mCoeffL[0]*left + 00519 mCoeffL[1]*camDirection; 00520 mFrustumPlanes[FRUSTUM_PLANE_LEFT].d = 00521 -position.dotProduct(mFrustumPlanes[FRUSTUM_PLANE_LEFT].normal); 00522 00523 // right plane 00524 mFrustumPlanes[FRUSTUM_PLANE_RIGHT].normal = mCoeffR[0]*left + 00525 mCoeffR[1]*camDirection; 00526 mFrustumPlanes[FRUSTUM_PLANE_RIGHT].d = 00527 -position.dotProduct(mFrustumPlanes[FRUSTUM_PLANE_RIGHT].normal); 00528 00529 // bottom plane 00530 mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].normal = mCoeffB[0]*up + 00531 mCoeffB[1]*camDirection; 00532 mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].d = 00533 -position.dotProduct(mFrustumPlanes[FRUSTUM_PLANE_BOTTOM].normal); 00534 00535 // top plane 00536 mFrustumPlanes[FRUSTUM_PLANE_TOP].normal = mCoeffT[0]*up + 00537 mCoeffT[1]*camDirection; 00538 mFrustumPlanes[FRUSTUM_PLANE_TOP].d = 00539 -position.dotProduct(mFrustumPlanes[FRUSTUM_PLANE_TOP].normal); 00540 00541 // far plane 00542 mFrustumPlanes[FRUSTUM_PLANE_FAR].normal = -camDirection; 00543 // d is distance along normal to origin 00544 mFrustumPlanes[FRUSTUM_PLANE_FAR].d = fDdE + mFarDist; 00545 00546 // near plane 00547 mFrustumPlanes[FRUSTUM_PLANE_NEAR].normal = camDirection; 00548 mFrustumPlanes[FRUSTUM_PLANE_NEAR].d = -(fDdE + mNearDist); 00549 00550 // Update worldspace corners 00551 Matrix4 eyeToWorld = mViewMatrix.inverse(); 00552 // Get worldspace frustum corners 00553 // Treat infinite fardist as some arbitrary far value 00554 Real farDist = (mFarDist == 0)? 100000 : mFarDist; 00555 Real y = Math::Tan(mFOVy * 0.5); 00556 Real x = mAspect * y; 00557 Real neary = y * mNearDist; 00558 Real fary = y * (mProjType == PT_ORTHOGRAPHIC? mNearDist : farDist); 00559 Real nearx = x * mNearDist; 00560 Real farx = x * (mProjType == PT_ORTHOGRAPHIC? mNearDist : farDist); 00561 // near 00562 mWorldSpaceCorners[0] = eyeToWorld * Vector3( nearx, neary, -mNearDist); 00563 mWorldSpaceCorners[1] = eyeToWorld * Vector3(-nearx, neary, -mNearDist); 00564 mWorldSpaceCorners[2] = eyeToWorld * Vector3(-nearx, -neary, -mNearDist); 00565 mWorldSpaceCorners[3] = eyeToWorld * Vector3( nearx, -neary, -mNearDist); 00566 // far 00567 mWorldSpaceCorners[4] = eyeToWorld * Vector3( farx, fary, -farDist); 00568 mWorldSpaceCorners[5] = eyeToWorld * Vector3(-farx, fary, -farDist); 00569 mWorldSpaceCorners[6] = eyeToWorld * Vector3(-farx, -fary, -farDist); 00570 mWorldSpaceCorners[7] = eyeToWorld * Vector3( farx, -fary, -farDist); 00571 00572 // Deal with reflection on frustum planes 00573 if (mReflect) 00574 { 00575 Vector3 pos = mReflectMatrix * position; 00576 Vector3 dir = camDirection.reflect(mReflectPlane.normal); 00577 fDdE = dir.dotProduct(pos); 00578 unsigned int i; 00579 for (i = 0; i < 6; ++i) 00580 { 00581 mFrustumPlanes[i].normal = mFrustumPlanes[i].normal.reflect(mReflectPlane.normal); 00582 // Near / far plane dealt with differently since they don't pass through camera 00583 switch (i) 00584 { 00585 case FRUSTUM_PLANE_NEAR: 00586 mFrustumPlanes[i].d = -(fDdE + mNearDist); 00587 break; 00588 case FRUSTUM_PLANE_FAR: 00589 mFrustumPlanes[i].d = fDdE + mFarDist; 00590 break; 00591 default: 00592 mFrustumPlanes[i].d = -pos.dotProduct(mFrustumPlanes[i].normal); 00593 } 00594 } 00595 // Also reflect corners 00596 for (i = 0; i < 8; ++i) 00597 { 00598 mWorldSpaceCorners[i] = mReflectMatrix * mWorldSpaceCorners[i]; 00599 } 00600 } 00601 00602 mRecalcView = false; 00603 00604 } 00605 00606 } 00607 00608 //----------------------------------------------------------------------- 00609 Real Frustum::getAspectRatio(void) const 00610 { 00611 return mAspect; 00612 } 00613 00614 //----------------------------------------------------------------------- 00615 void Frustum::setAspectRatio(Real r) 00616 { 00617 mAspect = r; 00618 invalidateFrustum(); 00619 } 00620 00621 //----------------------------------------------------------------------- 00622 const AxisAlignedBox& Frustum::getBoundingBox(void) const 00623 { 00624 return mBoundingBox; 00625 } 00626 //----------------------------------------------------------------------- 00627 void Frustum::_updateRenderQueue(RenderQueue* queue) 00628 { 00629 // Add self 00630 queue->addRenderable(this); 00631 } 00632 //----------------------------------------------------------------------- 00633 const String& Frustum::getMovableType(void) const 00634 { 00635 return msMovableType; 00636 } 00637 //----------------------------------------------------------------------- 00638 Real Frustum::getBoundingRadius(void) const 00639 { 00640 return (mFarDist == 0)? 100000 : mFarDist; 00641 } 00642 //----------------------------------------------------------------------- 00643 Material* Frustum::getMaterial(void) const 00644 { 00645 return mMaterial; 00646 } 00647 //----------------------------------------------------------------------- 00648 void Frustum::getRenderOperation(RenderOperation& op) 00649 { 00650 updateView(); 00651 updateFrustum(); 00652 op.operationType = RenderOperation::OT_LINE_LIST; 00653 op.useIndexes = false; 00654 op.vertexData = &mVertexData; 00655 } 00656 //----------------------------------------------------------------------- 00657 void Frustum::getWorldTransforms(Matrix4* xform) const 00658 { 00659 if (mParentNode) 00660 mParentNode->getWorldTransforms(xform); 00661 } 00662 //----------------------------------------------------------------------- 00663 const Quaternion& Frustum::getWorldOrientation(void) const 00664 { 00665 if (mParentNode) 00666 return mParentNode->_getDerivedOrientation(); 00667 else 00668 return Quaternion::IDENTITY; 00669 } 00670 //----------------------------------------------------------------------- 00671 const Vector3& Frustum::getWorldPosition(void) const 00672 { 00673 if (mParentNode) 00674 return mParentNode->_getDerivedPosition(); 00675 else 00676 return Vector3::ZERO; 00677 } 00678 //----------------------------------------------------------------------- 00679 Real Frustum::getSquaredViewDepth(const Camera* cam) const 00680 { 00681 // Calc from centre 00682 if (mParentNode) 00683 return (cam->getDerivedPosition() 00684 - mParentNode->_getDerivedPosition()).squaredLength(); 00685 else 00686 return 0; 00687 } 00688 //----------------------------------------------------------------------- 00689 const LightList& Frustum::getLights(void) const 00690 { 00691 // N/A 00692 static LightList ll; 00693 return ll; 00694 } 00695 //----------------------------------------------------------------------- 00696 const String& Frustum::getName(void) const 00697 { 00698 // NA 00699 return msMovableType; 00700 } 00701 //----------------------------------------------------------------------- 00702 void Frustum::_notifyCurrentCamera(Camera* cam) 00703 { 00704 // NA 00705 } 00706 00707 // ------------------------------------------------------------------- 00708 void Frustum::invalidateFrustum() 00709 { 00710 mRecalcFrustum = true; 00711 } 00712 // ------------------------------------------------------------------- 00713 void Frustum::invalidateView() 00714 { 00715 mRecalcView = true; 00716 } 00717 // ------------------------------------------------------------------- 00718 const Vector3* Frustum::getWorldSpaceCorners(void) const 00719 { 00720 updateView(); 00721 00722 return mWorldSpaceCorners; 00723 } 00724 //----------------------------------------------------------------------- 00725 void Frustum::setProjectionType(ProjectionType pt) 00726 { 00727 mProjType = pt; 00728 invalidateFrustum(); 00729 } 00730 00731 //----------------------------------------------------------------------- 00732 ProjectionType Frustum::getProjectionType(void) const 00733 { 00734 return mProjType; 00735 } 00736 //----------------------------------------------------------------------- 00737 const Vector3& Frustum::getPositionForViewUpdate(void) const 00738 { 00739 return mLastParentPosition; 00740 } 00741 //----------------------------------------------------------------------- 00742 const Quaternion& Frustum::getOrientationForViewUpdate(void) const 00743 { 00744 return mLastParentOrientation; 00745 } 00746 //----------------------------------------------------------------------- 00747 void Frustum::enableReflection(const Plane& p) 00748 { 00749 mReflect = true; 00750 mReflectPlane = p; 00751 mReflectMatrix = Math::buildReflectionMatrix(p); 00752 invalidateView(); 00753 00754 } 00755 //----------------------------------------------------------------------- 00756 void Frustum::disableReflection(void) 00757 { 00758 mReflect = false; 00759 invalidateView(); 00760 } 00761 //--------------------------------------------------------------------- 00762 bool Frustum::projectSphere(const Sphere& sphere, 00763 Real* left, Real* top, Real* right, Real* bottom) const 00764 { 00765 // initialise 00766 *left = *bottom = -1.0f; 00767 *right = *top = 1.0f; 00768 00769 // Transform light position into camera space 00770 Vector3 eyeSpacePos = getViewMatrix() * sphere.getCenter(); 00771 00772 if (eyeSpacePos.z < 0) 00773 { 00774 Real r = sphere.getRadius(); 00775 // early-exit 00776 if (eyeSpacePos.squaredLength() <= r * r) 00777 return false; 00778 00779 Vector3 screenSpacePos = getStandardProjectionMatrix() * eyeSpacePos; 00780 00781 00782 // perspective attenuate 00783 Vector3 spheresize(r, r, eyeSpacePos.z); 00784 spheresize = getStandardProjectionMatrix() * spheresize; 00785 00786 Real possLeft = screenSpacePos.x - spheresize.x; 00787 Real possRight = screenSpacePos.x + spheresize.x; 00788 Real possTop = screenSpacePos.y + spheresize.y; 00789 Real possBottom = screenSpacePos.y - spheresize.y; 00790 00791 *left = std::max(-1.0f, possLeft); 00792 *right = std::min(1.0f, possRight); 00793 *top = std::min(1.0f, possTop); 00794 *bottom = std::max(-1.0f, possBottom); 00795 00796 } 00797 00798 return (*left != -1.0f) || (*top != 1.0f) || (*right != 1.0f) || (*bottom != -1.0f); 00799 00800 } 00801 00802 00803 00804 } // namespace Ogre
Copyright © 2002-2003 by The OGRE Team
Last modified Fri May 14 23:22:10 2004