/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include using namespace osgTerrain; GeometryTechnique::GeometryTechnique() { setFilterBias(0); setFilterWidth(0.1); setFilterMatrixAs(GAUSSIAN); } GeometryTechnique::GeometryTechnique(const GeometryTechnique& gt,const osg::CopyOp& copyop): TerrainTechnique(gt,copyop) { setFilterBias(gt._filterBias); setFilterWidth(gt._filterWidth); setFilterMatrix(gt._filterMatrix); } GeometryTechnique::~GeometryTechnique() { } void GeometryTechnique::setFilterBias(float filterBias) { _filterBias = filterBias; if (!_filterBiasUniform) _filterBiasUniform = new osg::Uniform("filterBias",_filterBias); else _filterBiasUniform->set(filterBias); } void GeometryTechnique::setFilterWidth(float filterWidth) { _filterWidth = filterWidth; if (!_filterWidthUniform) _filterWidthUniform = new osg::Uniform("filterWidth",_filterWidth); else _filterWidthUniform->set(filterWidth); } void GeometryTechnique::setFilterMatrix(const osg::Matrix3& matrix) { _filterMatrix = matrix; if (!_filterMatrixUniform) _filterMatrixUniform = new osg::Uniform("filterMatrix",_filterMatrix); else _filterMatrixUniform->set(_filterMatrix); } void GeometryTechnique::setFilterMatrixAs(FilterType filterType) { switch(filterType) { case(SMOOTH): setFilterMatrix(osg::Matrix3(0.0, 0.5/2.5, 0.0, 0.5/2.5, 0.5/2.5, 0.5/2.5, 0.0, 0.5/2.5, 0.0)); break; case(GAUSSIAN): setFilterMatrix(osg::Matrix3(0.0, 1.0/8.0, 0.0, 1.0/8.0, 4.0/8.0, 1.0/8.0, 0.0, 1.0/8.0, 0.0)); break; case(SHARPEN): setFilterMatrix(osg::Matrix3(0.0, -1.0, 0.0, -1.0, 5.0, -1.0, 0.0, -1.0, 0.0)); break; }; } void GeometryTechnique::init(int dirtyMask, bool assumeMultiThreaded) { OSG_INFO<<"Doing GeometryTechnique::init()"< lock(_writeBufferMutex); // take a temporary referecen osg::ref_ptr tile = _terrainTile; if (dirtyMask==0) return; osg::ref_ptr buffer = new BufferData; Locator* masterLocator = computeMasterLocator(); osg::Vec3d centerModel = computeCenterModel(*buffer, masterLocator); if ((dirtyMask & TerrainTile::IMAGERY_DIRTY)==0) { generateGeometry(*buffer, masterLocator, centerModel); osg::ref_ptr read_buffer = _currentBufferData; osg::StateSet* stateset = read_buffer->_geode->getStateSet(); if (stateset) { // OSG_NOTICE<<"Reusing StateSet"<_geode->setStateSet(stateset); } else { applyColorLayers(*buffer); applyTransparency(*buffer); } } else { generateGeometry(*buffer, masterLocator, centerModel); applyColorLayers(*buffer); applyTransparency(*buffer); } if (buffer->_transform.valid()) buffer->_transform->setThreadSafeRefUnref(true); if (!_currentBufferData || !assumeMultiThreaded) { // no currentBufferData so we must be the first init to be applied _currentBufferData = buffer; } else { // there is already an active _currentBufferData so we'll request that this gets swapped on next frame. _newBufferData = buffer; if (_terrainTile->getTerrain()) _terrainTile->getTerrain()->updateTerrainTileOnNextFrame(_terrainTile); } _terrainTile->setDirtyMask(0); } Locator* GeometryTechnique::computeMasterLocator() { osgTerrain::Layer* elevationLayer = _terrainTile->getElevationLayer(); osgTerrain::Layer* colorLayer = _terrainTile->getColorLayer(0); Locator* elevationLocator = elevationLayer ? elevationLayer->getLocator() : 0; Locator* colorLocator = colorLayer ? colorLayer->getLocator() : 0; Locator* masterLocator = elevationLocator ? elevationLocator : colorLocator; if (!masterLocator) { OSG_NOTICE<<"Problem, no locator found in any of the terrain layers"<getElevationLayer(); osgTerrain::Layer* colorLayer = _terrainTile->getColorLayer(0); Locator* elevationLocator = elevationLayer ? elevationLayer->getLocator() : 0; Locator* colorLocator = colorLayer ? colorLayer->getLocator() : 0; if (!elevationLocator) elevationLocator = masterLocator; if (!colorLocator) colorLocator = masterLocator; osg::Vec3d bottomLeftNDC(DBL_MAX, DBL_MAX, 0.0); osg::Vec3d topRightNDC(-DBL_MAX, -DBL_MAX, 0.0); if (elevationLayer) { if (elevationLocator!= masterLocator) { masterLocator->computeLocalBounds(*elevationLocator, bottomLeftNDC, topRightNDC); } else { bottomLeftNDC.x() = osg::minimum(bottomLeftNDC.x(), 0.0); bottomLeftNDC.y() = osg::minimum(bottomLeftNDC.y(), 0.0); topRightNDC.x() = osg::maximum(topRightNDC.x(), 1.0); topRightNDC.y() = osg::maximum(topRightNDC.y(), 1.0); } } if (colorLayer) { if (colorLocator!= masterLocator) { masterLocator->computeLocalBounds(*colorLocator, bottomLeftNDC, topRightNDC); } else { bottomLeftNDC.x() = osg::minimum(bottomLeftNDC.x(), 0.0); bottomLeftNDC.y() = osg::minimum(bottomLeftNDC.y(), 0.0); topRightNDC.x() = osg::maximum(topRightNDC.x(), 1.0); topRightNDC.y() = osg::maximum(topRightNDC.y(), 1.0); } } OSG_INFO<<"bottomLeftNDC = "<size() + 1; _vertices->push_back(v); _normals->push_back(n); // OSG_NOTICE<<"setVertex("< _vertices; osg::ref_ptr _normals; osg::ref_ptr _elevations; osg::ref_ptr _boundaryVertices; }; VertexNormalGenerator::VertexNormalGenerator(Locator* masterLocator, const osg::Vec3d& centerModel, int numRows, int numColumns, float scaleHeight, bool createSkirt): _masterLocator(masterLocator), _centerModel(centerModel), _numRows(numRows), _numColumns(numColumns), _scaleHeight(scaleHeight) { int numVerticesInBody = numColumns*numRows; int numVerticesInSkirt = createSkirt ? numColumns*2 + numRows*2 - 4 : 0; int numVertices = numVerticesInBody+numVerticesInSkirt; _indices.resize((_numRows+2)*(_numColumns+2),0); _vertices = new osg::Vec3Array; _vertices->reserve(numVertices); _normals = new osg::Vec3Array; _normals->reserve(numVertices); _elevations = new osg::FloatArray; _elevations->reserve(numVertices); _boundaryVertices = new osg::Vec3Array; _boundaryVertices->reserve(_numRows*2 + _numColumns*2 + 4); } void VertexNormalGenerator::populateCenter(osgTerrain::Layer* elevationLayer, LayerToTexCoordMap& layerToTexCoordMap) { // OSG_NOTICE<getNumRows()!=static_cast(_numRows)) || (elevationLayer->getNumColumns()!=static_cast(_numColumns)) ); for(int j=0; j<_numRows; ++j) { for(int i=0; i<_numColumns; ++i) { osg::Vec3d ndc( ((double)i)/(double)(_numColumns-1), ((double)j)/(double)(_numRows-1), 0.0); bool validValue = true; if (elevationLayer) { float value = 0.0f; if (sampled) validValue = elevationLayer->getInterpolatedValidValue(ndc.x(), ndc.y(), value); else validValue = elevationLayer->getValidValue(i,j,value); ndc.z() = value*_scaleHeight; } if (validValue) { osg::Vec3d model; _masterLocator->convertLocalToModel(ndc, model); for(VertexNormalGenerator::LayerToTexCoordMap::iterator itr = layerToTexCoordMap.begin(); itr != layerToTexCoordMap.end(); ++itr) { osg::Vec2Array* texcoords = itr->second.first.get(); osgTerrain::ImageLayer* imageLayer(dynamic_cast(itr->first)); if (imageLayer != NULL) { Locator* colorLocator = itr->second.second; if (colorLocator != _masterLocator) { osg::Vec3d color_ndc; Locator::convertLocalCoordBetween(*_masterLocator, ndc, *colorLocator, color_ndc); (*texcoords).push_back(osg::Vec2(color_ndc.x(), color_ndc.y())); } else { (*texcoords).push_back(osg::Vec2(ndc.x(), ndc.y())); } } else { osgTerrain::ContourLayer* contourLayer(dynamic_cast(itr->first)); bool texCoordSet = false; if (contourLayer) { osg::TransferFunction1D* transferFunction = contourLayer->getTransferFunction(); if (transferFunction) { float difference = transferFunction->getMaximum()-transferFunction->getMinimum(); if (difference != 0.0f) { osg::Vec3d color_ndc; osgTerrain::Locator* colorLocator(itr->second.second); if (colorLocator != _masterLocator) { Locator::convertLocalCoordBetween(*_masterLocator,ndc,*colorLocator,color_ndc); } else { color_ndc = ndc; } color_ndc[2] /= _scaleHeight; (*texcoords).push_back(osg::Vec2((color_ndc[2]-transferFunction->getMinimum())/difference,0.0f)); texCoordSet = true; } } } if (!texCoordSet) { (*texcoords).push_back(osg::Vec2(0.0f,0.0f)); } } } if (_elevations.valid()) { (*_elevations).push_back(ndc.z()); } // compute the local normal osg::Vec3d ndc_one = ndc; ndc_one.z() += 1.0; osg::Vec3d model_one; _masterLocator->convertLocalToModel(ndc_one, model_one); model_one = model_one - model; model_one.normalize(); setVertex(i, j, osg::Vec3(model-_centerModel), model_one); } } } } void VertexNormalGenerator::populateLeftBoundary(osgTerrain::Layer* elevationLayer) { // OSG_NOTICE<<" VertexNormalGenerator::populateLeftBoundary("<getNumRows()!=static_cast(_numRows)) || (elevationLayer->getNumColumns()!=static_cast(_numColumns)) ); for(int j=0; j<_numRows; ++j) { for(int i=-1; i<=0; ++i) { osg::Vec3d ndc( ((double)i)/(double)(_numColumns-1), ((double)j)/(double)(_numRows-1), 0.0); osg::Vec3d left_ndc( 1.0+ndc.x(), ndc.y(), 0.0); bool validValue = true; if (elevationLayer) { float value = 0.0f; if (sampled) validValue = elevationLayer->getInterpolatedValidValue(left_ndc.x(), left_ndc.y(), value); else validValue = elevationLayer->getValidValue((_numColumns-1)+i,j,value); ndc.z() = value*_scaleHeight; ndc.z() += 0.f; } if (validValue) { osg::Vec3d model; _masterLocator->convertLocalToModel(ndc, model); // compute the local normal osg::Vec3d ndc_one = ndc; ndc_one.z() += 1.0; osg::Vec3d model_one; _masterLocator->convertLocalToModel(ndc_one, model_one); model_one = model_one - model; model_one.normalize(); setVertex(i, j, osg::Vec3(model-_centerModel), model_one); // OSG_NOTICE<<" setVertex("<getNumRows()!=static_cast(_numRows)) || (elevationLayer->getNumColumns()!=static_cast(_numColumns)) ); for(int j=0; j<_numRows; ++j) { for(int i=_numColumns-1; i<_numColumns+1; ++i) { osg::Vec3d ndc( ((double)i)/(double)(_numColumns-1), ((double)j)/(double)(_numRows-1), 0.0); osg::Vec3d right_ndc(ndc.x()-1.0, ndc.y(), 0.0); bool validValue = true; if (elevationLayer) { float value = 0.0f; if (sampled) validValue = elevationLayer->getInterpolatedValidValue(right_ndc.x(), right_ndc.y(), value); else validValue = elevationLayer->getValidValue(i-(_numColumns-1),j,value); ndc.z() = value*_scaleHeight; } if (validValue) { osg::Vec3d model; _masterLocator->convertLocalToModel(ndc, model); // compute the local normal osg::Vec3d ndc_one = ndc; ndc_one.z() += 1.0; osg::Vec3d model_one; _masterLocator->convertLocalToModel(ndc_one, model_one); model_one = model_one - model; model_one.normalize(); setVertex(i, j, osg::Vec3(model-_centerModel), model_one); // OSG_NOTICE<<" setVertex("<getNumRows()!=static_cast(_numRows)) || (elevationLayer->getNumColumns()!=static_cast(_numColumns)) ); for(int j=_numRows-1; j<_numRows+1; ++j) { for(int i=0; i<_numColumns; ++i) { osg::Vec3d ndc( ((double)i)/(double)(_numColumns-1), ((double)j)/(double)(_numRows-1), 0.0); osg::Vec3d above_ndc( ndc.x(), ndc.y()-1.0, 0.0); bool validValue = true; if (elevationLayer) { float value = 0.0f; if (sampled) validValue = elevationLayer->getInterpolatedValidValue(above_ndc.x(), above_ndc.y(), value); else validValue = elevationLayer->getValidValue(i,j-(_numRows-1),value); ndc.z() = value*_scaleHeight; } if (validValue) { osg::Vec3d model; _masterLocator->convertLocalToModel(ndc, model); // compute the local normal osg::Vec3d ndc_one = ndc; ndc_one.z() += 1.0; osg::Vec3d model_one; _masterLocator->convertLocalToModel(ndc_one, model_one); model_one = model_one - model; model_one.normalize(); setVertex(i, j, osg::Vec3(model-_centerModel), model_one); // OSG_NOTICE<<" setVertex("<getNumRows()!=static_cast(_numRows)) || (elevationLayer->getNumColumns()!=static_cast(_numColumns)) ); for(int j=-1; j<=0; ++j) { for(int i=0; i<_numColumns; ++i) { osg::Vec3d ndc( ((double)i)/(double)(_numColumns-1), ((double)j)/(double)(_numRows-1), 0.0); osg::Vec3d below_ndc( ndc.x(), 1.0+ndc.y(), 0.0); bool validValue = true; if (elevationLayer) { float value = 0.0f; if (sampled) validValue = elevationLayer->getInterpolatedValidValue(below_ndc.x(), below_ndc.y(), value); else validValue = elevationLayer->getValidValue(i,(_numRows-1)+j,value); ndc.z() = value*_scaleHeight; } if (validValue) { osg::Vec3d model; _masterLocator->convertLocalToModel(ndc, model); // compute the local normal osg::Vec3d ndc_one = ndc; ndc_one.z() += 1.0; osg::Vec3d model_one; _masterLocator->convertLocalToModel(ndc_one, model_one); model_one = model_one - model; model_one.normalize(); setVertex(i, j, osg::Vec3(model-_centerModel), model_one); // OSG_NOTICE<<" setVertex("<=0) computeNormal(i, j, (*_normals)[vi]); else OSG_NOTICE<<"Not computing normal, vi="<getTerrain(); osgTerrain::Layer* elevationLayer = _terrainTile->getElevationLayer(); buffer._geode = new osg::Geode; if(buffer._transform.valid()) buffer._transform->addChild(buffer._geode.get()); buffer._geometry = new osg::Geometry; buffer._geode->addDrawable(buffer._geometry.get()); osg::Geometry* geometry = buffer._geometry.get(); unsigned int numRows = 20; unsigned int numColumns = 20; if (elevationLayer) { numColumns = elevationLayer->getNumColumns(); numRows = elevationLayer->getNumRows(); } float sampleRatio = terrain ? terrain->getSampleRatio() : 1.0f; // OSG_NOTICE<<"Sample ratio="<minimumNumColumns) && (numRows>minimumNumRows)) { unsigned int originalNumColumns = numColumns; unsigned int originalNumRows = numRows; numColumns = std::max((unsigned int) (float(originalNumColumns)*sqrtf(sampleRatio)), minimumNumColumns); numRows = std::max((unsigned int) (float(originalNumRows)*sqrtf(sampleRatio)),minimumNumRows); } bool treatBoundariesToValidDataAsDefaultValue = _terrainTile->getTreatBoundariesToValidDataAsDefaultValue(); OSG_INFO<<"TreatBoundariesToValidDataAsDefaultValue="<(elevationLayer); if (hfl && hfl->getHeightField()) { skirtHeight = hfl->getHeightField()->getSkirtHeight(); } bool createSkirt = skirtHeight != 0.0f; float scaleHeight = terrain ? terrain->getVerticalScale() : 1.0f; // construct the VertexNormalGenerator which will manage the generation and the vertices and normals VertexNormalGenerator VNG(masterLocator, centerModel, numRows, numColumns, scaleHeight, createSkirt); unsigned int numVertices = VNG.capacity(); // allocate and assign vertices geometry->setVertexArray(VNG._vertices.get()); // allocate and assign normals geometry->setNormalArray(VNG._normals.get(), osg::Array::BIND_PER_VERTEX); // allocate and assign tex coords // typedef std::pair< osg::ref_ptr, Locator* > TexCoordLocatorPair; // typedef std::map< Layer*, TexCoordLocatorPair > LayerToTexCoordMap; VertexNormalGenerator::LayerToTexCoordMap layerToTexCoordMap; for(unsigned int layerNum=0; layerNum<_terrainTile->getNumColorLayers(); ++layerNum) { osgTerrain::Layer* colorLayer = _terrainTile->getColorLayer(layerNum); if (colorLayer) { VertexNormalGenerator::LayerToTexCoordMap::iterator itr = layerToTexCoordMap.find(colorLayer); if (itr!=layerToTexCoordMap.end()) { geometry->setTexCoordArray(layerNum, itr->second.first.get()); } else { Locator* locator = colorLayer->getLocator(); if (!locator) { osgTerrain::SwitchLayer* switchLayer = dynamic_cast(colorLayer); if (switchLayer) { if (switchLayer->getActiveLayer()>=0 && static_cast(switchLayer->getActiveLayer())getNumLayers() && switchLayer->getLayer(switchLayer->getActiveLayer())) { locator = switchLayer->getLayer(switchLayer->getActiveLayer())->getLocator(); } } } VertexNormalGenerator::TexCoordLocatorPair& tclp = layerToTexCoordMap[colorLayer]; tclp.first = new osg::Vec2Array; tclp.first->reserve(numVertices); tclp.second = locator ? locator : masterLocator; geometry->setTexCoordArray(layerNum, tclp.first.get()); } } } // allocate and assign color osg::ref_ptr colors = new osg::Vec4Array(1); (*colors)[0].set(1.0f,1.0f,1.0f,1.0f); geometry->setColorArray(colors.get(), osg::Array::BIND_OVERALL); // // populate vertex and tex coord arrays // VNG.populateCenter(elevationLayer, layerToTexCoordMap); if (terrain && terrain->getEqualizeBoundaries()) { TileID tileID = _terrainTile->getTileID(); osg::ref_ptr left_tile = terrain->getTile(TileID(tileID.level, tileID.x-1, tileID.y)); osg::ref_ptr right_tile = terrain->getTile(TileID(tileID.level, tileID.x+1, tileID.y)); osg::ref_ptr top_tile = terrain->getTile(TileID(tileID.level, tileID.x, tileID.y+1)); osg::ref_ptr bottom_tile = terrain->getTile(TileID(tileID.level, tileID.x, tileID.y-1)); #if 0 osg::ref_ptr top_left_tile = terrain->getTile(TileID(tileID.level, tileID.x-1, tileID.y+1)); osg::ref_ptr top_right_tile = terrain->getTile(TileID(tileID.level, tileID.x+1, tileID.y+1)); osg::ref_ptr bottom_left_tile = terrain->getTile(TileID(tileID.level, tileID.x-1, tileID.y-1)); osg::ref_ptr bottom_right_tile = terrain->getTile(TileID(tileID.level, tileID.x+1, tileID.y-1)); #endif VNG.populateLeftBoundary(left_tile.valid() ? left_tile->getElevationLayer() : 0); VNG.populateRightBoundary(right_tile.valid() ? right_tile->getElevationLayer() : 0); VNG.populateAboveBoundary(top_tile.valid() ? top_tile->getElevationLayer() : 0); VNG.populateBelowBoundary(bottom_tile.valid() ? bottom_tile->getElevationLayer() : 0); _neighbours.clear(); bool updateNeighboursImmediately = false; if (left_tile.valid()) addNeighbour(left_tile.get()); if (right_tile.valid()) addNeighbour(right_tile.get()); if (top_tile.valid()) addNeighbour(top_tile.get()); if (bottom_tile.valid()) addNeighbour(bottom_tile.get()); #if 0 if (bottom_left_tile.valid()) addNeighbour(bottom_left_tile.get()); if (bottom_right_tile.valid()) addNeighbour(bottom_right_tile.get()); if (top_left_tile.valid()) addNeighbour(top_left_tile.get()); if (top_right_tile.valid()) addNeighbour(top_right_tile.get()); #endif if (left_tile.valid()) { if (left_tile->getTerrainTechnique()==0 || !(left_tile->getTerrainTechnique()->containsNeighbour(_terrainTile))) { int dirtyMask = left_tile->getDirtyMask() | TerrainTile::LEFT_EDGE_DIRTY; if (updateNeighboursImmediately) left_tile->init(dirtyMask, true); else left_tile->setDirtyMask(dirtyMask); } } if (right_tile.valid()) { if (right_tile->getTerrainTechnique()==0 || !(right_tile->getTerrainTechnique()->containsNeighbour(_terrainTile))) { int dirtyMask = right_tile->getDirtyMask() | TerrainTile::RIGHT_EDGE_DIRTY; if (updateNeighboursImmediately) right_tile->init(dirtyMask, true); else right_tile->setDirtyMask(dirtyMask); } } if (top_tile.valid()) { if (top_tile->getTerrainTechnique()==0 || !(top_tile->getTerrainTechnique()->containsNeighbour(_terrainTile))) { int dirtyMask = top_tile->getDirtyMask() | TerrainTile::TOP_EDGE_DIRTY; if (updateNeighboursImmediately) top_tile->init(dirtyMask, true); else top_tile->setDirtyMask(dirtyMask); } } if (bottom_tile.valid()) { if (bottom_tile->getTerrainTechnique()==0 || !(bottom_tile->getTerrainTechnique()->containsNeighbour(_terrainTile))) { int dirtyMask = bottom_tile->getDirtyMask() | TerrainTile::BOTTOM_EDGE_DIRTY; if (updateNeighboursImmediately) bottom_tile->init(dirtyMask, true); else bottom_tile->setDirtyMask(dirtyMask); } } #if 0 if (bottom_left_tile.valid()) { if (!(bottom_left_tile->getTerrainTechnique()->containsNeighbour(_terrainTile))) { int dirtyMask = bottom_left_tile->getDirtyMask() | TerrainTile::BOTTOM_LEFT_CORNER_DIRTY; if (updateNeighboursImmediately) bottom_left_tile->init(dirtyMask, true); else bottom_left_tile->setDirtyMask(dirtyMask); } } if (bottom_right_tile.valid()) { if (!(bottom_right_tile->getTerrainTechnique()->containsNeighbour(_terrainTile))) { int dirtyMask = bottom_right_tile->getDirtyMask() | TerrainTile::BOTTOM_RIGHT_CORNER_DIRTY; if (updateNeighboursImmediately) bottom_right_tile->init(dirtyMask, true); else bottom_right_tile->setDirtyMask(dirtyMask); } } if (top_right_tile.valid()) { if (!(top_right_tile->getTerrainTechnique()->containsNeighbour(_terrainTile))) { int dirtyMask = top_right_tile->getDirtyMask() | TerrainTile::TOP_RIGHT_CORNER_DIRTY; if (updateNeighboursImmediately) top_right_tile->init(dirtyMask, true); else top_right_tile->setDirtyMask(dirtyMask); } } if (top_left_tile.valid()) { if (!(top_left_tile->getTerrainTechnique()->containsNeighbour(_terrainTile))) { int dirtyMask = top_left_tile->getDirtyMask() | TerrainTile::TOP_LEFT_CORNER_DIRTY; if (updateNeighboursImmediately) top_left_tile->init(dirtyMask, true); else top_left_tile->setDirtyMask(dirtyMask); } } #endif } osg::ref_ptr skirtVectors = new osg::Vec3Array((*VNG._normals)); VNG.computeNormals(); // // populate the primitive data // bool swapOrientation = !(masterLocator->orientationOpenGL()); bool smallTile = numVertices < 65536; // OSG_NOTICE<<"smallTile = "< elements = smallTile ? static_cast(new osg::DrawElementsUShort(GL_TRIANGLES)) : static_cast(new osg::DrawElementsUInt(GL_TRIANGLES)); elements->reserveElements((numRows-1) * (numColumns-1) * 6); geometry->addPrimitiveSet(elements.get()); unsigned int i, j; for(j=0; j=0) ++numValid; if (i01>=0) ++numValid; if (i10>=0) ++numValid; if (i11>=0) ++numValid; if (numValid==4) { // optimize which way to put the diagonal by choosing to // place it between the two corners that have the least curvature // relative to each other. float dot_00_11 = (*VNG._normals)[i00] * (*VNG._normals)[i11]; float dot_01_10 = (*VNG._normals)[i01] * (*VNG._normals)[i10]; if (dot_00_11 > dot_01_10) { elements->addElement(i01); elements->addElement(i00); elements->addElement(i11); elements->addElement(i00); elements->addElement(i10); elements->addElement(i11); } else { elements->addElement(i01); elements->addElement(i00); elements->addElement(i10); elements->addElement(i01); elements->addElement(i10); elements->addElement(i11); } } else if (numValid==3) { if (i00>=0) elements->addElement(i00); if (i01>=0) elements->addElement(i01); if (i11>=0) elements->addElement(i11); if (i10>=0) elements->addElement(i10); } } } if (createSkirt) { osg::ref_ptr vertices = VNG._vertices.get(); osg::ref_ptr normals = VNG._normals.get(); osg::ref_ptr skirtDrawElements = smallTile ? static_cast(new osg::DrawElementsUShort(GL_QUAD_STRIP)) : static_cast(new osg::DrawElementsUInt(GL_QUAD_STRIP)); // create bottom skirt vertices int r,c; r=0; for(c=0;c(numColumns);++c) { int orig_i = VNG.vertex_index(c,r); if (orig_i>=0) { unsigned int new_i = vertices->size(); // index of new index of added skirt point osg::Vec3 new_v = (*vertices)[orig_i] - ((*skirtVectors)[orig_i])*skirtHeight; (*vertices).push_back(new_v); if (normals.valid()) (*normals).push_back((*normals)[orig_i]); for(VertexNormalGenerator::LayerToTexCoordMap::iterator itr = layerToTexCoordMap.begin(); itr != layerToTexCoordMap.end(); ++itr) { itr->second.first->push_back((*itr->second.first)[orig_i]); } skirtDrawElements->addElement(orig_i); skirtDrawElements->addElement(new_i); } else { if (skirtDrawElements->getNumIndices()!=0) { geometry->addPrimitiveSet(skirtDrawElements.get()); skirtDrawElements = smallTile ? static_cast(new osg::DrawElementsUShort(GL_QUAD_STRIP)) : static_cast(new osg::DrawElementsUInt(GL_QUAD_STRIP)); } } } if (skirtDrawElements->getNumIndices()!=0) { geometry->addPrimitiveSet(skirtDrawElements.get()); skirtDrawElements = smallTile ? static_cast(new osg::DrawElementsUShort(GL_QUAD_STRIP)) : static_cast(new osg::DrawElementsUInt(GL_QUAD_STRIP)); } // create right skirt vertices c=numColumns-1; for(r=0;r(numRows);++r) { int orig_i = VNG.vertex_index(c,r); // index of original vertex of grid if (orig_i>=0) { unsigned int new_i = vertices->size(); // index of new index of added skirt point osg::Vec3 new_v = (*vertices)[orig_i] - ((*skirtVectors)[orig_i])*skirtHeight; (*vertices).push_back(new_v); if (normals.valid()) (*normals).push_back((*normals)[orig_i]); for(VertexNormalGenerator::LayerToTexCoordMap::iterator itr = layerToTexCoordMap.begin(); itr != layerToTexCoordMap.end(); ++itr) { itr->second.first->push_back((*itr->second.first)[orig_i]); } skirtDrawElements->addElement(orig_i); skirtDrawElements->addElement(new_i); } else { if (skirtDrawElements->getNumIndices()!=0) { geometry->addPrimitiveSet(skirtDrawElements.get()); skirtDrawElements = smallTile ? static_cast(new osg::DrawElementsUShort(GL_QUAD_STRIP)) : static_cast(new osg::DrawElementsUInt(GL_QUAD_STRIP)); } } } if (skirtDrawElements->getNumIndices()!=0) { geometry->addPrimitiveSet(skirtDrawElements.get()); skirtDrawElements = smallTile ? static_cast(new osg::DrawElementsUShort(GL_QUAD_STRIP)) : static_cast(new osg::DrawElementsUInt(GL_QUAD_STRIP)); } // create top skirt vertices r=numRows-1; for(c=numColumns-1;c>=0;--c) { int orig_i = VNG.vertex_index(c,r); // index of original vertex of grid if (orig_i>=0) { unsigned int new_i = vertices->size(); // index of new index of added skirt point osg::Vec3 new_v = (*vertices)[orig_i] - ((*skirtVectors)[orig_i])*skirtHeight; (*vertices).push_back(new_v); if (normals.valid()) (*normals).push_back((*normals)[orig_i]); for(VertexNormalGenerator::LayerToTexCoordMap::iterator itr = layerToTexCoordMap.begin(); itr != layerToTexCoordMap.end(); ++itr) { itr->second.first->push_back((*itr->second.first)[orig_i]); } skirtDrawElements->addElement(orig_i); skirtDrawElements->addElement(new_i); } else { if (skirtDrawElements->getNumIndices()!=0) { geometry->addPrimitiveSet(skirtDrawElements.get()); skirtDrawElements = smallTile ? static_cast(new osg::DrawElementsUShort(GL_QUAD_STRIP)) : static_cast(new osg::DrawElementsUInt(GL_QUAD_STRIP)); } } } if (skirtDrawElements->getNumIndices()!=0) { geometry->addPrimitiveSet(skirtDrawElements.get()); skirtDrawElements = smallTile ? static_cast(new osg::DrawElementsUShort(GL_QUAD_STRIP)) : static_cast(new osg::DrawElementsUInt(GL_QUAD_STRIP)); } // create left skirt vertices c=0; for(r=numRows-1;r>=0;--r) { int orig_i = VNG.vertex_index(c,r); // index of original vertex of grid if (orig_i>=0) { unsigned int new_i = vertices->size(); // index of new index of added skirt point osg::Vec3 new_v = (*vertices)[orig_i] - ((*skirtVectors)[orig_i])*skirtHeight; (*vertices).push_back(new_v); if (normals.valid()) (*normals).push_back((*normals)[orig_i]); for(VertexNormalGenerator::LayerToTexCoordMap::iterator itr = layerToTexCoordMap.begin(); itr != layerToTexCoordMap.end(); ++itr) { itr->second.first->push_back((*itr->second.first)[orig_i]); } skirtDrawElements->addElement(orig_i); skirtDrawElements->addElement(new_i); } else { if (skirtDrawElements->getNumIndices()!=0) { geometry->addPrimitiveSet(skirtDrawElements.get()); skirtDrawElements = new osg::DrawElementsUShort(GL_QUAD_STRIP); } } } if (skirtDrawElements->getNumIndices()!=0) { geometry->addPrimitiveSet(skirtDrawElements.get()); } } geometry->setUseDisplayList(false); geometry->setUseVertexBufferObjects(true); #if 0 { osgUtil::VertexCacheMissVisitor vcmv_before; osgUtil::VertexCacheMissVisitor vcmv_after; osgUtil::VertexCacheVisitor vcv; osgUtil::VertexAccessOrderVisitor vaov; vcmv_before.doGeometry(*geometry); vcv.optimizeVertices(*geometry); vaov.optimizeOrder(*geometry); vcmv_after.doGeometry(*geometry); #if 0 OSG_NOTICE<<"vcmv_before.triangles="< builder = osgDB::Registry::instance()->getKdTreeBuilder()->clone(); buffer._geode->accept(*builder); //osg::Timer_t after = osg::Timer::instance()->tick(); //OSG_NOTICE<<"KdTree build time "<delta_m(before, after)< LayerToTextureMap; LayerToTextureMap layerToTextureMap; for(unsigned int layerNum=0; layerNum<_terrainTile->getNumColorLayers(); ++layerNum) { osgTerrain::Layer* colorLayer = _terrainTile->getColorLayer(layerNum); if (!colorLayer) continue; osgTerrain::SwitchLayer* switchLayer = dynamic_cast(colorLayer); if (switchLayer) { if (switchLayer->getActiveLayer()<0 || static_cast(switchLayer->getActiveLayer())>=switchLayer->getNumLayers()) { continue; } colorLayer = switchLayer->getLayer(switchLayer->getActiveLayer()); if (!colorLayer) continue; } osg::Image* image = colorLayer->getImage(); if (!image) continue; osgTerrain::ImageLayer* imageLayer = dynamic_cast(colorLayer); osgTerrain::ContourLayer* contourLayer = dynamic_cast(colorLayer); if (imageLayer) { osg::StateSet* stateset = buffer._geode->getOrCreateStateSet(); osg::Texture2D* texture2D = dynamic_cast(layerToTextureMap[colorLayer]); if (!texture2D) { texture2D = new osg::Texture2D; texture2D->setImage(image); texture2D->setMaxAnisotropy(16.0f); texture2D->setResizeNonPowerOfTwoHint(false); texture2D->setFilter(osg::Texture::MIN_FILTER, colorLayer->getMinFilter()); texture2D->setFilter(osg::Texture::MAG_FILTER, colorLayer->getMagFilter()); texture2D->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE); texture2D->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE); bool mipMapping = !(texture2D->getFilter(osg::Texture::MIN_FILTER)==osg::Texture::LINEAR || texture2D->getFilter(osg::Texture::MIN_FILTER)==osg::Texture::NEAREST); bool s_NotPowerOfTwo = image->s()==0 || (image->s() & (image->s() - 1)); bool t_NotPowerOfTwo = image->t()==0 || (image->t() & (image->t() - 1)); if (mipMapping && (s_NotPowerOfTwo || t_NotPowerOfTwo)) { OSG_INFO<<"Disabling mipmapping for non power of two tile size("<s()<<", "<t()<<")"<setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); } layerToTextureMap[colorLayer] = texture2D; // OSG_NOTICE<<"Creating new ImageLayer texture "<s()="<s()<<" image->t()="<t()<setTextureAttributeAndModes(layerNum, texture2D, osg::StateAttribute::ON); } else if (contourLayer) { osg::StateSet* stateset = buffer._geode->getOrCreateStateSet(); osg::Texture1D* texture1D = dynamic_cast(layerToTextureMap[colorLayer]); if (!texture1D) { texture1D = new osg::Texture1D; texture1D->setImage(image); texture1D->setResizeNonPowerOfTwoHint(false); texture1D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST); texture1D->setFilter(osg::Texture::MAG_FILTER, colorLayer->getMagFilter()); layerToTextureMap[colorLayer] = texture1D; } stateset->setTextureAttributeAndModes(layerNum, texture1D, osg::StateAttribute::ON); } } } void GeometryTechnique::applyTransparency(BufferData& buffer) { TerrainTile::BlendingPolicy blendingPolicy = _terrainTile->getBlendingPolicy(); if (blendingPolicy == TerrainTile::INHERIT && _terrainTile->getTerrain()) { OSG_INFO<<"GeometryTechnique::applyTransparency() inheriting policy from Terrain"<getTerrain()->getBlendingPolicy(); } if (blendingPolicy == TerrainTile::INHERIT) { OSG_INFO<<"GeometryTechnique::applyTransparency() policy is INHERIT, defaulting to ENABLE_BLENDING_WHEN_ALPHA_PRESENT"<getNumColorLayers(); ++i) { osg::Image* image = (_terrainTile->getColorLayer(i)!=0) ? _terrainTile->getColorLayer(i)->getImage() : 0; if (image) { enableBlending = image->isImageTranslucent(); break; } } } if (enableBlending) { osg::StateSet* stateset = buffer._geode->getOrCreateStateSet(); stateset->setMode(GL_BLEND, osg::StateAttribute::ON); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); } } void GeometryTechnique::update(osgUtil::UpdateVisitor* uv) { if (_terrainTile) _terrainTile->osg::Group::traverse(*uv); if (_newBufferData.valid()) { _currentBufferData = _newBufferData; _newBufferData = 0; } } void GeometryTechnique::cull(osgUtil::CullVisitor* cv) { if (_currentBufferData.valid()) { if (_currentBufferData->_transform.valid()) { _currentBufferData->_transform->accept(*cv); } } } void GeometryTechnique::traverse(osg::NodeVisitor& nv) { if (!_terrainTile) return; // if app traversal update the frame count. if (nv.getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR) { if (_terrainTile->getDirty()) _terrainTile->init(_terrainTile->getDirtyMask(), false); osgUtil::UpdateVisitor* uv = nv.asUpdateVisitor(); if (uv) { update(uv); return; } } else if (nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR) { osgUtil::CullVisitor* cv = nv.asCullVisitor(); if (cv) { cull(cv); return; } } if (_terrainTile->getDirty()) { OSG_INFO<<"******* Doing init ***********"<init(_terrainTile->getDirtyMask(), false); } if (_currentBufferData.valid()) { if (_currentBufferData->_transform.valid()) _currentBufferData->_transform->accept(nv); } } void GeometryTechnique::cleanSceneGraph() { } void GeometryTechnique::releaseGLObjects(osg::State* state) const { if (_currentBufferData.valid() && _currentBufferData->_transform.valid()) _currentBufferData->_transform->releaseGLObjects(state); if (_newBufferData.valid() && _newBufferData->_transform.valid()) _newBufferData->_transform->releaseGLObjects(state); }