void
MPTerrainEngineNode::createTerrain()
{
    // scrub the heightfield cache.
    if (_tileModelFactory)
        _tileModelFactory->getHeightFieldCache()->clear();

    // New terrain
    _terrain = new TerrainNode( _deadTiles.get() );
    this->addChild( _terrain );

    // Enable blending on the terrain node; this will result in the underlying
    // "empty" globe being transparent instead of white.
    if (_terrainOptions.enableBlending().value())
    {
        _terrain->getOrCreateStateSet()->setMode(GL_BLEND , osg::StateAttribute::ON);
    }

    // Factory to create the root keys:
    KeyNodeFactory* factory = getKeyNodeFactory();

    // Build the first level of the terrain.
    // Collect the tile keys comprising the root tiles of the terrain.
    std::vector< TileKey > keys;
    _update_mapf->getProfile()->getAllKeysAtLOD( *_terrainOptions.firstLOD(), keys );

    // create a root node for each root tile key.
    OE_INFO << LC << "Creating " << keys.size() << " root keys.." << std::endl;

    TilePagedLOD* root = new TilePagedLOD( _uid, _liveTiles, _deadTiles );
    //osg::Group* root = new osg::Group();
    _terrain->addChild( root );

    osg::ref_ptr<osgDB::Options> dbOptions = Registry::instance()->cloneOrCreateOptions();

    unsigned child = 0;
    for( unsigned i=0; i<keys.size(); ++i )
    {
        osg::ref_ptr<osg::Node> node = factory->createNode( keys[i], true, 0L );
        if ( node.valid() )
        {
            root->addChild( node.get() );
            root->setRange( child++, 0.0f, FLT_MAX );
            root->setCenter( node->getBound().center() );
            root->setNumChildrenThatCannotBeExpired( child );
        }
        else
        {
            OE_WARN << LC << "Couldn't make tile for root key: " << keys[i].str() << std::endl;
        }
    }

    _rootTilesRegistered = false;

    updateShaders();
}
void
MPTerrainEngineNode::createTerrain()
{
    // scrub the heightfield cache.
    if (_tileModelFactory)
        _tileModelFactory->getHeightFieldCache()->clear();

    // New terrain
    _terrain = new TerrainNode( _deadTiles.get() );
    this->addChild( _terrain );

    // Enable blending on the terrain node; this will result in the underlying
    // "empty" globe being transparent instead of white.
    if (_terrainOptions.enableBlending().value())
    {
        _terrain->getOrCreateStateSet()->setMode(GL_BLEND , osg::StateAttribute::ON);
    }

    // Factory to create the root keys:
    KeyNodeFactory* factory = getKeyNodeFactory();

    // Build the first level of the terrain.
    // Collect the tile keys comprising the root tiles of the terrain.
    std::vector< TileKey > keys;
    _update_mapf->getProfile()->getAllKeysAtLOD( *_terrainOptions.firstLOD(), keys );

    // create a root node for each root tile key.
    OE_INFO << LC << "Creating root keys (" << keys.size() << ")" << std::flush;

    for( unsigned i=0; i<keys.size(); ++i )
    {
        osg::Node* node = factory->createRootNode( keys[i] );
        OE_INFO_CONTINUE << "." << std::flush;
        if ( node )
        {
            _terrain->addChild( node );
            TileNode* tilenode = osgEarth::findTopMostNodeOfType<TileNode>(node);
            if ( tilenode )
                _liveTiles->add( tilenode );
        }
        else
        {
            OE_WARN << LC << "Couldn't make tile for root key: " << keys[i].str() << std::endl;
        }
    }

    OE_INFO_CONTINUE << "done." << std::endl;

    updateShaders();
}
//---------------------------------------------
//$$$
void MPTerrainEngineNode::_createTerrainTilePagedLOD()
{
	// Factory to create the root keys:
	KeyNodeFactory* factory = getKeyNodeFactory();

	// Build the first level of the terrain.
	// Collect the tile keys comprising the root tiles of the terrain.
	std::vector< TileKey > keys;
	_update_mapf->getProfile()->getAllKeysAtLOD( *_terrainOptions.firstLOD(), keys );

	// create a root node for each root tile key.
	OE_INFO << LC << "Creating " << keys.size() << " root keys.." << std::endl;

	TilePagedLOD* root = new TilePagedLOD( _uid, _liveTiles, _deadTiles );
	//osg::Group* root = new osg::Group();

	osg::ref_ptr<osgDB::Options> dbOptions = Registry::instance()->cloneOrCreateOptions();

	unsigned child = 0;
	std::cout<<"MPTerrainEngineNode::refresh() ( @osgEarthDrivers\\..\\MPTerrainEngineNode.cpp ) : Begin create KeyNode"<<std::endl;//$$$
	for( unsigned i=0; i<keys.size(); ++i )
	{
		osg::ref_ptr<osg::Node> node = factory->createNode( keys[i], true, true, 0L );//$$$这里消耗太多时间了!!阻塞了渲染线程。
		if ( node.valid() )
		{
			root->addChild( node.get() );
			root->setRange( child++, 0.0f, FLT_MAX );
			root->setCenter( node->getBound().center() );
			root->setNumChildrenThatCannotBeExpired( child );
		}
		else
		{
			OE_WARN << LC << "Couldn't make tile for root key: " << keys[i].str() << std::endl;
		}
	}
	std::cout<<"After create KeyNode"<<std::endl;//$$$

	osgX::StaticOSGViewerAssistant::dealWithUpdateOperation( new RefreshTerrainOperation( this, root ) );
}
void
MPTerrainEngineNode::dirtyTerrain()
{
    // scrub the heightfield cache.
    if (_tileModelFactory)
    {
        _tileModelFactory->clearCaches();
    }

    // remove existing:
    if ( _terrain )
    {
        this->removeChild( _terrain );
    }

    // New terrain
    _terrain = new TerrainNode( _deadTiles.get() );

#ifdef USE_RENDER_BINS
    _terrain->getOrCreateStateSet()->setRenderBinDetails( 0, _terrainRenderBinPrototype->getName() );
    _terrain->getOrCreateStateSet()->setNestRenderBins(false);
#else
    _terrain->getOrCreateStateSet()->setRenderBinDetails(0, "SORT_FRONT_TO_BACK");
#endif

    this->addChild( _terrain );

    // Factory to create the root keys:
    KeyNodeFactory* factory = getKeyNodeFactory();
    
    // Build the first level of the terrain.
    // Collect the tile keys comprising the root tiles of the terrain.
    std::vector< TileKey > keys;
    _update_mapf->getProfile()->getAllKeysAtLOD( *_terrainOptions.firstLOD(), keys );

    // create a root node for each root tile key.
    OE_INFO << LC << "Creating " << keys.size() << " root keys.." << std::endl;

    TilePagedLOD* root = new TilePagedLOD( _uid, _liveTiles, _deadTiles );
    _terrain->addChild( root );

    osg::ref_ptr<osgDB::Options> dbOptions = Registry::instance()->cloneOrCreateOptions();

    unsigned child = 0;
    for( unsigned i=0; i<keys.size(); ++i )
    {
        osg::ref_ptr<osg::Node> node = factory->createNode( keys[i], true, true, 0L );
        if ( node.valid() )
        {
            root->addChild( node.get() );
            root->setRange( child++, 0.0f, FLT_MAX );
            root->setCenter( node->getBound().center() );
            root->setNumChildrenThatCannotBeExpired( child );
        }
        else
        {
            OE_WARN << LC << "Couldn't make tile for root key: " << keys[i].str() << std::endl;
        }
    }

    _rootTilesRegistered = false;

    updateState();

    // Call the base class
    TerrainEngineNode::dirtyTerrain();
}
void
MPTerrainEngineNode::dirtyTerrain()
{
    // scrub the heightfield cache.
    if (_tileModelFactory)
    {
        _tileModelFactory->clearCaches();
    }

    // remove existing:
    if ( _terrain )
    {
        this->removeChild( _terrain );
    }

    // New terrain
    _terrain = new TerrainNode();

    // Clear out the tile registry:
    _liveTiles->releaseAll(_releaser.get());

    // minimizes depth overdraw
    _terrain->getOrCreateStateSet()->setRenderBinDetails(0, "SORT_FRONT_TO_BACK");

    this->addChild( _terrain );
    // Build the first level of the terrain.
    // Collect the tile keys comprising the root tiles of the terrain.
    if ( _update_mapf )
    {
        // Factory to create the root keys:
        KeyNodeFactory* factory = getKeyNodeFactory();
    
        std::vector< TileKey > keys;
        _update_mapf->getProfile()->getAllKeysAtLOD( *_terrainOptions.firstLOD(), keys );

        // create a root node for each root tile key.
        OE_DEBUG << LC << "Creating " << keys.size() << " root keys.." << std::endl;

        osg::Group* root = new osg::Group;
        _terrain->addChild( root );        


        osg::ref_ptr<osgDB::Options> dbOptions = Registry::instance()->cloneOrCreateOptions();

        // Accumulate data from low to high resolution when necessary:
        bool accumulate = true;

        unsigned child = 0;
        for( unsigned i=0; i<keys.size(); ++i )
        {
            osg::ref_ptr<osg::Node> node = factory->createNode( keys[i], accumulate, true, 0L );
            if ( node.valid() )
            {
                root->addChild( node.get() );
            }
            else
            {
                OE_WARN << LC << "Couldn't make tile for root key: " << keys[i].str() << std::endl;
            }
        }
    }

    updateState();

    // Call the base class
    TerrainEngineNode::dirtyTerrain();
}