Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreFrustum.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://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