void TileNode::cull(osg::NodeVisitor& nv) { if ( nv.getFrameStamp() ) { _lastTraversalFrame.exchange( nv.getFrameStamp()->getFrameNumber() ); } unsigned currLOD = getTileKey().getLOD(); osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>( &nv ); EngineContext* context = static_cast<EngineContext*>( nv.getUserData() ); const SelectionInfo& selectionInfo = context->getSelectionInfo(); if ( context->progress() ) context->progress()->stats()["TileNode::cull"]++; // determine whether we can and should subdivide to a higher resolution: bool subdivide = shouldSubDivide(nv, selectionInfo, cv->getLODScale()); // whether it is OK to create child TileNodes is necessary. bool canCreateChildren = subdivide; // whether it is OK to load data if necessary. bool canLoadData = true; if ( _dirty && context->getOptions().progressive() == true ) { // Don't create children in progressive mode until content is in place canCreateChildren = false; } else { // If this is an inherit-viewpoint camera, we don't need it to invoke subdivision // because we want only the tiles loaded by the true viewpoint. const osg::Camera* cam = cv->getCurrentCamera(); if ( cam && cam->getReferenceFrame() == osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT ) { canCreateChildren = false; canLoadData = false; } } optional<bool> surfaceVisible; // If *any* of the children are visible, subdivide. if (subdivide) { // We are in range of the child nodes. Either draw them or load them. // If the children don't exist, create them and inherit the parent's data. if ( getNumChildren() == 0 && canCreateChildren ) { Threading::ScopedMutexLock exclusive(_mutex); if ( getNumChildren() == 0 ) { createChildren( context ); } } // If all are ready, traverse them now. if ( getNumChildren() == 4 ) { for(int i=0; i<4; ++i) { _children[i]->accept( nv ); } } // If we don't traverse the children, traverse this node's payload. else if ( _surface.valid() ) { surfaceVisible = acceptSurface( cv, context ); } } // If children are outside camera range, draw the payload and expire the children. else if ( _surface.valid() ) { surfaceVisible = acceptSurface( cv, context ); if ( getNumChildren() >= 4 && context->maxLiveTilesExceeded() ) { if (getSubTile(0)->isDormant( nv ) && getSubTile(1)->isDormant( nv ) && getSubTile(2)->isDormant( nv ) && getSubTile(3)->isDormant( nv )) { expireChildren( nv ); } } } // Traverse land cover data at this LOD. int zoneIndex = context->_landCoverData->_currentZoneIndex; if ( zoneIndex < (int)context->_landCoverData->_zones.size() ) { unsigned clearMask = cv->getCurrentCamera()->getClearMask(); bool isDepthCamera = ((clearMask & GL_COLOR_BUFFER_BIT) == 0u) && ((clearMask & GL_DEPTH_BUFFER_BIT) != 0u); bool isShadowCamera = osgEarth::Shadowing::isShadowCamera(cv->getCurrentCamera()); // only consider land cover if we are capturing color OR shadow. if ( isShadowCamera || !isDepthCamera ) { const LandCoverZone& zone = context->_landCoverData->_zones.at(zoneIndex); for(int i=0; i<zone._bins.size(); ++i) { bool pushedPayloadSS = false; const LandCoverBin& bin = zone._bins.at(i); if ( bin._lod == _key.getLOD() && (!isShadowCamera || bin._castShadows) ) { if ( !pushedPayloadSS ) { cv->pushStateSet( _payloadStateSet.get() ); pushedPayloadSS = true; } cv->pushStateSet( bin._stateSet.get() ); // hopefully groups together for rendering. _landCover->accept( nv ); cv->popStateSet(); } if ( pushedPayloadSS ) { cv->popStateSet(); } } } } // If this tile is marked dirty, try loading data. if ( _dirty && canLoadData ) { // Only load data if the surface would be visible to the camera if ( !surfaceVisible.isSet() ) { surfaceVisible = _surface->isVisible(cv); } if ( surfaceVisible == true ) { load( nv ); } else { OE_DEBUG << LC << "load skipped for " << _key.str() << std::endl; } } }
void TileNode::cull(osg::NodeVisitor& nv) { if ( nv.getFrameStamp() ) { _lastTraversalFrame.exchange( nv.getFrameStamp()->getFrameNumber() ); } unsigned currLOD = getTileKey().getLOD(); #if OSGEARTH_REX_TILE_NODE_DEBUG_TRAVERSAL if (currLOD==0) { OE_INFO << LC <<"Traversing: "<<"\n"; } #endif osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>( &nv ); EngineContext* context = static_cast<EngineContext*>( nv.getUserData() ); const SelectionInfo& selectionInfo = context->getSelectionInfo(); // determine whether we can and should subdivide to a higher resolution: bool subdivide = shouldSubDivide(nv, selectionInfo, cv->getLODScale()); // If this is an inherit-viewpoint camera, we don't need it to invoke subdivision // because we want only the tiles loaded by the true viewpoint. bool canCreateChildren = subdivide; const osg::Camera* cam = cv->getCurrentCamera(); if ( cam && cam->getReferenceFrame() == osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT ) { canCreateChildren = false; } // If *any* of the children are visible, subdivide. if (subdivide) { // We are in range of the child nodes. Either draw them or load them. // If the children don't exist, create them and inherit the parent's data. if ( getNumChildren() == 0 && canCreateChildren ) { Threading::ScopedMutexLock exclusive(_mutex); if ( getNumChildren() == 0 ) { createChildren( context ); } } // All 4 children must be ready before we can traverse any of them: unsigned numChildrenReady = 0; if ( getNumChildren() == 4 ) { for(unsigned i = 0; i < 4; ++i) { if ( getSubTile(i)->isReadyToTraverse() ) { ++numChildrenReady; } } } // If all are ready, traverse them now. if ( numChildrenReady == 4 ) { // TODO: // When we do this, we need to quite sure that all 4 children will be accepted into // the draw set. Perhaps isReadyToTraverse() needs to check that. _children[0]->accept( nv ); _children[1]->accept( nv ); _children[2]->accept( nv ); _children[3]->accept( nv ); } // If we don't traverse the children, traverse this node's payload. else if ( _surface.valid() ) { cullSurface( cv ); } } // If children are outside camera range, draw the payload and expire the children. else if ( _surface.valid() ) { cullSurface( cv ); if ( getNumChildren() >= 4 && context->maxLiveTilesExceeded() ) { if (getSubTile(0)->isDormant( nv ) && getSubTile(1)->isDormant( nv ) && getSubTile(2)->isDormant( nv ) && getSubTile(3)->isDormant( nv )) { expireChildren( nv ); } } } // Traverse land cover bins at this LOD. for(int i=0; i<context->landCoverBins()->size(); ++i) { bool first = true; const LandCoverBin& bin = context->landCoverBins()->at(i); if ( bin._lod == getTileKey().getLOD() ) { if ( first ) { cv->pushStateSet( _payloadStateSet.get() ); } cv->pushStateSet( bin._stateSet.get() ); _landCover->accept( nv ); cv->popStateSet(); if ( first ) { cv->popStateSet(); first = false; } } } // If this tile is marked dirty, try loading data. if ( _dirty ) { load( nv ); } }