History: ScreenRatioLodStrategy
Source of version: 1 (current)
Copy to clipboard
!Screen Ratio LOD Strategy
ScreenRatioLodStrategy works by analyzing how much portion of screen a model occupies on screen on any given instance of time, and selects a LOD mesh/material accordingly. ScreenRatioLodStrategy is inspired by PixelCountLodStrategy.
!Status
*ScreenRatioLodStrategy is slight modification of PixelCountLodStrategy.
*Currently it is not included in Ogre SDK
!Inspiration
I feel ScreenRatioLodStrategy does a little more justice to varying screen resolutions these days.
Say, I specify a PixelCountLodStrategy mesh with 50% complexity reduction below 500*500 pixel area. Now this might work very well on my 1080p monitor, but when I view the same model on a 1024*800 netbook screen or projector, model will switch to level 1 a little too soon.
ScreenRatioLodStrategy on the other hand specifies the __Ratio__ below which lod will be reduced. We spacify lod values as 0.2(=20%), 0.1(=10%) and so on. So when a model takes below 20% of total screen area, it will switch to level 1. This is total independent of whether I am running a 800*600 projector or a 1080p monitor.
!ScreenRatioLodStrategy VS PixelCountLodStrategy
#ScreenRatioLodStrategy is inspired by PixelCountLodStrategy, but provide simpler and better control over LOD meshes.
#Where PixelCountLodStrategy specifies LOD meshes when they occupy __certain number pixels__ on screen (eg 500*500pixels, 200*200), ScreenRatioLodStrategy specifies LOD meshes when they occupy certain percent of total screen area (50% of screen, 20% of screen)
#Easier to specify lod values while defining LOD meshes
!ScreenRatioLodStrategy Values
''NOTE: values need testing''
LOD values are specified as ratio, that is, area occupied by a model of total screen area. However please note that the values are approximations and generally higher than actual area. For example
*LOD Value > 1.0 = majority of screen space (~50%)
*LOD Value > 0.5 = significant amount of screen space (~25%)
*LOD Value > 0.2 = small amount of screen space (~5%)
*''and so on''
!!How To Programatically Prepare A Mesh For ScreenRatioLodStrategy ?
''NOTE: code needs testing''
For ScreenRatioLodStrategy , mesh lod values are stored in decreasing orger, starting with MAX_FLOAT value. Here is what you have to do
{CODE(wrap="1", colors="c++")}
// define base mesh
MeshPtr mesh = MeshManager::getSingleton().load("something-100p.mesh"); // level 0, 100 percent
// add LOD strategy
mesh->setLodStrategy(new Ogre::ScreenRatioLodStrategy()); // might need to reapply after load
// add level 1 mesh
mesh->createManualLodLevel(0.5, "something-50p.mesh"); // level 1, 50 percent
// add level 2 mesh, for pixel area below 200*200
mesh->createManualLodLevel(0.2, "something-25p.mesh"); // level 2, 25 percent
// export LODed mesh
MeshSerializer ser;
ser.exportMesh(mesh1.get(), "something-with-lod.mesh");
{CODE}
!!How to use LODed mesh
''NOTE: code needs testing''
{CODE(wrap="1", colors="c++")}
Entity* enty = sceneManager->createEntity("MyLodMesh", "something-with-lod.mesh");
enty->setLodStrategy(new Ogre::ScreenRatioLodStrategy()); // optional
{CODE}
!Help Needed
*Currently it does not implement Singleton interface, if someone can do it
*I could not decide if I need to do something in __transformBias__ function
!CODE
!!.H
{CODE(wrap="0", colors="c++")}
#ifndef __Screen_Ratio_Lod_Strategy_H__
#define __Screen_Ratio_Lod_Strategy_H__
#include "Ogre.h"
#include "OgreLodStrategy.h"
using namespace Ogre;
// TODO add singleton interface
class SUBMERGE_API ScreenRatioLodStrategy : public LodStrategy
{
protected:
virtual Real getValueImpl(const MovableObject *movableObject, const Camera *camera) const;
public:
ScreenRatioLodStrategy();
virtual Real getBaseValue() const;
virtual Real transformBias(Real factor) const;
virtual ushort getIndex(Real value, const Mesh::MeshLodUsageList& meshLodUsageList) const;
virtual ushort getIndex(Real value, const Material::LodValueList& materialLodValueList) const;
virtual void sort(Mesh::MeshLodUsageList& meshLodUsageList) const;
virtual bool isSorted(const Mesh::LodValueList& values) const;
};
#endif
{CODE}
!!.CPP
{CODE(wrap="0", colors="c++")}
#include "ScreenRatioLodStrategy.h"
ScreenRatioLodStrategy::ScreenRatioLodStrategy()
: LodStrategy("ScreenRatio")
{ }
Real ScreenRatioLodStrategy::getValueImpl(const MovableObject *movableObject, const Ogre::Camera *camera) const
{
// Get area of unprojected circle with object bounding radius
Real boundingArea = Math::PI * Math::Sqr(movableObject->getBoundingRadius());
// Base computation on projection type
switch (camera->getProjectionType())
{
case PT_PERSPECTIVE:
{
// Get camera distance
Real distanceSquared = movableObject->getParentNode()->getSquaredViewDepth(camera);
// Check for 0 distance
if (distanceSquared <= std::numeric_limits<Real>::epsilon())
return getBaseValue();
// Get projection matrix (this is done to avoid computation of tan(fov / 2))
const Matrix4& projectionMatrix = camera->getProjectionMatrix();
// Estimate pixel ratio
return (boundingArea * projectionMatrix[0][0] * projectionMatrix[1][1]) / distanceSquared;
}
case PT_ORTHOGRAPHIC:
{
// Compute orthographic area
Real orthoArea = camera->getOrthoWindowHeight() * camera->getOrthoWindowWidth();
// Check for 0 orthographic area
if (orthoArea <= std::numeric_limits<Real>::epsilon())
return getBaseValue();
// Estimate pixel ratio
return boundingArea / orthoArea;
}
default:
{
// This case is not covered for obvious reasons
throw;
}
}
}
//---------------------------------------------------------------------
Real ScreenRatioLodStrategy::getBaseValue() const
{
// Use the maximum possible value as base
return std::numeric_limits<Real>::max();
}
//---------------------------------------------------------------------
Real ScreenRatioLodStrategy::transformBias(Real factor) const
{
// No transformation required for pixel ratio strategy
return factor;
}
//---------------------------------------------------------------------
ushort ScreenRatioLodStrategy::getIndex(Real value, const Mesh::MeshLodUsageList& meshLodUsageList) const
{
// Values are descending
return getIndexDescending(value, meshLodUsageList);
}
//---------------------------------------------------------------------
ushort ScreenRatioLodStrategy::getIndex(Real value, const Material::LodValueList& materialLodValueList) const
{
// Values are descending
return getIndexDescending(value, materialLodValueList);
}
//---------------------------------------------------------------------
void ScreenRatioLodStrategy::sort(Mesh::MeshLodUsageList& meshLodUsageList) const
{
// Sort descending
sortDescending(meshLodUsageList);
}
//---------------------------------------------------------------------
bool ScreenRatioLodStrategy::isSorted(const Mesh::LodValueList& values) const
{
// Check if values are sorted descending
return isSortedDescending(values);
}
{CODE}
!References
http://www.ogre3d.org/tikiwiki/PixelCountLodStrategy