Files
OpenSceneGraph/src/osg/LOD.cpp
Robert Osfield 8a230d42ed From Luc Frauciel, "You'll find attached a new option that allow, when using LOD in USER_DEFINED_CENTER mode to expand the radius of the node by the radius of loaded objets.
Motivation ;
When using PagedLODs, you don't always know the real size of loaded children,
If it occurs that they  are out of predefined bounds, picking on the parts that are out of bound will fail
They also can be culled out too soon.
The problem often  occurs with long object (roads).
I've modified LOD and ProxyNode to include this option."

and later email:

"Attached the UNION_OF_BOUNDING_SPHERE_AND_USER_DEFINED version
There are impacts on some serializers (dae, osgWrapper).
I haven't modified deprecated osg, since it's deprecated"
2011-09-19 10:34:31 +00:00

150 lines
4.5 KiB
C++

/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#include <osg/LOD>
#include <osg/CullStack>
#include <algorithm>
using namespace osg;
LOD::LOD():
_centerMode(USE_BOUNDING_SPHERE_CENTER),
_radius(-1.0f),
_rangeMode(DISTANCE_FROM_EYE_POINT)
{
}
LOD::LOD(const LOD& lod,const CopyOp& copyop):
Group(lod,copyop),
_centerMode(lod._centerMode),
_userDefinedCenter(lod._userDefinedCenter),
_radius(lod._radius),
_rangeMode(lod._rangeMode),
_rangeList(lod._rangeList)
{
}
void LOD::traverse(NodeVisitor& nv)
{
switch(nv.getTraversalMode())
{
case(NodeVisitor::TRAVERSE_ALL_CHILDREN):
std::for_each(_children.begin(),_children.end(),NodeAcceptOp(nv));
break;
case(NodeVisitor::TRAVERSE_ACTIVE_CHILDREN):
{
float required_range = 0;
if (_rangeMode==DISTANCE_FROM_EYE_POINT)
{
required_range = nv.getDistanceToViewPoint(getCenter(),true);
}
else
{
osg::CullStack* cullStack = dynamic_cast<osg::CullStack*>(&nv);
if (cullStack && cullStack->getLODScale())
{
required_range = cullStack->clampedPixelSize(getBound()) / cullStack->getLODScale();
}
else
{
// fallback to selecting the highest res tile by
// finding out the max range
for(unsigned int i=0;i<_rangeList.size();++i)
{
required_range = osg::maximum(required_range,_rangeList[i].first);
}
}
}
unsigned int numChildren = _children.size();
if (_rangeList.size()<numChildren) numChildren=_rangeList.size();
for(unsigned int i=0;i<numChildren;++i)
{
if (_rangeList[i].first<=required_range && required_range<_rangeList[i].second)
{
_children[i]->accept(nv);
}
}
break;
}
default:
break;
}
}
BoundingSphere LOD::computeBound() const
{
if (_centerMode==USER_DEFINED_CENTER && _radius>=0.0f)
{
return BoundingSphere(_userDefinedCenter,_radius);
}
else if (_centerMode==UNION_OF_BOUNDING_SPHERE_AND_USER_DEFINED && _radius>=0.0f)
{
BoundingSphere bs = BoundingSphere(_userDefinedCenter,_radius);
bs.expandBy(Group::computeBound());
//alternative (used in TxpPagedLOD)
// bs.expandRadiusBy(Group::computeBound());
return bs;
}
else
{
return Group::computeBound();
}
}
bool LOD::addChild( Node *child )
{
if (Group::addChild(child))
{
if (_children.size()>_rangeList.size())
{
float maxRange = !_rangeList.empty() ? _rangeList.back().second : 0.0f;
_rangeList.resize(_children.size(),MinMaxPair(maxRange,maxRange));
}
return true;
}
return false;
}
bool LOD::addChild(Node *child, float min, float max)
{
if (Group::addChild(child))
{
if (_children.size()>_rangeList.size()) _rangeList.resize(_children.size(),MinMaxPair(min,min));
_rangeList[_children.size()-1].first = min;
_rangeList[_children.size()-1].second = max;
return true;
}
return false;
}
bool LOD::removeChildren( unsigned int pos,unsigned int numChildrenToRemove)
{
if (pos<_rangeList.size()) _rangeList.erase(_rangeList.begin()+pos, osg::minimum(_rangeList.begin()+(pos+numChildrenToRemove), _rangeList.end()) );
return Group::removeChildren(pos,numChildrenToRemove);
}
void LOD::setRange(unsigned int childNo, float min,float max)
{
if (childNo>=_rangeList.size()) _rangeList.resize(childNo+1,MinMaxPair(min,min));
_rangeList[childNo].first=min;
_rangeList[childNo].second=max;
}