Skip to content

Commit

Permalink
Allow per-node add/replace strategy
Browse files Browse the repository at this point in the history
Previously the whole chunked entity had one strategy, now it is possible
that each node has a different strategy - as 3D tiles allow.
  • Loading branch information
wonder-sk authored and nyalldawson committed Aug 31, 2023
1 parent e81f334 commit b0c0e6c
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 25 deletions.
4 changes: 2 additions & 2 deletions src/3d/chunks/qgschunkedentity_p.cpp
Expand Up @@ -492,7 +492,7 @@ void QgsChunkedEntity::update( QgsChunkNode *root, const SceneState &state )
// has additive strategy. With additive strategy, child nodes should be rendered
// in addition to the parent nodes (rather than child nodes replacing parent entirely)

if ( mAdditiveStrategy )
if ( node->refinementProcess() == Qgis::TileRefinementProcess::Additive )
{
// Logic of the additive strategy:
// - children that are not loaded will get requested to be loaded
Expand Down Expand Up @@ -547,7 +547,7 @@ void QgsChunkedEntity::update( QgsChunkNode *root, const SceneState &state )
{
mActiveNodes << node;
// if we are not using additive strategy we need to make sure the parent primitives are not counted
if ( !mAdditiveStrategy && node->parent() && nodes.contains( node->parent() ) )
if ( node->refinementProcess() != Qgis::TileRefinementProcess::Additive && node->parent() && nodes.contains( node->parent() ) )
{
nodes.remove( node->parent() );
renderedCount -= mChunkLoaderFactory->primitivesCount( node->parent() );
Expand Down
16 changes: 0 additions & 16 deletions src/3d/chunks/qgschunkedentity_p.h
Expand Up @@ -93,16 +93,6 @@ class QgsChunkedEntity : public Qgs3DMapSceneEntity
//! Returns the root node of the whole quadtree hierarchy of nodes
QgsChunkNode *rootNode() const { return mRootNode; }

//! Sets whether additive strategy is enabled - see usingAditiveStrategy()
void setUsingAdditiveStrategy( bool additive ) { mAdditiveStrategy = additive; }

/**
* Returns whether additive strategy is enabled.
* With additive strategy enabled, also all parent nodes are added to active nodes.
* This is desired when child nodes add more detailed data rather than just replace coarser data in parents.
*/
bool usingAditiveStrategy() const { return mAdditiveStrategy; }

/**
* Sets the limit of the GPU memory used to render the entity
* \since QGIS 3.26
Expand Down Expand Up @@ -189,12 +179,6 @@ class QgsChunkedEntity : public Qgs3DMapSceneEntity
//! jobs that are currently being processed (asynchronously in worker threads)
QList<QgsChunkQueueJob *> mActiveJobs;

/**
* With additive strategy enabled, also all parent nodes are added to active nodes.
* This is desired when child nodes add more detailed data rather than just replace coarser data in parents.
*/
bool mAdditiveStrategy = false;

bool mIsValid = true;

int mPrimitivesBudget = std::numeric_limits<int>::max();
Expand Down
8 changes: 8 additions & 0 deletions src/3d/chunks/qgschunknode_p.h
Expand Up @@ -29,6 +29,7 @@

#include "qgsaabb.h"

#include "qgis.h"
#include <QTime>

#define SIP_NO_FILE
Expand Down Expand Up @@ -167,6 +168,8 @@ class QgsChunkNode
int childCount() const { return mChildren.count(); }
//! Returns array of the four children. Children may be NULLPTR if they were not created yet
QgsChunkNode *const *children() const { return mChildren.constData(); }
//! Returns how the chunked entity should behave when it is going to activate node's children
Qgis::TileRefinementProcess refinementProcess() const { return mRefinementProcess; }
//! Returns current state of the node
State state() const { return mState; }

Expand All @@ -190,6 +193,9 @@ class QgsChunkNode
//! Sets child nodes of this node. Takes ownership of all objects. Must be only called once.
void populateChildren( const QVector<QgsChunkNode *> &children );

//! Sets how the chunked entity should behave when it is going to activate node's children
void setRefinementProcess( Qgis::TileRefinementProcess refinementProcess ) { mRefinementProcess = refinementProcess; }

//! how deep is the node in the tree (zero means root node, every level adds one)
int level() const;

Expand Down Expand Up @@ -262,6 +268,8 @@ class QgsChunkNode

State mState; //!< State of the node

Qgis::TileRefinementProcess mRefinementProcess = Qgis::TileRefinementProcess::Replacement; //!< How to handle display of the node when children get activated

QgsChunkListEntry *mLoaderQueueEntry; //!< Not null <=> QueuedForLoad or QueuedForUpdate state
QgsChunkListEntry *mReplacementQueueEntry; //!< Not null <=> has non-null entity (Loaded or QueuedForUpdate or Updating state)

Expand Down
9 changes: 6 additions & 3 deletions src/3d/qgspointcloudlayerchunkloader_p.cpp
Expand Up @@ -176,7 +176,9 @@ QgsChunkNode *QgsPointCloudLayerChunkLoaderFactory::createRootNode() const
{
const QgsAABB bbox = nodeBoundsToAABB( mPointCloudIndex->nodeBounds( IndexedPointCloudNode( 0, 0, 0, 0 ) ), mPointCloudIndex->offset(), mPointCloudIndex->scale(), mMap, mCoordinateTransform, mZValueOffset );
const float error = mPointCloudIndex->nodeError( IndexedPointCloudNode( 0, 0, 0, 0 ) );
return new QgsChunkNode( QgsChunkNodeId( 0, 0, 0, 0 ), bbox, error );
QgsChunkNode *node = new QgsChunkNode( QgsChunkNodeId( 0, 0, 0, 0 ), bbox, error );
node->setRefinementProcess( mSymbol->renderAsTriangles() ? Qgis::TileRefinementProcess::Replacement : Qgis::TileRefinementProcess::Additive );
return node;
}

QVector<QgsChunkNode *> QgsPointCloudLayerChunkLoaderFactory::createChildren( QgsChunkNode *node ) const
Expand Down Expand Up @@ -208,7 +210,9 @@ QVector<QgsChunkNode *> QgsPointCloudLayerChunkLoaderFactory::createChildren( Qg
const float chZMax = !dy ? bbox.zMax : zc;
const float chYMin = dz ? yc : bbox.yMin;
const float chYMax = dz ? bbox.yMax : yc;
children << new QgsChunkNode( childId, QgsAABB( chXMin, chYMin, chZMin, chXMax, chYMax, chZMax ), childError, node );
QgsChunkNode *child = new QgsChunkNode( childId, QgsAABB( chXMin, chYMin, chZMin, chXMax, chYMax, chZMax ), childError, node );
child->setRefinementProcess( mSymbol->renderAsTriangles() ? Qgis::TileRefinementProcess::Replacement : Qgis::TileRefinementProcess::Additive );
children << child;
}
return children;
}
Expand Down Expand Up @@ -247,7 +251,6 @@ QgsPointCloudLayerChunkedEntity::QgsPointCloudLayerChunkedEntity( QgsPointCloudI
: QgsChunkedEntity( maximumScreenSpaceError,
new QgsPointCloudLayerChunkLoaderFactory( map, coordinateTransform, pc, symbol, zValueScale, zValueOffset, pointBudget ), true, pointBudget )
{
setUsingAdditiveStrategy( !symbol->renderAsTriangles() );
setShowBoundingBoxes( showBoundingBoxes );
}

Expand Down
10 changes: 6 additions & 4 deletions src/3d/qgstiledscenechunkloader_p.cpp
Expand Up @@ -154,23 +154,27 @@ static QgsAABB aabbConvert( const QgsBox3D &b0, const QgsVector3D &sceneOriginTa

QgsChunkNode *QgsTiledSceneChunkLoaderFactory::nodeForTile( const QgsTiledSceneTile &t, const QgsChunkNodeId &nodeId, QgsChunkNode *parent ) const
{
QgsChunkNode *node = nullptr;
if ( hasLargeBounds( t ) )
{
// use the full extent of the scene
QgsVector3D v0 = mMap.mapToWorldCoordinates( QgsVector3D( mMap.extent().xMinimum(), mMap.extent().yMinimum(), -100 ) );
QgsVector3D v1 = mMap.mapToWorldCoordinates( QgsVector3D( mMap.extent().xMaximum(), mMap.extent().yMaximum(), +100 ) );
QgsAABB aabb( v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z() );
float err = std::min( 1e6, t.geometricError() );
return new QgsChunkNode( nodeId, aabb, err, parent );
node = new QgsChunkNode( nodeId, aabb, err, parent );
}
else
{
QgsBox3D box = t.boundingVolume().bounds( mBoundsTransform );
box.setZMinimum( box.zMinimum() * mZValueScale + mZValueOffset );
box.setZMaximum( box.zMaximum() * mZValueScale + mZValueOffset );
const QgsAABB aabb = aabbConvert( box, mMap.origin() );
return new QgsChunkNode( nodeId, aabb, t.geometricError(), parent );
node = new QgsChunkNode( nodeId, aabb, t.geometricError(), parent );
}

node->setRefinementProcess( t.refinementProcess() );
return node;
}


Expand Down Expand Up @@ -312,8 +316,6 @@ void QgsTiledSceneChunkLoaderFactory::prepareChildren( QgsChunkNode *node )
QgsTiledSceneLayerChunkedEntity::QgsTiledSceneLayerChunkedEntity( const Qgs3DMapSettings &map, const QgsTiledSceneIndex &index, double maximumScreenError, bool showBoundingBoxes, double zValueScale, double zValueOffset )
: QgsChunkedEntity( maximumScreenError, new QgsTiledSceneChunkLoaderFactory( map, index, zValueScale, zValueOffset ), true )
{
if ( index.rootTile().refinementProcess() == Qgis::TileRefinementProcess::Additive )
setUsingAdditiveStrategy( true );
setShowBoundingBoxes( showBoundingBoxes );
}

Expand Down

0 comments on commit b0c0e6c

Please sign in to comment.