@ -40,9 +40,9 @@ namespace
return 1 < < depth ;
}
int Log2 ( unsigned int n )
unsigned int Log2 ( unsigned int n )
{
int targetlevel = 0 ;
unsigned int targetlevel = 0 ;
while ( n > > = 1 ) + + targetlevel ;
return targetlevel ;
}
@ -78,16 +78,18 @@ public:
if ( intersects )
return Deeper ;
}
dist = std : : max ( 0.f , dist + mDistanceModifier ) ;
if ( dist > mViewDistance & & ! activeGrid ) // for Scene<->ObjectPaging sync the activegrid must remain loaded
return StopTraversal ;
int nativeLodLevel = Log2 ( static_cast < unsigned int > ( node - > getSize ( ) / mMinSize ) ) ;
int lodLevel = Log2 ( static_cast < unsigned int > ( dist / ( Constants : : CellSizeInUnits * mMinSize * mFactor ) ) ) ;
return nativeLodLevel < = lodLevel ? StopTraversalAndUse : Deeper ;
return getNativeLodLevel ( node , mMinSize ) < = convertDistanceToLodLevel ( dist , mMinSize , mFactor ) ? StopTraversalAndUse : Deeper ;
}
static unsigned int getNativeLodLevel ( const QuadTreeNode * node , float minSize )
{
return Log2 ( static_cast < unsigned int > ( node - > getSize ( ) / minSize ) ) ;
}
static unsigned int convertDistanceToLodLevel ( float dist , float minSize , float factor )
{
return Log2 ( static_cast < unsigned int > ( dist / ( Constants : : CellSizeInUnits * minSize * factor ) ) ) ;
}
private :
@ -278,7 +280,6 @@ QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resour
, mViewDistance ( std : : numeric_limits < float > : : max ( ) )
, mMinSize ( 1 / 8.f )
, mDebugTerrainChunks ( debugChunks )
, mRevalidateDistance ( 0.f )
{
mChunkManager - > setCompositeMapSize ( compMapResolution ) ;
mChunkManager - > setCompositeMapLevel ( compMapLevel ) ;
@ -296,13 +297,14 @@ QuadTreeWorld::~QuadTreeWorld()
{
}
/// get the level of vertex detail to render this node at, expressed relative to the native resolution of the data set.
/// get the level of vertex detail to render this node at, expressed relative to the native resolution of the vertex data set,
/// NOT relative to mMinSize as is the case with node LODs.
unsigned int getVertexLod ( QuadTreeNode * node , int vertexLodMod )
{
int lod = Log2 ( int ( node - > getSize ( ) ) ) ;
unsigned int vertexLod = DefaultLodCallback : : getNativeLodLevel ( node , 1 ) ;
if ( vertexLodMod > 0 )
{
lod = std : : max ( 0 , lod - vertexLodMod ) ;
vertexLod = static_cast < unsigned int > ( std : : max ( 0 , static_cast < int > ( vertexLod ) - vertexLodMod ) ) ;
}
else if ( vertexLodMod < 0 )
{
@ -313,13 +315,13 @@ unsigned int getVertexLod(QuadTreeNode* node, int vertexLodMod)
size * = 2 ;
vertexLodMod = std : : min ( 0 , vertexLodMod + 1 ) ;
}
l od + = std : : abs ( vertexLodMod ) ;
vertexL od + = std : : abs ( vertexLodMod ) ;
}
return l od;
return vertexL od;
}
/// get the flags to use for stitching in the index buffer so that chunks of different LOD connect seamlessly
unsigned int getLodFlags ( QuadTreeNode * node , int our Lod, int vertexLodMod , const ViewData * vd )
unsigned int getLodFlags ( QuadTreeNode * node , unsigned int our Vertex Lod, int vertexLodMod , const ViewData * vd )
{
unsigned int lodFlags = 0 ;
for ( unsigned int i = 0 ; i < 4 ; + + i )
@ -332,40 +334,38 @@ unsigned int getLodFlags(QuadTreeNode* node, int ourLod, int vertexLodMod, const
// our detail and the neighbour would handle stitching by itself.
while ( neighbour & & ! vd - > contains ( neighbour ) )
neighbour = neighbour - > getParent ( ) ;
int lod = 0 ;
unsigned int lod = 0 ;
if ( neighbour )
lod = getVertexLod ( neighbour , vertexLodMod ) ;
if ( lod < = our Lod) // We only need to worry about neighbours less detailed than we are -
if ( lod < = our Vertex Lod) // We only need to worry about neighbours less detailed than we are -
lod = 0 ; // neighbours with more detail will do the stitching themselves
// Use 4 bits for each LOD delta
if ( lod > 0 )
{
lodFlags | = static_cast < unsigned int > ( lod - our Lod) < < ( 4 * i ) ;
lodFlags | = ( lod - our Vertex Lod) < < ( 4 * i ) ;
}
}
// Use the remaining bits for our vertex LOD
lodFlags | = ( ourVertexLod < < ( 4 * 4 ) ) ;
return lodFlags ;
}
void QuadTreeWorld : : loadRenderingNode ( ViewDataEntry & entry , ViewData * vd , float cellWorldSize , const osg : : Vec4i & gridbounds , bool compile , float reuseDistance )
void QuadTreeWorld : : loadRenderingNode ( ViewDataEntry & entry , ViewData * vd , float cellWorldSize , const osg : : Vec4i & gridbounds , bool compile )
{
if ( ! vd - > hasChanged ( ) & & entry . mRenderingNode )
return ;
int ourLod = getVertexLod ( entry . mNode , mVertexLodMod ) ;
if ( vd - > hasChanged ( ) )
{
unsigned int ourVertexLod = getVertexLod ( entry . mNode , mVertexLodMod ) ;
// have to recompute the lodFlags in case a neighbour has changed LOD.
unsigned int lodFlags = getLodFlags ( entry . mNode , our Lod, mVertexLodMod , vd ) ;
unsigned int lodFlags = getLodFlags ( entry . mNode , our Vertex Lod, mVertexLodMod , vd ) ;
if ( lodFlags ! = entry . mLodFlags )
{
entry . mRenderingNode = nullptr ;
entry . mLodFlags = lodFlags ;
}
// have to revalidate chunks within a custom view distance.
if ( mRevalidateDistance & & entry . mNode - > distance ( vd - > getViewPoint ( ) ) < = mRevalidateDistance + reuseDistance )
entry . mRenderingNode = nullptr ;
}
if ( ! entry . mRenderingNode )
@ -378,9 +378,7 @@ void QuadTreeWorld::loadRenderingNode(ViewDataEntry& entry, ViewData* vd, float
for ( QuadTreeWorld : : ChunkManager * m : mChunkManagers )
{
if ( mRevalidateDistance & & m - > getViewDistance ( ) & & entry . mNode - > distance ( vd - > getViewPoint ( ) ) > m - > getViewDistance ( ) + reuseDistance )
continue ;
osg : : ref_ptr < osg : : Node > n = m - > getChunk ( entry . mNode - > getSize ( ) , entry . mNode - > getCenter ( ) , ourLod , entry . mLodFlags , activeGrid , vd - > getViewPoint ( ) , compile ) ;
osg : : ref_ptr < osg : : Node > n = m - > getChunk ( entry . mNode - > getSize ( ) , entry . mNode - > getCenter ( ) , DefaultLodCallback : : getNativeLodLevel ( entry . mNode , mMinSize ) , entry . mLodFlags , activeGrid , vd - > getViewPoint ( ) , compile ) ;
if ( n ) pat - > addChild ( n ) ;
}
entry . mRenderingNode = pat ;
@ -462,7 +460,7 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv)
for ( unsigned int i = 0 ; i < vd - > getNumEntries ( ) ; + + i )
{
ViewDataEntry & entry = vd - > getEntry ( i ) ;
loadRenderingNode ( entry , vd , cellWorldSize , mActiveGrid , false , mViewDataMap - > getReuseDistance ( ) );
loadRenderingNode ( entry , vd , cellWorldSize , mActiveGrid , false );
entry . mRenderingNode - > accept ( nv ) ;
}
@ -541,12 +539,11 @@ void QuadTreeWorld::preload(View *view, const osg::Vec3f &viewPoint, const osg::
reporter . addTotal ( progressTotal ) ;
}
const float reuseDistance = std : : max ( mViewDataMap - > getReuseDistance ( ) , std : : abs ( distanceModifier ) ) ;
for ( unsigned int i = startEntry ; i < vd - > getNumEntries ( ) & & ! abort ; + + i )
{
ViewDataEntry & entry = vd - > getEntry ( i ) ;
loadRenderingNode ( entry , vd , cellWorldSize , grid , true , reuseDistance );
loadRenderingNode ( entry , vd , cellWorldSize , grid , true );
if ( pass = = 0 ) reporter . addProgress ( entry . mNode - > getSize ( ) ) ;
entry . mNode = nullptr ; // Clear node lest we break the neighbours search for the next pass
}
@ -584,7 +581,7 @@ void QuadTreeWorld::addChunkManager(QuadTreeWorld::ChunkManager* m)
mChunkManagers . push_back ( m ) ;
mTerrainRoot - > setNodeMask ( mTerrainRoot - > getNodeMask ( ) | m - > getNodeMask ( ) ) ;
if ( m - > getViewDistance ( ) )
m RevalidateDistance = std : : max ( m - > getViewDistance ( ) , mRevalidateDistance ) ;
m - > setMaxLodLevel ( DefaultLodCallback : : convertDistanceToLodLevel ( m - > getViewDistance ( ) + mViewDataMap - > getReuseDistance ( ) , mMinSize , mLodFactor ) ) ;
}
void QuadTreeWorld : : rebuildViews ( )