osgearth瓦片渲染

相关类:

  • TileNode
/**
     * TileNode represents a single tile. TileNode has 5 children:
     * one SurfaceNode that renders the actual tile content under a MatrixTransform;
     * and four TileNodes representing the LOD+1 quadtree tiles under this tile.
     */
  • TileDrawable: 只是瓦片的一个外壳,持有内部的SharedGeomtry进行最后渲染
 /**
     * TileDrawable is an osg::Drawable that represents an individual terrain tile
     * for the purposes of scene graph operations (like intersections, bounds
     * computation, statistics, etc.)
     * 
     * NOTE: TileDrawable does not actually render anything!
     * The TerrainRenderData object does all the rendering of tiles.
     *
     * Instead, it exposes various osg::Drawable Functors for traversing
     * the terrain's geometry. It also hold a pointer to the tile's elevation
     * raster so it can properly reflect the elevation data in the texture.
     */
  • SharedGeometry: 瓦片渲染的最小单元,由GeometryPool::createGeometry创建,保存mesh信息

  • SurfaceNode: the node to house the tile drawable:TtileDrawable的持有者

  • RexTerrainEngine:派生自TerrainEngine,用于生成瓦片

     * TerrainEngineNode is the base class and interface for map engine implementations.
         *
         * A map engine lives under a MapNode and is responsible for generating the
         * actual geometry representing the Earth.
    

    RexTerrainEngine有个创建tile的接口:

    一个是创建heightmap的瓦片,一个是创建地球瓦片

        //! for standalone tile creation outside of a terrain
        osg::Node* createTile(const TileKey& key);
    
        //! Create a standalone tile from a tile model (experimental)
        osg::Node* createTile(
            const TerrainTileModel* model,
            int createTileFlags,
            unsigned referenceLOD);
    
  • LayerDrawable:作为一个layer所拥有的DrawTileCommand,统一进行渲染

/**
     * Drawable for single "Layer" i.e. rendering pass. 
     * It is important that LayerDrawables be rendered in the order in which
     * they appear. Since all LayerDrawables share a common bounds, this 
     * should happen automatically, but let's keep an eye out for trouble.
     */
group
GeometryPool
SharedGeometry
drawable
TileDrawable
Image
SurfaceNode
TileNode
TerrainEngineNode
RexTerrainEngineNode
group_terrain
LayerDrawable
DrawTileCommands
vector
DrawTileCommand

tile的渲染:

TerrainCuller,在执行cull流程时,遍历SurfaceNode,获取,::addDrawCommand 将可见的tile加入到待渲染列表中

TerrainCuller::apply(SurfaceNode& node)
{
    TileRenderModel& renderModel = _currentTileNode->renderModel();

    // push the surface matrix:
    osg::RefMatrix* matrix = createOrReuseMatrix(*getModelViewMatrix());
    node.computeLocalToWorldMatrix(*matrix,this);
    _cv->pushModelViewMatrix(matrix, node.getReferenceFrame());

    // now test against the local bounding box for tighter culling:
    if (!_cv->isCulled(node.getAlignedBoundingBox()))
    {
        if (!_isSpy)
        {
            node.setLastFramePassedCull(getFrameStamp()->getFrameNumber());
        }

        int order = 0;
        unsigned count = 0;

        // First go through any legit rendering pass data in the Tile and
        // and add a DrawCommand for each.
        for (unsigned p = 0; p < renderModel._passes.size(); ++p)
        {
            const RenderingPass& pass = renderModel._passes[p];
            DrawTileCommand* cmd = addDrawCommand(pass.sourceUID(), &renderModel, &pass, _currentTileNode);
            if (cmd)
            {
                if (_firstDrawCommandForTile == 0L)
                {
                    _firstDrawCommandForTile = cmd;
                }
                else if (cmd->_layerOrder < _firstDrawCommandForTile->_layerOrder)
                {
                    _firstDrawCommandForTile = cmd;
                }
            }
        }

        // 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 (_firstDrawCommandForTile == 0L)
        {
            //OE_INFO << LC << "Adding blank render for tile " << _currentTileNode->getKey().str() << std::endl;
            DrawTileCommand* cmd = addDrawCommand(-1, &renderModel, 0L, _currentTileNode);
            if (cmd)
            {
                _firstDrawCommandForTile = cmd;
            }
        }

        // Set the layer order of the first draw command for this tile to zero,
        // to support proper terrain blending.
        if (_firstDrawCommandForTile)
        {
            _firstDrawCommandForTile->_layerOrder = 0;
        }

        // update our bounds
        _terrain._drawState->_bs.expandBy(node.getBound());
        _terrain._drawState->_box.expandBy(_terrain._drawState->_bs);
    }
                
    // pop the matrix from the cull stack
    _cv->popModelViewMatrix();

    if (node.getDebugNode())
    {
        node.accept(*_cv);
    }
}

生成DrawTilecommand,保存渲染状态、投影、pass,几何体(SharedGeometry)等参数,并将DrawTileCommand添加到与某个layer相关联的layerDrawable中

