1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2014 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 29 #include "OgreStableHeaders.h" 30 #include "OgreDistanceLodStrategy.h" 31 #include "OgreViewport.h" 32 33 #include <limits> 34 35 namespace Ogre { DistanceLodStrategyBase(const String & name)36 DistanceLodStrategyBase::DistanceLodStrategyBase(const String& name) 37 : LodStrategy(name) 38 , mReferenceViewEnabled(false) 39 , mReferenceViewValue(-1) 40 { } 41 //----------------------------------------------------------------------- getValueImpl(const MovableObject * movableObject,const Ogre::Camera * camera) const42 Real DistanceLodStrategyBase::getValueImpl(const MovableObject *movableObject, const Ogre::Camera *camera) const 43 { 44 Real squaredDepth = getSquaredDepth(movableObject, camera); 45 46 // Check if reference view needs to be taken into account 47 if (mReferenceViewEnabled) 48 { 49 // Reference view only applicable to perspective projection 50 assert(camera->getProjectionType() == PT_PERSPECTIVE && "Camera projection type must be perspective!"); 51 52 // Get camera viewport 53 Viewport *viewport = camera->getViewport(); 54 55 // Get viewport area 56 Real viewportArea = static_cast<Real>(viewport->getActualWidth() * viewport->getActualHeight()); 57 58 // Get projection matrix (this is done to avoid computation of tan(FOV / 2)) 59 const Matrix4& projectionMatrix = camera->getProjectionMatrix(); 60 61 // Compute bias value (note that this is similar to the method used for PixelCountLodStrategy) 62 Real biasValue = viewportArea * projectionMatrix[0][0] * projectionMatrix[1][1]; 63 64 // Scale squared depth appropriately 65 squaredDepth *= (mReferenceViewValue / biasValue); 66 } 67 68 // Squared depth should never be below 0, so clamp 69 squaredDepth = std::max(squaredDepth, Real(0)); 70 71 // Now adjust it by the camera bias and return the computed value 72 return squaredDepth * camera->_getLodBiasInverse(); 73 } 74 //----------------------------------------------------------------------- getBaseValue() const75 Real DistanceLodStrategyBase::getBaseValue() const 76 { 77 return Real(0); 78 } 79 //--------------------------------------------------------------------- transformBias(Real factor) const80 Real DistanceLodStrategyBase::transformBias(Real factor) const 81 { 82 assert(factor > 0.0f && "Bias factor must be > 0!"); 83 return 1.0f / factor; 84 } 85 //----------------------------------------------------------------------- transformUserValue(Real userValue) const86 Real DistanceLodStrategyBase::transformUserValue(Real userValue) const 87 { 88 // Square user-supplied distance 89 return Math::Sqr(userValue); 90 } 91 //----------------------------------------------------------------------- getIndex(Real value,const Mesh::MeshLodUsageList & meshLodUsageList) const92 ushort DistanceLodStrategyBase::getIndex(Real value, const Mesh::MeshLodUsageList& meshLodUsageList) const 93 { 94 // Get index assuming ascending values 95 return getIndexAscending(value, meshLodUsageList); 96 } 97 //----------------------------------------------------------------------- getIndex(Real value,const Material::LodValueList & materialLodValueList) const98 ushort DistanceLodStrategyBase::getIndex(Real value, const Material::LodValueList& materialLodValueList) const 99 { 100 // Get index assuming ascending values 101 return getIndexAscending(value, materialLodValueList); 102 } 103 //--------------------------------------------------------------------- isSorted(const Mesh::LodValueList & values) const104 bool DistanceLodStrategyBase::isSorted(const Mesh::LodValueList& values) const 105 { 106 // Determine if sorted ascending 107 return isSortedAscending(values); 108 } 109 //--------------------------------------------------------------------- sort(Mesh::MeshLodUsageList & meshLodUsageList) const110 void DistanceLodStrategyBase::sort(Mesh::MeshLodUsageList& meshLodUsageList) const 111 { 112 // Sort ascending 113 return sortAscending(meshLodUsageList); 114 } 115 //--------------------------------------------------------------------- setReferenceView(Real viewportWidth,Real viewportHeight,Radian fovY)116 void DistanceLodStrategyBase::setReferenceView(Real viewportWidth, Real viewportHeight, Radian fovY) 117 { 118 // Determine x FOV based on aspect ratio 119 Radian fovX = fovY * (viewportWidth / viewportHeight); 120 121 // Determine viewport area 122 Real viewportArea = viewportHeight * viewportWidth; 123 124 // Compute reference view value based on viewport area and FOVs 125 mReferenceViewValue = viewportArea * Math::Tan(fovX * 0.5f) * Math::Tan(fovY * 0.5f); 126 127 // Enable use of reference view 128 mReferenceViewEnabled = true; 129 } 130 //--------------------------------------------------------------------- setReferenceViewEnabled(bool value)131 void DistanceLodStrategyBase::setReferenceViewEnabled(bool value) 132 { 133 // Ensure reference value has been set before being enabled 134 if (value) 135 assert(mReferenceViewValue != -1 && "Reference view must be set before being enabled!"); 136 137 mReferenceViewEnabled = value; 138 } 139 //--------------------------------------------------------------------- isReferenceViewEnabled() const140 bool DistanceLodStrategyBase::isReferenceViewEnabled() const 141 { 142 return mReferenceViewEnabled; 143 } 144 145 /************************************************************************/ 146 /* */ 147 /************************************************************************/ 148 149 //----------------------------------------------------------------------- 150 template<> DistanceLodSphereStrategy* Singleton<DistanceLodSphereStrategy>::msSingleton = 0; getSingletonPtr(void)151 DistanceLodSphereStrategy* DistanceLodSphereStrategy::getSingletonPtr(void) 152 { 153 return msSingleton; 154 } getSingleton(void)155 DistanceLodSphereStrategy& DistanceLodSphereStrategy::getSingleton(void) 156 { 157 assert( msSingleton ); return ( *msSingleton ); 158 } 159 //----------------------------------------------------------------------- DistanceLodSphereStrategy()160 DistanceLodSphereStrategy::DistanceLodSphereStrategy() 161 : DistanceLodStrategyBase("distance_sphere") 162 { } 163 //----------------------------------------------------------------------- getSquaredDepth(const MovableObject * movableObject,const Ogre::Camera * camera) const164 Real DistanceLodSphereStrategy::getSquaredDepth(const MovableObject *movableObject, const Ogre::Camera *camera) const 165 { 166 // Get squared depth taking into account bounding radius 167 // (d - r) ^ 2 = d^2 - 2dr + r^2, but this requires a lot 168 // more computation (including a sqrt) so we approximate 169 // it with d^2 - r^2, which is good enough for determining 170 // LOD. 171 172 const Vector3& scl = movableObject->getParentNode()->_getDerivedScale(); 173 Real factor = std::max(std::max(scl.x, scl.y), scl.z); 174 return movableObject->getParentNode()->getSquaredViewDepth(camera) - Math::Sqr(movableObject->getBoundingRadius() * factor); 175 } 176 //----------------------------------------------------------------------- 177 178 /************************************************************************/ 179 /* */ 180 /************************************************************************/ 181 182 //----------------------------------------------------------------------- 183 template<> DistanceLodBoxStrategy* Singleton<DistanceLodBoxStrategy>::msSingleton = 0; getSingletonPtr(void)184 DistanceLodBoxStrategy* DistanceLodBoxStrategy::getSingletonPtr(void) 185 { 186 return msSingleton; 187 } getSingleton(void)188 DistanceLodBoxStrategy& DistanceLodBoxStrategy::getSingleton(void) 189 { 190 assert( msSingleton ); return ( *msSingleton ); 191 } 192 //----------------------------------------------------------------------- DistanceLodBoxStrategy()193 DistanceLodBoxStrategy::DistanceLodBoxStrategy() 194 : DistanceLodStrategyBase("distance_box") 195 { } 196 //----------------------------------------------------------------------- getSquaredDepth(const MovableObject * movableObject,const Ogre::Camera * camera) const197 Real DistanceLodBoxStrategy::getSquaredDepth(const MovableObject *movableObject, const Ogre::Camera *camera) const 198 { 199 return movableObject->getWorldBoundingBox().squaredDistance(camera->getDerivedPosition()); 200 } 201 //----------------------------------------------------------------------- 202 203 } // namespace 204