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