DrawTileCommand*
TerrainCuller::addDrawCommand(UID uid, const TileRenderModel* model, const RenderingPass* pass, TileNode* tileNode)
{
    SurfaceNode* surface = tileNode->getSurfaceNode();

    const RenderBindings& bindings = _context->getRenderBindings();

    // skip layers that are not visible:
    if (pass && 
        pass->visibleLayer() && 
        pass->visibleLayer()->getVisible() == false)
    {
        //OE_DEBUG << LC << "Skipping " << pass->visibleLayer()->getName() << " because it's not visible." << std::endl;
        return 0L;
    }

    // add a new Draw command to the appropriate layer
    osg::ref_ptr<LayerDrawable> drawable = _terrain.layer(uid);
    if (drawable.valid())
    {
        // Layer marked for drawing?
        if (drawable->_draw)
        {
            // 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 = _cv->getModelViewMatrix();
            tile->_keyValue = tileNode->getTileKeyValue();
            tile->_geom = surface->getDrawable()->_geom.get();
            tile->_morphConstants = tileNode->getMorphConstants();
            tile->_key = &tileNode->getKey();

            osg::Vec3 c = surface->getBound().center() * surface->getInverseMatrix();
            tile->_range = getDistanceToViewPoint(c, true);

            tile->_layerOrder = drawable->_drawOrder;

            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;
        }
    }
    else if (pass)
    {
        // The pass exists but it's layer is not in the render data draw list.
        // This means that the layer is no longer in the map. Detect and record
        // this information so we can run a cleanup visitor later on.
        ++_orphanedPassesDetected;
    }
    else
    {
        OE_WARN << "Added nothing for a UID -1 darw command" << std::endl;
    }
    
    return 0L;
}

LayerDrawable的渲染,执行真正的瓦片渲染:

LayerDrawable::drawImplementation(osg::RenderInfo& ri) const
{
    //OE_INFO << LC << (_layer ? _layer->getName() : "[empty]") << " tiles=" << _tiles.size() << std::endl;

    // Get this context's state values:
    PerContextDrawState& ds = _drawState->getPCDS(ri.getContextID());

    ds.refresh(ri, _drawState->_bindings);

    if (ds._layerUidUL >= 0)
    {
        GLint uid = _layer ? (GLint)_layer->getUID() : (GLint)-1;
        ds._ext->glUniform1i(ds._layerUidUL, uid);
    }
    else
    {
        // This just means that the fragment shader for this layer doesn't use oe_layer_uid
    }

    for (DrawTileCommands::const_iterator tile = _tiles.begin(); tile != _tiles.end(); ++tile)
    {
        tile->draw(ri, *_drawState, 0L);
    }

    // If set, dirty all OSG state to prevent any leakage - this is sometimes
    // necessary when doing custom OpenGL within a Drawable.
    if (_clearOsgState)
    {
        // Dirty the texture attributes so OSG can properly reset them
        // NOTE: cannot call state.dirtyAllAttributes, because that would invalidate
        // positional state like light sources!
        reinterpret_cast<StateEx*>(ri.getState())->dirtyAllTextureAttributes();

        // NOTE: this is a NOOP in OSG 3.5.x, but not in 3.4.x ... Later we will need to
        // revisit whether to call disableAllVertexArrays() in 3.5.x instead.
        ri.getState()->dirtyAllVertexArrays();
        
        // unbind local buffers when finished.
        ds._ext->glBindBuffer(GL_ARRAY_BUFFER_ARB,0);
        ds._ext->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB,0);

        // gw: no need to do this, in fact it will cause positional attributes
        // (light clip planes and lights) to immediately be reapplied under the
        // current MVM, which will by definition be wrong!)
        //ri.getState()->apply();
    }
}

  • 23
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
osgEarth中,加载二维瓦片地图需要进行以下步骤: 1. 创建地球模型(Earth Model):首先,你需要创建一个osgEarth的地球模型,用于加载和渲染地图数据。你可以使用 osgEarth::Map 或者 osgEarth::MapNode 类来创建地球模型。 2. 添加图层(Layer):在地球模型中,你需要添加一个图层来加载二维瓦片地图数据。osgEarth支持多种图层类型,例如图片图层、矢量图层、高程图层等。对于二维瓦片地图,你可以使用 osgEarth::ImageLayer 类来创建和添加图层。 3. 配置瓦片源(TileSource):对于二维瓦片地图,你需要配置一个瓦片源来提供地图数据。osgEarth支持多种瓦片源类型,如WMS、TMS、WMTS等。你可以通过 osgEarth::TileSourceOptions 类来设置瓦片源的参数,并使用 osgEarth::ImageLayer 类的方法将瓦片源添加到地球模型中。 ``` osgEarth::TileSourceOptions options; options.url() = "http://example.com/tileserver/{z}/{x}/{y}.png"; osgEarth::ImageLayer* imageLayer = new osgEarth::ImageLayer("Tile Layer", options); map->addLayer(imageLayer); ``` 4. 设置视口(Viewpoint):在加载地图之前,你可以设置一个初始的视口(Viewpoint),用于指定地图的默认视角和位置。你可以使用 osgEarth::Viewpoint 类来定义视口,并使用 osgEarth::Map 或者 osgEarth::MapNode 类的方法设置初始视口。 ``` osgEarth::Viewpoint initialViewpoint("Initial View", 0.0, 0.0, 100000.0); map->setInitialViewpoint(initialViewpoint); ``` 5. 创建地球操纵器(EarthManipulator):osgEarth提供了地球操纵器用于交互式操作地球场景。你可以创建一个地球操纵器,并将其附加到 osgViewer::Viewer 或者 osgEarth::View 类上,以实现用户与地图的交互。 ``` osgEarth::Util::EarthManipulator* earthManipulator = new osgEarth::Util::EarthManipulator(); viewer->setCameraManipulator(earthManipulator); ``` 6. 加载和显示地图:最后,你可以使用 osgViewer::Viewer 或者 osgEarth::View 类的方法来加载和显示地图。osgEarth会根据配置的图层、瓦片源等信息,自动加载并渲染地图数据。 ``` viewer->setSceneData(mapNode); viewer->run(); ``` 以上是一个基本的加载二维瓦片地图的流程,具体的实现细节会根据你的需求和使用的API有所不同。你可以参考osgEarth的文档和示例代码,了解更多关于加载二维瓦片地图的详细信息和具体用法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值