Hi Robert, The attached files add the ability to control when a paged child becomes eligible for expiry based on time and/or elapsed frames.
I found that some of the items that had been paged in were being expired on the first frame that they were not visible (as the cache was full). This resulted in excessive paging every time the view was moved. With the following changes I could only allow children to be expired if they had not been used for e.g. 30 seconds or 60 frames. The changes were made against trunk revision 12822. Cheers, Brad ------------------------------------------------------------------------- DISCLAIMER: This e-mail transmission and any documents, files and previous e-mail messages attached to it are private and confidential. They may contain proprietary or copyright material or information that is subject to legal professional privilege. They are for the use of the intended recipient only. Any unauthorised viewing, use, disclosure, copying, alteration, storage or distribution of, or reliance on, this message is strictly prohibited. No part may be reproduced, adapted or transmitted without the written permission of the owner. If you have received this transmission in error, or are not an authorised recipient, please immediately notify the sender by return email, delete this message and all copies from your e-mail system, and destroy any printed copies. Receipt by anyone other than the intended recipient should not be deemed a waiver of any privilege or protection. Thales Australia does not warrant or represent that this e-mail or any documents, files and previous e-mail messages attached are error or virus free. -------------------------------------------------------------------------
PagedLOD
Description: PagedLOD
/* -*-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/PagedLOD>
#include <osg/CullStack>
#include <osg/Notify>
#include <algorithm>
using namespace osg;
PagedLOD::PerRangeData::PerRangeData():
_priorityOffset(0.0f),
_priorityScale(1.0f),
_minExpiryTime(0.0f),
_minExpiryFrames(0),
_timeStamp(0.0f),
_frameNumber(0),
_frameNumberOfLastReleaseGLObjects(0) {}
PagedLOD::PerRangeData::PerRangeData(const PerRangeData& prd):
_filename(prd._filename),
_priorityOffset(prd._priorityOffset),
_priorityScale(prd._priorityScale),
_minExpiryTime(prd._minExpiryTime),
_minExpiryFrames(prd._minExpiryFrames),
_timeStamp(prd._timeStamp),
_frameNumber(prd._frameNumber),
_frameNumberOfLastReleaseGLObjects(prd._frameNumberOfLastReleaseGLObjects),
_databaseRequest(prd._databaseRequest) {}
PagedLOD::PerRangeData& PagedLOD::PerRangeData::operator = (const PerRangeData&
prd)
{
if (this==&prd) return *this;
_filename = prd._filename;
_priorityOffset = prd._priorityOffset;
_priorityScale = prd._priorityScale;
_timeStamp = prd._timeStamp;
_frameNumber = prd._frameNumber;
_frameNumberOfLastReleaseGLObjects = prd._frameNumberOfLastReleaseGLObjects;
_databaseRequest = prd._databaseRequest;
_minExpiryTime = prd._minExpiryTime;
_minExpiryFrames = prd._minExpiryFrames;
return *this;
}
PagedLOD::PagedLOD()
{
_frameNumberOfLastTraversal = 0;
_centerMode = USER_DEFINED_CENTER;
_radius = -1;
_numChildrenThatCannotBeExpired = 0;
_disableExternalChildrenPaging = false;
}
PagedLOD::PagedLOD(const PagedLOD& plod,const CopyOp& copyop):
LOD(plod,copyop),
_databaseOptions(plod._databaseOptions),
_databasePath(plod._databasePath),
_frameNumberOfLastTraversal(plod._frameNumberOfLastTraversal),
_numChildrenThatCannotBeExpired(plod._numChildrenThatCannotBeExpired),
_disableExternalChildrenPaging(plod._disableExternalChildrenPaging),
_perRangeDataList(plod._perRangeDataList)
{
}
PagedLOD::~PagedLOD()
{
}
void PagedLOD::setDatabasePath(const std::string& path)
{
_databasePath = path;
if (!_databasePath.empty())
{
char& lastCharacter = _databasePath[_databasePath.size()-1];
const char unixSlash = '/';
const char winSlash = '\\';
if (lastCharacter==winSlash)
{
lastCharacter = unixSlash;
}
else if (lastCharacter!=unixSlash)
{
_databasePath += unixSlash;
}
/*
// make sure the last character is the appropriate slash
#ifdef WIN32
if (lastCharacter==unixSlash)
{
lastCharacter = winSlash;
}
else if (lastCharacter!=winSlash)
{
_databasePath += winSlash;
}
#else
if (lastCharacter==winSlash)
{
lastCharacter = unixSlash;
}
else if (lastCharacter!=unixSlash)
{
_databasePath += unixSlash;
}
#endif
*/
}
}
void PagedLOD::traverse(NodeVisitor& nv)
{
// set the frame number of the traversal so that external nodes can find
out how active this
// node is.
if (nv.getFrameStamp() &&
nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR)
{
setFrameNumberOfLastTraversal(nv.getFrameStamp()->getFrameNumber());
}
double timeStamp =
nv.getFrameStamp()?nv.getFrameStamp()->getReferenceTime():0.0;
unsigned int frameNumber =
nv.getFrameStamp()?nv.getFrameStamp()->getFrameNumber():0;
bool updateTimeStamp = nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR;
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()>0.0f)
{
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);
}
}
}
int lastChildTraversed = -1;
bool needToLoadChild = false;
for(unsigned int i=0;i<_rangeList.size();++i)
{
if (_rangeList[i].first<=required_range &&
required_range<_rangeList[i].second)
{
if (i<_children.size())
{
if (updateTimeStamp)
{
_perRangeDataList[i]._timeStamp=timeStamp;
_perRangeDataList[i]._frameNumber=frameNumber;
}
_children[i]->accept(nv);
lastChildTraversed = (int)i;
}
else
{
needToLoadChild = true;
}
}
}
if (needToLoadChild)
{
unsigned int numChildren = _children.size();
// select the last valid child.
if (numChildren>0 && ((int)numChildren-1)!=lastChildTraversed)
{
if (updateTimeStamp)
{
_perRangeDataList[numChildren-1]._timeStamp=timeStamp;
_perRangeDataList[numChildren-1]._frameNumber=frameNumber;
}
_children[numChildren-1]->accept(nv);
}
// now request the loading of the next unloaded child.
if (!_disableExternalChildrenPaging &&
nv.getDatabaseRequestHandler() &&
numChildren<_perRangeDataList.size())
{
// compute priority from where abouts in the required range
the distance falls.
float priority =
(_rangeList[numChildren].second-required_range)/(_rangeList[numChildren].second-_rangeList[numChildren].first);
// invert priority for PIXEL_SIZE_ON_SCREEN mode
if(_rangeMode==PIXEL_SIZE_ON_SCREEN)
{
priority = -priority;
}
// modify the priority according to the child's priority
offset and scale.
priority = _perRangeDataList[numChildren]._priorityOffset +
priority * _perRangeDataList[numChildren]._priorityScale;
if (_databasePath.empty())
{
nv.getDatabaseRequestHandler()->requestNodeFile(_perRangeDataList[numChildren]._filename,nv.getNodePath(),priority,nv.getFrameStamp(),
_perRangeDataList[numChildren]._databaseRequest, _databaseOptions.get());
}
else
{
// prepend the databasePath to the child's filename.
nv.getDatabaseRequestHandler()->requestNodeFile(_databasePath+_perRangeDataList[numChildren]._filename,nv.getNodePath(),priority,nv.getFrameStamp(),
_perRangeDataList[numChildren]._databaseRequest, _databaseOptions.get());
}
}
}
break;
}
default:
break;
}
}
void PagedLOD::expandPerRangeDataTo(unsigned int pos)
{
if (pos>=_perRangeDataList.size()) _perRangeDataList.resize(pos+1);
}
bool PagedLOD::addChild( Node *child )
{
if (LOD::addChild(child))
{
expandPerRangeDataTo(_children.size()-1);
return true;
}
return false;
}
bool PagedLOD::addChild(Node *child, float min, float max)
{
if (LOD::addChild(child,min,max))
{
expandPerRangeDataTo(_children.size()-1);
return true;
}
return false;
}
bool PagedLOD::addChild(Node *child, float min, float max,const std::string&
filename, float priorityOffset, float priorityScale)
{
if (LOD::addChild(child,min,max))
{
setFileName(_children.size()-1,filename);
setPriorityOffset(_children.size()-1,priorityOffset);
setPriorityScale(_children.size()-1,priorityScale);
return true;
}
return false;
}
bool PagedLOD::removeChildren( unsigned int pos,unsigned int
numChildrenToRemove)
{
if (pos<_rangeList.size()) _rangeList.erase(_rangeList.begin()+pos,
osg::minimum(_rangeList.begin()+(pos+numChildrenToRemove), _rangeList.end()) );
if (pos<_perRangeDataList.size())
_perRangeDataList.erase(_perRangeDataList.begin()+pos,
osg::minimum(_perRangeDataList.begin()+ (pos+numChildrenToRemove),
_perRangeDataList.end()) );
return Group::removeChildren(pos,numChildrenToRemove);
}
bool PagedLOD::removeExpiredChildren(double expiryTime, unsigned int
expiryFrame, NodeList& removedChildren)
{
if (_children.size()>_numChildrenThatCannotBeExpired)
{
unsigned cindex = _children.size() - 1;
if (!_perRangeDataList[cindex]._filename.empty() &&
_perRangeDataList[cindex]._timeStamp +
_perRangeDataList[cindex]._minExpiryTime < expiryTime &&
_perRangeDataList[cindex]._frameNumber +
_perRangeDataList[cindex]._minExpiryFrames < expiryFrame)
{
osg::Node* nodeToRemove = _children[cindex].get();
removedChildren.push_back(nodeToRemove);
return Group::removeChildren(cindex,1);
}
}
return false;
}
_______________________________________________ osg-submissions mailing list [email protected] http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
