目标:(三十七)中的105
rex渲染出的地球是靠一块块TileNode瓦片拼接起来的,瓦片之间存在父子关系,一般显示父TileNode就不应显示子TileNode,反之亦然。那么rex是如何做这种显隐控制呢?
1、每一个TileNode瓦片在遍历时,会根据是否有子节点及子节点的准备情况来决定是否遍历其_surface(负责具体的显示内容)。
osgEarthDrivers/engine_rex/TileNode.cpp
bool
TileNode::cull(TerrainCuller* culler)
{
// determine whether we can and should subdivide to a higher resolution:
bool childrenInRange = shouldSubDivide(culler, context->getSelectionInfo());
// whether it is OK to create child TileNodes is necessary.
bool canCreateChildren = childrenInRange;
// whether it is OK to load data if necessary.
bool canLoadData = true;
// whether to accept the current surface node and not the children.
bool canAcceptSurface = false;
// Don't create children in progressive mode until content is in place
if ( _dirty && context->getOptions().progressive() == true )
{
canCreateChildren = false;
}
// 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 = culler->getCamera();
if ( cam && cam->getReferenceFrame() == osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT )
{
canCreateChildren = false;
canLoadData = false;
}
if (childrenInRange)
{
// 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 ( !_childrenReady && canCreateChildren )
{
_mutex.lock();
if ( !_childrenReady )
{
OE_START_TIMER(createChildren);
createChildren( context );
REPORT("TileNode::createChildren", createChildren);
_childrenReady = true;
// This means that you cannot start loading data immediately; must wait a frame.
canLoadData = false;
}
_mutex.unlock();
}
// If all are ready, traverse them now.
if ( _childrenReady )
{
for(int i=0; i<4; ++i)
{
getSubTile(i)->accept(*culler);
}
}
// If we don't traverse the children, traverse this node's payload.
else
{
canAcceptSurface = true;
}
}
// If children are outside camera range, draw the payload and expire the children.
else
{
canAcceptSurface = true;
}
// accept this surface if necessary.
if ( canAcceptSurface )
{
_surface->accept( *culler );
_lastAcceptSurfaceFrame.exchange( culler->getFrameStamp()->getFrameNumber() );
}
}
2、对于一个TileNode瓦片节点,如果经过1的判断,需要裁剪遍历其_surface的话,会在TerrainCuller下的_terrain(TerrainRenderData)下的_tile(DrawTileCommand)中形成一条记录。
osgEarthDrivers/engine_rex/TerrainCuller.cpp
void
TerrainCuller::apply(osg::Node& node)
{
// If the culler added no draw commands for this tile... we still need
// to draw something or else there will be a hole! So draw a blank tile.
// UID = -1 is the special UID code for a blank.
if (_firstTileDrawCommandForTile == 0L)
{
//OE_INFO << LC << "Adding blank render for tile " << _currentTileNode->getKey().str() << std::endl;
DrawTileCommand* cmd = addDrawCommand(-1, &renderModel, 0L, _currentTileNode);
if (cmd)
cmd->_order = 0;
}
}
DrawTileCommand*
TerrainCuller::addDrawCommand(UID uid, const TileRenderModel* model, const RenderingPass* pass, TileNode* tileNode)
{
osg::ref_ptr<LayerDrawable> drawable = _terrain.layer(uid);
if (drawable.valid())
{
// Cull based on the layer extent.
if (drawable->_layer)
{
const LayerExtent& le = (*_layerExtents)[drawable->_layer->getUID()];
if (le._computed &&
le._extent.isValid() &&
le._extent.intersects(tileNode->getKey().getExtent()) == false)
{
// culled out!
//OE_DEBUG << LC << "Skippping " << drawable->_layer->getName()
// << " key " << tileNode->getKey().str()
// << " because it was culled by extent." << std::endl;
return 0L;
}
}
drawable->_tiles.push_back(DrawTileCommand());
DrawTileCommand* tile = &drawable->_tiles.back();
// install everything we need in the Draw Command:
tile->_colorSamplers = pass ? &(pass->samplers()) : 0L;
tile->_sharedSamplers = &model->_sharedSamplers;
tile->_modelViewMatrix = this->getModelViewMatrix();
tile->_keyValue = tileNode->getTileKeyValue();
tile->_geom = surface->getDrawable()->_geom.get();
tile->_morphConstants = tileNode->getMorphConstants();
tile->_key = &tileNode->getKey();
//tile->_order = (int)orderInTile;
tile->_order = drawable->_order; // layer order in map tile.
osg::Vec3 c = surface->getBound().center() * surface->getInverseMatrix();
tile->_range = getDistanceToViewPoint(c, true);
const osg::Image* elevRaster = tileNode->getElevationRaster();
if (elevRaster)
{
float bias = _context->getUseTextureBorder() ? 1.5 : 0.5;
// Compute an elevation texture sampling scale/bias so we sample elevation data on center
// instead of on edge (as we do with color, etc.)
//
// This starts out as:
// scale = (size-1)/size : this shrinks the sample area by one texel since we're sampling on center
// bias = 0.5/size : this shifts the sample area over 1/2 texel to the center.
//
// But, since we also have a 1-texel border, we need to further reduce the scale by 2 texels to
// remove the border, and shift an extra texel over as well. Giving us this:
float size = (float)elevRaster->s();
tile->_elevTexelCoeff.set((size - (2.0*bias)) / size, bias / size);
}
return tile;
}
}
3、加入的记录会在rex引擎遍历时生成渲染叶RenderLeaf,进而绘制出来
void
RexTerrainEngineNode::traverse(osg::NodeVisitor& nv)
{
for(LayerDrawableList::iterator i = culler._terrain.layers().begin();
i != culler._terrain.layers().end();
++i)
{
if (!i->get()->_tiles.empty())
{
lastLayer = i->get();
lastLayer->_order = -1;
cv->apply(*lastLayer);
}
}
待继续分析列表:
9、earth文件中都有哪些options((九)中问题)
10、如何根据earth文件options创建不同的地理信息引擎节点((九)中问题)
11、rex地理信息引擎的四梁八柱((九)中问题)
12、osgEarth::TerrainEngineNode中setMap方法作用((十二)中问题)
13、RexTerrainEngineNode中_mapFrame的作用((十二)中问题)
14、地形变形(Terrain morphing)((十二)中问题)
15、地球瓦片过期门限的含义((十二)中问题)
16、高分辨率优先的含义((十二)中问题)
17、OSGEARTH_DEBUG_NORMALS环境变量的作用((十二)中问题)
18、活跃瓦片寄存器的作用((十二)中问题)
19、资源释放器子节点的作用((十二)中问题)
20、共享几何图形池子节点的作用((十二)中问题)
21、分页瓦片加载器子节点的作用((十二)中问题)
22、分页瓦片卸载器子节点的作用((十二)中问题)
23、栅格化器子节点的作用((十二)中问题)
24、地形子节点的作用((十二)中问题)
25、绑定渲染器的作用((十二)中问题)
26、地图回调函数的作用((十二)中问题)
27、如何将地图图层添加到rex引擎中((十二)中问题)
28、选择信息的作用((十二)中问题)
29、瓦片包围盒修改回调函数的作用((十二)中问题)
30、刷新rex引擎((十二)中问题)
31、刷新边界作用((十二)中问题)
32、osgEarth::Metrics类的意义((十四)中问题)
33、请求合并队列_mergeQueue((十四)中问题)
34、分页瓦片加载器在更新遍历时对请求处理过程((十四)中问题)
35、分页瓦片加载器在更新遍历时对已处理请求裁剪过程((十四)中问题)
36、已处理的请求队列_requests((十四)中问题)
37、DatabasePager中的_fileRequestQueue和_httpRequestQueue((十六)中问题)
38、瓦片请求的生成到处理过程详解((十六)中问题)
39、瓦片节点TileNode的创建过程((十七)中问题)
40、request请求加载瓦片优先级的含义((十七)中问题)
41、request的_internalHandle的作用((十七)中问题)
42、DatabaseRequest中_objectCache含义((十七)中问题)
42、osgEarth的多线程分析((十七)中问题)
43、osgEarth的缓存及其结构((十七)中问题)
44、DatabaseThread从缓存加载数据过程((十七)中问题)
45、DatabaseThread从文件加载数据过程((十七)中问题)
46、决定创建TileNode的时机条件((十七)中问题)
47、TerrainEngineNode的createTileModel过程详解((十七)中问题)
48、DatabaseThread中CompileSet的含义((十七)中问题)
48、PagerLoader的traverse过程详解((十七)中问题)
49、DatabaseThread的run过程详解((十七)中问题)
50、LoadTileData的invoke过程详解((十七)中问题)
51、TileNode的cull过程详解((十七)中问题)
52、遮罩生成器osgEarth::Drivers::RexTerrainEngine::MaskGenerator((十八)中问题)
53、RexTerrainEngineNode::traverse过程详解((十八)中问题)
54、TileNode节点下的场景树分析((十八)中问题)
55、地形瓦片大小尺寸和LOD的关系((十八)中问题)
56、TileNode的_tileKeyValue作用((十八)中问题)
57、TileNode的_morphConstants作用((十八)中问题)
58、TileNode的_stitchNormalMap作用((十八)中问题)
59、TileNode的_renderModel作用((十八)中问题)
60、初始化高程栅格过程详解((十八)中问题)
61、LoadTileData中的CreateTileModelFilter作用((十八)中问题)
62、TileNode节点何时会从场景树中移除((十八)中问题)
63、osgEarth::Map的Profile创建过程((二十)中问题)
64、osgEarth::TerrainTileModelFactory添加颜色层和影像层的区别((二十一)中问题)
65、osgEarth::PatchLayer修补层的作用((二十一)中问题)
66、osgEarth::TerrainLayer中的_memCache(osgEarth::MemCache)详解((二十一)中问题)
67、osgEarth::Layer::RenderType图层渲染类型的作用((二十一)中问题)
68、osgEarth::TerrainLayer中TileSource的作用((二十一)中问题)
69、earth文件没有设置高程图层会不会有默认高程层(高程均为0)((二十一)中问题)
70、TerrainTileModelFactory::addColorLayers过程详解((二十一)中问题)
71、TerrainTileModelFactory::addElevation过程详解((二十一)中问题)
72、osgearth中可能用到的几个全局实例对象(osgDB::Registry osgEarth::Registry osg::Timer osg::DisplaySetting)((二十三)中问题)
73、osgEarth::Map::addLayer过程详解((二十三)中问题)
74、TileNode::setDirty过程详解((二十三)中问题)
75、请求四个状态的含义(IDLE RUNNING MERGING FINISHED)((二十三)中问题)
76、什么时候删除TileNode节点,不会一直增加吧((二十三)中问题)
77、寄存器中请求状态活动记录的含义Registry::instance()->endActivity( req->getName() )((二十三)中问题)
78、瓦片TileNode的生命周期流程详解((二十三)中问题)
79、rex引擎如何将瓦片构造成地球形状((二十五)中问题)
80、高程、影像文件格式详解((二十五)中问题)
81、TileNode的merge过程详解((二十六)中问题)
82、osgEarth支持的空间参考坐标系详解(osgEarth::SpatialReference、osgEarth::CubeSpatialReference、osgEarth::TangentPlaneSpatialReference)((二十九)中问题)
83、osgEarth地球椭球体ellipsoid 大地基准面datum 地图投影Projection详解((二十九)中问题)
84、空间参考坐标系和坐标系统类型的关系(geocentric projected)((二十九)中问题)
85、proj4是什么((二十九)中问题)
86、为什么要删除设置过的垂直水准面((二十九)中问题)
87、osgEarth如何对投影坐标系和大地坐标系进行显示处理的((二十九)中问题)
88、TileNode的节点构成,一个surface、tilenode((三十)中问题)
89、MapFram和MapInfo的关系((三十)中问题)
90、ModifyBoundingBoxCallback的使用时机和场合((三十)中问题)
91、MapFrame为什么要单独存放高程层_elevationLayers,而不是放在图层_layers中((三十)中问题)
92、MapFrame和Map中高程池的作用osg::ref_ptr<ElevationPool> _elevationPool((三十)中问题)
93、osgEarth::Drivers::RexTerrainEngine::TileDrawable分析((三十)中问题)
94、请求读取地理信息失败会如何处理((三十二)中问题)
95、RexTerrainEngineNode的遍历过程详解((三十三)中问题)
96、osgEarth::Drivers::RexTerrainEngine::TerrainCuller的apply过程详解((三十三)中问题)
97、RexTerrainEngineNode的updateState过程详解 设置了很多着色器变量((三十三)中问题)
98、什么时候分配opengl资源((三十三)中问题)
99、TileNode释放opengl资源过程releaseGLObjects详解((三十三)中问题)
100、最近一次遍历的帧号和时间是怎么设置呢(在渲染遍历里),怎么就不会再渲染遍历该瓦片节点了((三十三)中问题)
101、osg::State和osg::StateSet的关系((三十四)中问题)
102、osgEarth::SpatialReference和osgEarth::Profile的关系((三十六)中问题)
103、osgEarth的Geographic、Geodetic、Geocentric和Project的关系((三十六)中问题)
104、TileNode绘制过程详解((三十七)中问题)
105、如何控制父子TileNode节点的显隐((三十七)中问题)
106、GeometryPool的createGeometry过程详解((三十七)中问题)
107、TileNode如何从地图中提取与其分辨率相适应的图像数据((三十七)中问题)