void TerrainTileModelFactory::addNormalMap(TerrainTileModel* model, const Map* map, const TileKey& key, ProgressCallback* progress) { OE_START_TIMER(fetch_normalmap); if (model->elevationModel().valid()) { const osgEarth::ElevationInterpolation& interp = map->getMapOptions().elevationInterpolation().get(); // Can only generate the normal map if the center heightfield was built: osg::ref_ptr<osg::Image> image = HeightFieldUtils::convertToNormalMap( model->heightFields(), key.getProfile()->getSRS() ); if (image.valid()) { TerrainTileImageLayerModel* layerModel = new TerrainTileImageLayerModel(); layerModel->setName( "oe_normal_map" ); // Made an image, so store this as a texture with no matrix. osg::Texture* texture = createNormalTexture( image.get() ); layerModel->setTexture( texture ); model->normalModel() = layerModel; } } if (progress) progress->stats()["fetch_normalmap_time"] += OE_STOP_TIMER(fetch_normalmap); }
void TileNode::merge(const TerrainTileModel* model, const RenderBindings& bindings) { bool newElevationData = false; const SamplerBinding& color = bindings[SamplerBinding::COLOR]; if (color.isActive()) { for(TerrainTileColorLayerModelVector::const_iterator i = model->colorLayers().begin(); i != model->colorLayers().end(); ++i) { TerrainTileImageLayerModel* model = dynamic_cast<TerrainTileImageLayerModel*>(i->get()); if (model) { if (model->getTexture()) { RenderingPass* pass = _renderModel.getPass(model->getImageLayer()->getUID()); if (!pass) { pass = &_renderModel.addPass(); pass->setLayer(model->getLayer()); // This is a new pass that just showed up at this LOD // Since it just arrived at this LOD, make the parent the same as the color. if (bindings[SamplerBinding::COLOR_PARENT].isActive()) { pass->samplers()[SamplerBinding::COLOR_PARENT]._texture = model->getTexture(); pass->samplers()[SamplerBinding::COLOR_PARENT]._matrix.makeIdentity(); } } pass->samplers()[SamplerBinding::COLOR]._texture = model->getTexture(); pass->samplers()[SamplerBinding::COLOR]._matrix = *model->getMatrix(); // Handle an RTT image layer: if (model->getImageLayer() && model->getImageLayer()->createTextureSupported()) { // Check the texture's userdata for a Node. If there is one there, // render it to the texture using the Tile Rasterizer service. // TODO: consider hanging on to this texture and not applying it to // the live tile until the RTT is complete. (Prevents unsightly flashing) GeoNode* rttNode = dynamic_cast<GeoNode*>(model->getTexture()->getUserData()); if (rttNode) { _context->getTileRasterizer()->push(rttNode->_node.get(), model->getTexture(), rttNode->_extent); } } } } else // non-image color layer (like splatting, e.g.) { TerrainTileColorLayerModel* model = i->get(); if (model && model->getLayer()) { RenderingPass* pass = _renderModel.getPass(model->getLayer()->getUID()); if (!pass) { pass = &_renderModel.addPass(); pass->setLayer(model->getLayer()); } } } } } // Elevation: const SamplerBinding& elevation = bindings[SamplerBinding::ELEVATION]; if (elevation.isActive() && model->elevationModel().valid() && model->elevationModel()->getTexture()) { osg::Texture* tex = model->elevationModel()->getTexture(); // always keep the elevation image around because we use it for bounding box computation: tex->setUnRefImageDataAfterApply(false); _renderModel._sharedSamplers[SamplerBinding::ELEVATION]._texture = tex; _renderModel._sharedSamplers[SamplerBinding::ELEVATION]._matrix.makeIdentity(); setElevationRaster(tex->getImage(0), osg::Matrixf::identity()); newElevationData = true; } // Normals: const SamplerBinding& normals = bindings[SamplerBinding::NORMAL]; if (normals.isActive() && model->normalModel().valid() && model->normalModel()->getTexture()) { osg::Texture* tex = model->normalModel()->getTexture(); // keep the normal map around because we might update it later in "ping" tex->setUnRefImageDataAfterApply(false); _renderModel._sharedSamplers[SamplerBinding::NORMAL]._texture = tex; _renderModel._sharedSamplers[SamplerBinding::NORMAL]._matrix.makeIdentity(); updateNormalMap(); } // Other Shared Layers: for (unsigned i = 0; i < model->sharedLayers().size(); ++i) { TerrainTileImageLayerModel* layerModel = model->sharedLayers()[i].get(); if (layerModel->getTexture()) { // locate the shared binding corresponding to this layer: UID uid = layerModel->getImageLayer()->getUID(); unsigned bindingIndex = INT_MAX; for(unsigned i=SamplerBinding::SHARED; i<bindings.size() && bindingIndex==INT_MAX; ++i) { if (bindings[i].isActive() && bindings[i].sourceUID().isSetTo(uid)) { bindingIndex = i; } } if (bindingIndex < INT_MAX) { osg::Texture* tex = layerModel->getTexture(); _renderModel._sharedSamplers[bindingIndex]._texture = tex; _renderModel._sharedSamplers[bindingIndex]._matrix.makeIdentity(); } } } // Patch Layers for (unsigned i = 0; i < model->patchLayers().size(); ++i) { TerrainTilePatchLayerModel* layerModel = model->patchLayers()[i].get(); } if (_childrenReady) { getSubTile(0)->refreshInheritedData(this, bindings); getSubTile(1)->refreshInheritedData(this, bindings); getSubTile(2)->refreshInheritedData(this, bindings); getSubTile(3)->refreshInheritedData(this, bindings); } if (newElevationData) { _context->getEngine()->getTerrain()->notifyTileAdded(getKey(), this); } }
void TerrainTileModelFactory::addColorLayers(TerrainTileModel* model, const Map* map, const TerrainEngineRequirements* reqs, const TileKey& key, const CreateTileModelFilter& filter, ProgressCallback* progress) { OE_START_TIMER(fetch_image_layers); int order = 0; LayerVector layers; map->getLayers(layers); for (LayerVector::const_iterator i = layers.begin(); i != layers.end(); ++i) { Layer* layer = i->get(); if (layer->getRenderType() != layer->RENDERTYPE_TERRAIN_SURFACE) continue; if (!layer->getEnabled()) continue; if (!filter.accept(layer)) continue; ImageLayer* imageLayer = dynamic_cast<ImageLayer*>(layer); if (imageLayer) { osg::Texture* tex = 0L; osg::Matrixf textureMatrix; if (imageLayer->isKeyInLegalRange(key) && imageLayer->mayHaveDataInExtent(key.getExtent())) { if (imageLayer->createTextureSupported()) { tex = imageLayer->createTexture( key, progress, textureMatrix ); } else { GeoImage geoImage = imageLayer->createImage( key, progress ); if ( geoImage.valid() ) { if ( imageLayer->isCoverage() ) tex = createCoverageTexture(geoImage.getImage(), imageLayer); else tex = createImageTexture(geoImage.getImage(), imageLayer); } } } // if this is the first LOD, and the engine requires that the first LOD // be populated, make an empty texture if we didn't get one. if (tex == 0L && _options.firstLOD() == key.getLOD() && reqs && reqs->fullDataAtFirstLodRequired()) { tex = _emptyTexture.get(); } if (tex) { tex->setName(model->getKey().str()); TerrainTileImageLayerModel* layerModel = new TerrainTileImageLayerModel(); layerModel->setImageLayer(imageLayer); layerModel->setTexture(tex); layerModel->setMatrix(new osg::RefMatrixf(textureMatrix)); model->colorLayers().push_back(layerModel); if (imageLayer->isShared()) { model->sharedLayers().push_back(layerModel); } if (imageLayer->isDynamic()) { model->setRequiresUpdateTraverse(true); } } } else // non-image kind of TILE layer: { TerrainTileColorLayerModel* colorModel = new TerrainTileColorLayerModel(); colorModel->setLayer(layer); model->colorLayers().push_back(colorModel); } } if (progress) progress->stats()["fetch_imagery_time"] += OE_STOP_TIMER(fetch_image_layers); }
void TerrainTileModelFactory::addElevation(TerrainTileModel* model, const Map* map, const TileKey& key, const CreateTileModelFilter& filter, unsigned border, ProgressCallback* progress) { // make an elevation layer. OE_START_TIMER(fetch_elevation); if (!filter.empty() && !filter.elevation().isSetTo(true)) return; const osgEarth::ElevationInterpolation& interp = map->getMapOptions().elevationInterpolation().get(); // Request a heightfield from the map. osg::ref_ptr<osg::HeightField> mainHF; osg::ref_ptr<NormalMap> normalMap; bool hfOK = getOrCreateHeightField(map, key, SAMPLE_FIRST_VALID, interp, border, mainHF, normalMap, progress) && mainHF.valid(); if (hfOK == false && key.getLOD() == _options.firstLOD().get()) { OE_DEBUG << LC << "No HF at key " << key.str() << ", making placeholder" << std::endl; mainHF = new osg::HeightField(); mainHF->allocate(1, 1); mainHF->setHeight(0, 0, 0.0f); hfOK = true; } if (hfOK && mainHF.valid()) { osg::ref_ptr<TerrainTileElevationModel> layerModel = new TerrainTileElevationModel(); layerModel->setHeightField( mainHF.get() ); // pre-calculate the min/max heights: for( unsigned col = 0; col < mainHF->getNumColumns(); ++col ) { for( unsigned row = 0; row < mainHF->getNumRows(); ++row ) { float h = mainHF->getHeight(col, row); if ( h > layerModel->getMaxHeight() ) layerModel->setMaxHeight( h ); if ( h < layerModel->getMinHeight() ) layerModel->setMinHeight( h ); } } // needed for normal map generation model->heightFields().setNeighbor(0, 0, mainHF.get()); // convert the heightfield to a 1-channel 32-bit fp image: ImageToHeightFieldConverter conv; osg::Image* hfImage = conv.convertToR32F(mainHF.get()); if ( hfImage ) { // Made an image, so store this as a texture with no matrix. osg::Texture* texture = createElevationTexture( hfImage ); layerModel->setTexture( texture ); model->elevationModel() = layerModel.get(); } if (normalMap.valid()) { TerrainTileImageLayerModel* layerModel = new TerrainTileImageLayerModel(); layerModel->setName( "oe_normal_map" ); // Made an image, so store this as a texture with no matrix. osg::Texture* texture = createNormalTexture(normalMap.get()); layerModel->setTexture( texture ); model->normalModel() = layerModel; } } if (progress) progress->stats()["fetch_elevation_time"] += OE_STOP_TIMER(fetch_elevation); }
// invoke runs in the background pager thread. void LoadTileData::invoke() { osg::ref_ptr<TileNode> tilenode; if ( _tilenode.lock(tilenode) ) { // Assemble all the components necessary to display this tile _model = _context->getEngine()->createTileModel( _context->getMapFrame(), tilenode->getTileKey(), 0L ); // progress // Prep the stateset for merging (and for GL pre-compile). if ( _model.valid() ) { const RenderBindings& bindings = _context->getRenderBindings(); osg::StateSet* stateSet = getStateSet(); // Insert all the color layers into a new MPTexture state attribute, // which exists to facilitate GL pre-compilation. if ( _model->colorLayers().size() > 0 ) { const SamplerBinding* colorBinding = SamplerBinding::findUsage(bindings, SamplerBinding::COLOR); if ( colorBinding ) { osg::ref_ptr<MPTexture> mptex = new MPTexture(); for(TerrainTileImageLayerModelVector::iterator i = _model->colorLayers().begin(); i != _model->colorLayers().end(); ++i) { TerrainTileImageLayerModel* layerModel = i->get(); if ( layerModel && layerModel->getTexture() ) { mptex->setLayer( layerModel->getImageLayer(), layerModel->getTexture(), layerModel->getOrder() ); } } if ( !mptex->getPasses().empty() ) { stateSet->setTextureAttribute( colorBinding->unit(), mptex ); } } } // Insert the elevation texture and an identity matrix: if ( _model->elevationModel().valid() && _model->elevationModel()->getTexture()) { const SamplerBinding* binding = SamplerBinding::findUsage(bindings, SamplerBinding::ELEVATION); if ( binding ) { stateSet->setTextureAttribute( binding->unit(), _model->elevationModel()->getTexture() ); stateSet->removeUniform(binding->matrixName()); stateSet->addUniform( _context->getOrCreateMatrixUniform( binding->matrixName(), osg::Matrixf::identity() ) ); } } // Insert the normal texture and an identity matrix: if ( _model->normalModel().valid() && _model->normalModel()->getTexture() ) { const SamplerBinding* binding = SamplerBinding::findUsage(bindings, SamplerBinding::NORMAL); if ( binding ) { stateSet->setTextureAttribute( binding->unit(), _model->normalModel()->getTexture() ); stateSet->removeUniform(binding->matrixName()); stateSet->addUniform( _context->getOrCreateMatrixUniform( binding->matrixName(), osg::Matrixf::identity() ) ); } } // Process any shared image layers, each of which should have its // own sampler binding point for(TerrainTileImageLayerModelVector::iterator i = _model->sharedLayers().begin(); i != _model->sharedLayers().end(); ++i) { TerrainTileImageLayerModel* layerModel = i->get(); if ( layerModel->getTexture() ) { const SamplerBinding* binding = SamplerBinding::findUID(bindings, layerModel->getImageLayer()->getUID()); if ( binding ) { stateSet->setTextureAttribute( binding->unit(), layerModel->getTexture() ); stateSet->removeUniform(binding->matrixName()); stateSet->addUniform( _context->getOrCreateMatrixUniform( binding->matrixName(), osg::Matrixf::identity() ) ); } } } } } }