osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/engine_osgterrain/MultiPassTerrainTechnique.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003  * Copyright 2008-2010 Pelican Mapping
00004  * http://osgearth.org
00005  *
00006  * osgEarth is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018  */
00019 #include "MultiPassTerrainTechnique"
00020 #include "Terrain"
00021 #include "TransparentLayer"
00022 #include <osgEarth/ImageUtils>
00023 
00024 
00025 #include <osgUtil/SmoothingVisitor>
00026 #include <osgDB/FileUtils>
00027 #include <osg/io_utils>
00028 #include <osg/Texture2D>
00029 #include <osg/Texture1D>
00030 #include <osg/TexEnvCombine>
00031 #include <osg/Program>
00032 #include <osg/Math>
00033 #include <osg/Timer>
00034 #include <osg/Depth>
00035 #include <osg/Version>
00036 
00037 using namespace osgEarth;
00038 
00039 #define NEW_COORD_CODE
00040 
00041 //-------------------------------------------------------------------------
00042 
00043 namespace
00044 {
00045     // userdata structure so we can look up passes by layer-UID in the graph.
00046     struct LayerData : public osg::Referenced
00047     {
00048         LayerData( UID layerUID ) : _layerUID(layerUID) { }
00049         UID _layerUID;
00050     };
00051 
00052     static osg::Geode*
00053     s_findGeodeByUID( osg::Group* group, UID layerUID )
00054     {
00055         for( unsigned int i=0; i<group->getNumChildren(); ++i )
00056         {
00057             osg::Geode* geode = static_cast<osg::Geode*>( group->getChild(i) );
00058             LayerData* d = static_cast<LayerData*>( geode->getUserData() );
00059             if ( d && d->_layerUID == layerUID )
00060                 return geode;
00061         }
00062         return 0L;
00063     }
00064 }
00065 
00066 //-------------------------------------------------------------------------
00067 
00068 MultiPassTerrainTechnique::MultiPassTerrainTechnique( TextureCompositor* texCompositor ) :
00069 TerrainTechnique(),
00070 //osgTerrain::TerrainTechnique(),
00071 _terrainTileInitialized(false),
00072 _texCompositor( texCompositor )
00073 {
00074     this->setThreadSafeRefUnref( true );
00075 }
00076 
00077 MultiPassTerrainTechnique::MultiPassTerrainTechnique(const MultiPassTerrainTechnique& mt,const osg::CopyOp& copyop) :
00078 TerrainTechnique(mt,copyop)
00079 {
00080     _terrainTileInitialized = mt._terrainTileInitialized;
00081     _texCompositor = mt._texCompositor.get();
00082 }
00083 
00084 MultiPassTerrainTechnique::~MultiPassTerrainTechnique()
00085 {
00086 }
00087 
00088 #if 0
00089 void
00090 #if OSG_MIN_VERSION_REQUIRED(2,9,8)
00091 MultiPassTerrainTechnique::init(int dirtyMask, bool assumeMultiThreaded)
00092 #else
00093 MultiPassTerrainTechnique::init()
00094 #endif
00095 #endif
00096 
00097 void
00098 MultiPassTerrainTechnique::init()
00099 {
00100     OE_DEBUG<<"Doing MultiPassTerrainTechnique::init()"<<std::endl;
00101     
00102     if (!_tile) return;
00103    
00104     osgTerrain::Locator* masterLocator = computeMasterLocator();
00105     
00106     osg::Vec3d centerModel = computeCenterModel(masterLocator);
00107     
00108     generateGeometry(masterLocator, centerModel);   
00109 
00110     if (_transform.valid()) _transform->setThreadSafeReferenceCounting(true);
00111 }
00112 
00113 osgTerrain::Locator*
00114 MultiPassTerrainTechnique::computeMasterLocator()
00115 {
00116     osgTerrain::Layer* elevationLayer = _tile->getElevationLayer();
00117     osgTerrain::Locator* locator = elevationLayer ? elevationLayer->getLocator() : 0L;
00118 
00119     if ( !locator )
00120     {
00121         OE_NOTICE << "Problem, no locator found in any of the terrain layers"<<std::endl;
00122         return 0;
00123     }
00124     return locator;
00125 }
00126 
00127 osg::Vec3d
00128 MultiPassTerrainTechnique::computeCenterModel(osgTerrain::Locator* masterLocator)
00129 {
00130     if (!masterLocator) return osg::Vec3d(0.0,0.0,0.0);
00131   
00132     osgTerrain::Layer*   elevationLayer   = _tile->getElevationLayer();
00133     osgTerrain::Locator* elevationLocator = elevationLayer ? elevationLayer->getLocator() : 0;
00134     osgTerrain::Locator* colorLocator     = 0L;
00135     
00136     if (!elevationLocator) elevationLocator = masterLocator;
00137     if (!colorLocator) colorLocator = masterLocator;
00138 
00139     osg::Vec3d bottomLeftNDC(DBL_MAX, DBL_MAX, 0.0);
00140     osg::Vec3d topRightNDC(-DBL_MAX, -DBL_MAX, 0.0);
00141     
00142     if (elevationLayer)
00143     {
00144         if (elevationLocator!= masterLocator)
00145         {
00146             masterLocator->computeLocalBounds(*elevationLocator, bottomLeftNDC, topRightNDC);
00147         }
00148         else
00149         {
00150             bottomLeftNDC.x() = osg::minimum(bottomLeftNDC.x(), 0.0);
00151             bottomLeftNDC.y() = osg::minimum(bottomLeftNDC.y(), 0.0);
00152             topRightNDC.x() = osg::maximum(topRightNDC.x(), 1.0);
00153             topRightNDC.y() = osg::maximum(topRightNDC.y(), 1.0);
00154         }
00155     }
00156 
00157     //if (colorLayer)
00158     //{
00159     //    if (colorLocator!= masterLocator)
00160     //    {
00161     //        masterLocator->computeLocalBounds(*colorLocator, bottomLeftNDC, topRightNDC);
00162     //    }
00163     //    else
00164     //    {
00165     //        bottomLeftNDC.x() = osg::minimum(bottomLeftNDC.x(), 0.0);
00166     //        bottomLeftNDC.y() = osg::minimum(bottomLeftNDC.y(), 0.0);
00167     //        topRightNDC.x() = osg::maximum(topRightNDC.x(), 1.0);
00168     //        topRightNDC.y() = osg::maximum(topRightNDC.y(), 1.0);
00169     //    }
00170     //}
00171 
00172     //OE_DEBUG<<"bottomLeftNDC = "<<bottomLeftNDC<<std::endl;
00173     //OE_DEBUG<<"topRightNDC = "<<topRightNDC<<std::endl;
00174 
00175     _transform = new osg::MatrixTransform;
00176 
00177     osg::Vec3d centerNDC = (bottomLeftNDC + topRightNDC)*0.5;
00178     osg::Vec3d centerModel = (bottomLeftNDC + topRightNDC)*0.5;
00179     masterLocator->convertLocalToModel(centerNDC, centerModel);
00180     
00181     _transform->setMatrix(osg::Matrix::translate(centerModel));
00182     
00183     return centerModel;
00184 }
00185 
00186 osg::Geometry*
00187 MultiPassTerrainTechnique::createGeometryPrototype(osgTerrain::Locator* masterLocator, const osg::Vec3d& centerModel)
00188 {  
00189     osgTerrain::Layer* elevationLayer = _tile->getElevationLayer();
00190 
00191     osg::Geometry* geometry = new osg::Geometry;
00192 
00193         unsigned int numRows = 20;
00194     unsigned int numColumns = 20;
00195     
00196     if (elevationLayer)
00197     {
00198         numColumns = elevationLayer->getNumColumns();
00199         numRows = elevationLayer->getNumRows();
00200     }
00201     
00202     float sampleRatio = _tile->getTerrain() ? _tile->getTerrain()->getSampleRatio() : 1.0f;
00203     
00204     double i_sampleFactor = 1.0;
00205     double j_sampleFactor = 1.0;
00206 
00207     // OE_NOTICE<<"Sample ratio="<<sampleRatio<<std::endl;
00208 
00209     if (sampleRatio!=1.0f)
00210     {
00211     
00212         unsigned int originalNumColumns = numColumns;
00213         unsigned int originalNumRows = numRows;
00214     
00215         numColumns = osg::maximum((unsigned int) (float(originalNumColumns)*sqrtf(sampleRatio)), 4u);
00216         numRows = osg::maximum((unsigned int) (float(originalNumRows)*sqrtf(sampleRatio)),4u);
00217 
00218         i_sampleFactor = double(originalNumColumns-1)/double(numColumns-1);
00219         j_sampleFactor = double(originalNumRows-1)/double(numRows-1);
00220     }
00221     
00222     
00223 
00224     //bool treatBoundariesToValidDataAsDefaultValue = _tile->getTreatBoundariesToValidDataAsDefaultValue();
00225     //OE_DEBUG<<"TreatBoundariesToValidDataAsDefaultValue="<<treatBoundariesToValidDataAsDefaultValue<<std::endl;
00226     
00227     float skirtHeight = 0.0f;
00228     osgTerrain::HeightFieldLayer* hfl = dynamic_cast<osgTerrain::HeightFieldLayer*>(elevationLayer);
00229     if (hfl && hfl->getHeightField()) 
00230     {
00231         skirtHeight = hfl->getHeightField()->getSkirtHeight();
00232     }
00233     
00234     bool createSkirt = skirtHeight != 0.0f;
00235   
00236     unsigned int numVerticesInBody = numColumns*numRows;
00237     unsigned int numVerticesInSkirt = createSkirt ? numColumns*2 + numRows*2 - 4 : 0;
00238     unsigned int numVertices = numVerticesInBody+numVerticesInSkirt;
00239 
00240     // allocate and assign vertices
00241     osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
00242     vertices->reserve(numVertices);
00243     geometry->setVertexArray(vertices.get());
00244 
00245     // allocate and assign normals
00246     osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array;
00247     if (normals.valid()) normals->reserve(numVertices);
00248     geometry->setNormalArray(normals.get());
00249     geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
00250     
00251     //float minHeight = 0.0;
00252     float scaleHeight = _tile->getTerrain() ? _tile->getTerrain()->getVerticalScale() : 1.0f;
00253 
00254     //Reserve space for the elevations
00255     osg::ref_ptr<osg::FloatArray> elevations = new osg::FloatArray;
00256     if (elevations.valid()) elevations->reserve(numVertices);
00257 
00258     // allocate and assign color
00259     osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(1);
00260     (*colors)[0].set(1.0f,1.0f,1.0f,1.0f);    
00261     geometry->setColorArray(colors.get());
00262     geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
00263 
00264     typedef std::vector<int> Indices;
00265     Indices indices(numVertices, -1);
00266     
00267     // populate vertex and tex coord arrays
00268     unsigned int i, j;
00269     for(j=0; j<numRows; ++j)
00270     {
00271         for(i=0; i<numColumns; ++i)
00272         {
00273             unsigned int iv = j*numColumns + i;
00274             osg::Vec3d ndc( ((double)i)/(double)(numColumns-1), ((double)j)/(double)(numRows-1), 0.0);
00275      
00276             bool validValue = true;
00277      
00278             
00279             unsigned int i_equiv = i_sampleFactor==1.0 ? i : (unsigned int) (double(i)*i_sampleFactor);
00280             unsigned int j_equiv = i_sampleFactor==1.0 ? j : (unsigned int) (double(j)*j_sampleFactor);
00281             
00282             if (elevationLayer)
00283             {
00284                 float value = 0.0f;
00285                 validValue = elevationLayer->getValidValue(i_equiv,j_equiv, value);
00286                 // OE_INFO<<"i="<<i<<" j="<<j<<" z="<<value<<std::endl;
00287                 ndc.z() = value*scaleHeight;
00288             }
00289             
00290             if (validValue)
00291             {
00292                 indices[iv] = vertices->size();
00293             
00294                 osg::Vec3d model;
00295                 masterLocator->convertLocalToModel(ndc, model);
00296 
00297                 (*vertices).push_back(model - centerModel);
00298 
00299                 if (elevations.valid())
00300                 {
00301                     (*elevations).push_back(ndc.z());
00302                 }
00303 
00304                 // compute the local normal
00305                 osg::Vec3d ndc_one = ndc; ndc_one.z() += 1.0;
00306                 osg::Vec3d model_one;
00307                 masterLocator->convertLocalToModel(ndc_one, model_one);
00308                 model_one = model_one - model;
00309                 model_one.normalize();            
00310                 (*normals).push_back(model_one);
00311             }
00312             else
00313             {
00314                 indices[iv] = -1;
00315             }
00316         }
00317     }
00318     
00319     // populate primitive sets
00320 //    bool optimizeOrientations = elevations!=0;
00321     bool swapOrientation = !(masterLocator->orientationOpenGL());
00322     
00323     osg::ref_ptr<osg::DrawElementsUInt> elements = new osg::DrawElementsUInt(GL_TRIANGLES);
00324     elements->reserve((numRows-1) * (numColumns-1) * 6);
00325 
00326     geometry->addPrimitiveSet(elements.get());
00327 
00328     for(j=0; j<numRows-1; ++j)
00329     {
00330         for(i=0; i<numColumns-1; ++i)
00331         {
00332             int i00;
00333             int i01;
00334             if (swapOrientation)
00335             {
00336                 i01 = j*numColumns + i;
00337                 i00 = i01+numColumns;
00338             }
00339             else
00340             {
00341                 i00 = j*numColumns + i;
00342                 i01 = i00+numColumns;
00343             }
00344 
00345             int i10 = i00+1;
00346             int i11 = i01+1;
00347 
00348             // remap indices to final vertex positions
00349             i00 = indices[i00];
00350             i01 = indices[i01];
00351             i10 = indices[i10];
00352             i11 = indices[i11];
00353             
00354             unsigned int numValid = 0;
00355             if (i00>=0) ++numValid;
00356             if (i01>=0) ++numValid;
00357             if (i10>=0) ++numValid;
00358             if (i11>=0) ++numValid;
00359             
00360             if (numValid==4)
00361             {
00362                 float e00 = (*elevations)[i00];
00363                 float e10 = (*elevations)[i10];
00364                 float e01 = (*elevations)[i01];
00365                 float e11 = (*elevations)[i11];
00366 
00367                 if (fabsf(e00-e11)<fabsf(e01-e10))
00368                 {
00369                     elements->push_back(i01);
00370                     elements->push_back(i00);
00371                     elements->push_back(i11);
00372 
00373                     elements->push_back(i00);
00374                     elements->push_back(i10);
00375                     elements->push_back(i11);
00376                 }
00377                 else
00378                 {
00379                     elements->push_back(i01);
00380                     elements->push_back(i00);
00381                     elements->push_back(i10);
00382 
00383                     elements->push_back(i01);
00384                     elements->push_back(i10);
00385                     elements->push_back(i11);
00386                 }
00387             }
00388             else if (numValid==3)
00389             {
00390                 if (i00>=0) elements->push_back(i00);
00391                 if (i01>=0) elements->push_back(i01);
00392                 if (i11>=0) elements->push_back(i11);
00393                 if (i10>=0) elements->push_back(i10);
00394             }
00395             
00396         }
00397     }
00398     
00399     osg::ref_ptr<osg::Vec3Array> skirtVectors = new osg::Vec3Array((*normals));
00400     
00401     if (elevationLayer)
00402     {
00403         osgUtil::SmoothingVisitor smoother;
00404         smoother.smooth(*geometry);
00405         
00406         normals = dynamic_cast<osg::Vec3Array*>(geometry->getNormalArray());
00407         
00408         if (!normals) createSkirt = false;
00409     }
00410 
00411     if (createSkirt)
00412     {
00413         osg::ref_ptr<osg::DrawElementsUShort> skirtDrawElements = new osg::DrawElementsUShort(GL_QUAD_STRIP);
00414 
00415         // create bottom skirt vertices
00416         int r,c;
00417         r=0;
00418         for(c=0;c<static_cast<int>(numColumns);++c)
00419         {
00420             int orig_i = indices[(r)*numColumns+c]; // index of original vertex of grid
00421             if (orig_i>=0)
00422             {
00423                 unsigned int new_i = vertices->size(); // index of new index of added skirt point
00424                 osg::Vec3 new_v = (*vertices)[orig_i] - ((*skirtVectors)[orig_i])*skirtHeight;
00425                 (*vertices).push_back(new_v);
00426                 if (normals.valid()) (*normals).push_back((*normals)[orig_i]);
00427 
00428                 skirtDrawElements->push_back(orig_i);
00429                 skirtDrawElements->push_back(new_i);
00430             }
00431             else
00432             {
00433                 if (!skirtDrawElements->empty())
00434                 {
00435                     geometry->addPrimitiveSet(skirtDrawElements.get());
00436                     skirtDrawElements = new osg::DrawElementsUShort(GL_QUAD_STRIP);
00437                 }
00438                 
00439             }
00440         }
00441 
00442         if (!skirtDrawElements->empty())
00443         {
00444             geometry->addPrimitiveSet(skirtDrawElements.get());
00445             skirtDrawElements = new osg::DrawElementsUShort(GL_QUAD_STRIP);
00446         }
00447 
00448         // create right skirt vertices
00449         c=numColumns-1;
00450         for(r=0;r<static_cast<int>(numRows);++r)
00451         {
00452             int orig_i = indices[(r)*numColumns+c]; // index of original vertex of grid
00453             if (orig_i>=0)
00454             {
00455                 unsigned int new_i = vertices->size(); // index of new index of added skirt point
00456                 osg::Vec3 new_v = (*vertices)[orig_i] - ((*skirtVectors)[orig_i])*skirtHeight;
00457                 (*vertices).push_back(new_v);
00458                 if (normals.valid()) (*normals).push_back((*normals)[orig_i]);
00459                 skirtDrawElements->push_back(orig_i);
00460                 skirtDrawElements->push_back(new_i);
00461             }
00462             else
00463             {
00464                 if (!skirtDrawElements->empty())
00465                 {
00466                     geometry->addPrimitiveSet(skirtDrawElements.get());
00467                     skirtDrawElements = new osg::DrawElementsUShort(GL_QUAD_STRIP);
00468                 }
00469                 
00470             }
00471         }
00472 
00473         if (!skirtDrawElements->empty())
00474         {
00475             geometry->addPrimitiveSet(skirtDrawElements.get());
00476             skirtDrawElements = new osg::DrawElementsUShort(GL_QUAD_STRIP);
00477         }
00478 
00479         // create top skirt vertices
00480         r=numRows-1;
00481         for(c=numColumns-1;c>=0;--c)
00482         {
00483             int orig_i = indices[(r)*numColumns+c]; // index of original vertex of grid
00484             if (orig_i>=0)
00485             {
00486                 unsigned int new_i = vertices->size(); // index of new index of added skirt point
00487                 osg::Vec3 new_v = (*vertices)[orig_i] - ((*skirtVectors)[orig_i])*skirtHeight;
00488                 (*vertices).push_back(new_v);
00489                 if (normals.valid()) (*normals).push_back((*normals)[orig_i]);
00490                 skirtDrawElements->push_back(orig_i);
00491                 skirtDrawElements->push_back(new_i);
00492             }
00493             else
00494             {
00495                 if (!skirtDrawElements->empty())
00496                 {
00497                     geometry->addPrimitiveSet(skirtDrawElements.get());
00498                     skirtDrawElements = new osg::DrawElementsUShort(GL_QUAD_STRIP);
00499                 }
00500                 
00501             }
00502         }
00503 
00504         if (!skirtDrawElements->empty())
00505         {
00506             geometry->addPrimitiveSet(skirtDrawElements.get());
00507             skirtDrawElements = new osg::DrawElementsUShort(GL_QUAD_STRIP);
00508         }
00509 
00510         // create left skirt vertices
00511         c=0;
00512         for(r=numRows-1;r>=0;--r)
00513         {
00514             int orig_i = indices[(r)*numColumns+c]; // index of original vertex of grid
00515             if (orig_i>=0)
00516             {
00517                 unsigned int new_i = vertices->size(); // index of new index of added skirt point
00518                 osg::Vec3 new_v = (*vertices)[orig_i] - ((*skirtVectors)[orig_i])*skirtHeight;
00519                 (*vertices).push_back(new_v);
00520                 if (normals.valid()) (*normals).push_back((*normals)[orig_i]);
00521                 skirtDrawElements->push_back(orig_i);
00522                 skirtDrawElements->push_back(new_i);
00523             }
00524             else
00525             {
00526                 if (!skirtDrawElements->empty())
00527                 {
00528                     geometry->addPrimitiveSet(skirtDrawElements.get());
00529                     skirtDrawElements = new osg::DrawElementsUShort(GL_QUAD_STRIP);
00530                 }
00531                 
00532             }
00533         }
00534 
00535         if (!skirtDrawElements->empty())
00536         {
00537             geometry->addPrimitiveSet(skirtDrawElements.get());
00538             skirtDrawElements = new osg::DrawElementsUShort(GL_QUAD_STRIP);
00539         }
00540     }
00541 
00542 
00543     geometry->setUseDisplayList(false);
00544     geometry->setUseVertexBufferObjects(true);
00545 
00546         return geometry;
00547 }
00548 
00549 osg::Geode* MultiPassTerrainTechnique::createPass(unsigned int            order,
00550                                                   const CustomColorLayer* colorLayer,
00551                                                   osgTerrain::Locator*    masterLocator,
00552                                                   const osg::Vec3d&       centerModel,
00553                                                   osg::Geometry*          geometry)
00554 {
00555         OE_DEBUG << "osgEarth::MultiPassTerrainTechnique createPass " << order << std::endl;
00556     unsigned int binNumber = 1000;
00557     binNumber += order;
00558    
00559     osgTerrain::Layer* elevationLayer = _tile->getElevationLayer();
00560 
00561     //Create a new geode to store the geometry
00562     osg::Geode* geode = new osg::Geode;
00563    
00564     //Set up the pass 
00565     geode->getOrCreateStateSet()->setRenderBinDetails(binNumber, "RenderBin");
00566     geode->addDrawable(geometry);
00567 
00568     unsigned int numRows = 20;
00569     unsigned int numColumns = 20;
00570     
00571     if (elevationLayer)
00572     {
00573         numColumns = elevationLayer->getNumColumns();
00574         numRows = elevationLayer->getNumRows();
00575     }
00576     
00577     float sampleRatio = _tile->getTerrain() ? _tile->getTerrain()->getSampleRatio() : 1.0f;
00578     
00579     double i_sampleFactor = 1.0;
00580     double j_sampleFactor = 1.0;
00581 
00582     // OE_NOTICE<<"Sample ratio="<<sampleRatio<<std::endl;
00583 
00584     if (sampleRatio!=1.0f)
00585     {
00586     
00587         unsigned int originalNumColumns = numColumns;
00588         unsigned int originalNumRows = numRows;
00589     
00590         numColumns = osg::maximum((unsigned int) (float(originalNumColumns)*sqrtf(sampleRatio)), 4u);
00591         numRows = osg::maximum((unsigned int) (float(originalNumRows)*sqrtf(sampleRatio)),4u);
00592 
00593         i_sampleFactor = double(originalNumColumns-1)/double(numColumns-1);
00594         j_sampleFactor = double(originalNumRows-1)/double(numRows-1);
00595     }
00596 
00597     //bool treatBoundariesToValidDataAsDefaultValue = _terrainTile->getTreatBoundariesToValidDataAsDefaultValue();
00598     //OE_DEBUG<<"TreatBoundariesToValidDataAsDefaultValue="<<treatBoundariesToValidDataAsDefaultValue<<std::endl;
00599     
00600     float skirtHeight = 0.0f;
00601     osgTerrain::HeightFieldLayer* hfl = dynamic_cast<osgTerrain::HeightFieldLayer*>(elevationLayer);
00602     if (hfl && hfl->getHeightField()) 
00603     {
00604         skirtHeight = hfl->getHeightField()->getSkirtHeight();
00605     }
00606     
00607     bool createSkirt = skirtHeight != 0.0f;
00608   
00609     unsigned int numVerticesInBody = numColumns*numRows;
00610     unsigned int numVerticesInSkirt = createSkirt ? numColumns*2 + numRows*2 - 4 : 0;
00611     unsigned int numVertices = numVerticesInBody+numVerticesInSkirt;
00612 
00613     //float minHeight = 0.0;
00614     float scaleHeight = _tile->getTerrain() ? _tile->getTerrain()->getVerticalScale() : 1.0f;
00615 
00616     osg::ref_ptr<osg::Vec2Array> texCoords;
00617 
00618     const osgTerrain::Locator* locator = colorLayer ? colorLayer->getLocator() : 0L;
00619     if ( locator )
00620     {
00621         texCoords = new osg::Vec2Array;
00622         texCoords->reserve(numVertices);
00623         _texCompositor->assignTexCoordArray( geometry, colorLayer->getUID(), texCoords.get() );
00624     }
00625 
00626     const osgTerrain::Locator* colorLocator = locator ? locator : masterLocator;
00627 
00628     // allocate and assign color
00629     osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(1);
00630     (*colors)[0].set(1.0f,1.0f,1.0f,1.0f);    
00631     geometry->setColorArray(colors.get());
00632     geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
00633 
00634     typedef std::vector<int> Indices;
00635     Indices indices(numVertices, -1);
00636     
00637     // populate vertex and tex coord arrays
00638     unsigned int i, j;
00639         int vindex = 0;
00640     for(j=0; j<numRows; ++j)
00641     {
00642         for(i=0; i<numColumns; ++i)
00643         {
00644             unsigned int iv = j*numColumns + i;
00645             osg::Vec3d ndc( ((double)i)/(double)(numColumns-1), ((double)j)/(double)(numRows-1), 0.0);
00646      
00647             bool validValue = true;
00648 
00649             unsigned int i_equiv = i_sampleFactor==1.0 ? i : (unsigned int) (double(i)*i_sampleFactor);
00650             unsigned int j_equiv = i_sampleFactor==1.0 ? j : (unsigned int) (double(j)*j_sampleFactor);
00651             
00652             if (elevationLayer)
00653             {
00654                 float value = 0.0f;
00655                 validValue = elevationLayer->getValidValue(i_equiv,j_equiv, value);
00656                 // OE_INFO<<"i="<<i<<" j="<<j<<" z="<<value<<std::endl;
00657                 ndc.z() = value*scaleHeight;
00658             }
00659             
00660             if (validValue)
00661             {
00662                 indices[iv] = vindex++;
00663 
00664                                 if (texCoords.valid())
00665                                 {
00666                                         osg::Vec3d model;
00667                                         masterLocator->convertLocalToModel(ndc, model);
00668 
00669                                         if (colorLocator != masterLocator)
00670                                         {
00671                                                 osg::Vec3d color_ndc;
00672                                                 osgTerrain::Locator::convertLocalCoordBetween(*masterLocator, ndc, *colorLocator, color_ndc);
00673                                                 texCoords->push_back(osg::Vec2(color_ndc.x(), color_ndc.y()));
00674                                         }
00675                                         else
00676                                         {
00677                                                 texCoords->push_back(osg::Vec2(ndc.x(), ndc.y()));
00678                                         }
00679                                 }
00680                         }
00681             else
00682             {
00683                 indices[iv] = -1;
00684             }
00685         }
00686     }
00687     
00688     // populate primitive sets
00689 //    bool optimizeOrientations = elevations!=0;
00690 //    bool swapOrientation = !(masterLocator->orientationOpenGL());    
00691 
00692     if (createSkirt)
00693     {
00694          // create bottom skirt vertices
00695         int r,c;
00696         r=0;
00697         for(c=0;c<static_cast<int>(numColumns);++c)
00698         {
00699             int orig_i = indices[(r)*numColumns+c]; // index of original vertex of grid
00700             if (orig_i>=0)
00701             {
00702                 if (texCoords.valid()) texCoords->push_back((*texCoords)[orig_i]);               
00703             }
00704         }
00705 
00706         // create right skirt vertices
00707         c=numColumns-1;
00708         for(r=0;r<static_cast<int>(numRows);++r)
00709         {
00710             int orig_i = indices[(r)*numColumns+c]; // index of original vertex of grid
00711             if (orig_i>=0)
00712             {
00713                  if (texCoords.valid()) texCoords->push_back((*texCoords)[orig_i]);
00714             }
00715         }
00716 
00717         // create top skirt vertices
00718         r=numRows-1;
00719         for(c=numColumns-1;c>=0;--c)
00720         {
00721             int orig_i = indices[(r)*numColumns+c]; // index of original vertex of grid
00722             if (orig_i>=0)
00723             {
00724                 if (texCoords.valid()) texCoords->push_back((*texCoords)[orig_i]);               
00725             }
00726         }
00727 
00728         // create left skirt vertices
00729         c=0;
00730         for(r=numRows-1;r>=0;--r)
00731         {
00732             int orig_i = indices[(r)*numColumns+c]; // index of original vertex of grid
00733             if (orig_i>=0)
00734             {
00735                 if (texCoords.valid()) texCoords->push_back((*texCoords)[orig_i]);               
00736             }
00737         }
00738     }
00739 
00740     geometry->setUseDisplayList(false);
00741     geometry->setUseVertexBufferObjects(true);
00742 
00743         //TODO:  Should we do this for each geode?  
00744     if (osgDB::Registry::instance()->getBuildKdTreesHint()==osgDB::ReaderWriter::Options::BUILD_KDTREES &&
00745         osgDB::Registry::instance()->getKdTreeBuilder())
00746     {    
00747         //osg::Timer_t before = osg::Timer::instance()->tick();
00748         //OE_NOTICE<<"osgTerrain::GeometryTechnique::build kd tree"<<std::endl;
00749         osg::ref_ptr<osg::KdTreeBuilder> builder = osgDB::Registry::instance()->getKdTreeBuilder()->clone();
00750         //buffer._geode->accept(*builder);
00751         geode->accept(*builder);
00752         //osg::Timer_t after = osg::Timer::instance()->tick();
00753         //OE_NOTICE<<"KdTree build time "<<osg::Timer::instance()->delta_m(before, after)<<std::endl;
00754     }
00755 
00756 
00757     //Apply the appropriate color layer to the pass
00758 
00759     if (colorLayer)
00760     {
00761         const osg::Image* image = colorLayer->getImage();
00762         if (image)
00763         {
00764             //osgTerrain::ImageLayer* imageLayer = dynamic_cast<osgTerrain::ImageLayer*>(colorLayer);
00765             //osgTerrain::ContourLayer* contourLayer = dynamic_cast<osgTerrain::ContourLayer*>(colorLayer);
00766             //if (imageLayer)
00767             //{
00768 
00769                 osg::StateSet* stateset = geode->getOrCreateStateSet();
00770 
00771                 //Compress the image if it's not compressed and it is requested that we compress textures
00772 
00773                 osg::Image* img = const_cast<osg::Image*>(image);
00774 
00775                 osg::Texture2D* texture2D = new osg::Texture2D;
00776                 texture2D->setImage( img );
00777                 texture2D->setMaxAnisotropy(16.0f);
00778                 texture2D->setResizeNonPowerOfTwoHint(false);
00779 
00780                 texture2D->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR );
00781                 if (ImageUtils::isPowerOfTwo( img ) && !(!img->isMipmap() && ImageUtils::isCompressed(img)))
00782                 {
00783                     texture2D->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR );
00784                 }
00785                 else
00786                 {
00787                     OE_DEBUG<<"[osgEarth::MultiPassTerrainTechnique] Disabling mipmapping for non power of two tile size("<<image->s()<<", "<<image->t()<<")"<<std::endl;
00788                     texture2D->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR );
00789                 }
00790 
00791                 texture2D->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE);
00792                 texture2D->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE);
00793                 stateset->setTextureAttributeAndModes(0, texture2D, osg::StateAttribute::ON);           
00794         }
00795         //    }
00796         //    else if (contourLayer)
00797         //    {
00798         //        osg::StateSet* stateset = geode->getOrCreateStateSet();
00799 
00800         //        osg::Texture1D* texture1D = new osg::Texture1D;
00801         //        texture1D->setImage(image);
00802         //        texture1D->setResizeNonPowerOfTwoHint(false);
00803         //        texture1D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
00804         //        texture1D->setFilter(osg::Texture::MAG_FILTER, colorLayer->getMagFilter());            
00805         //        stateset->setTextureAttributeAndModes(0, texture1D, osg::StateAttribute::ON);
00806         //    }
00807         //}
00808     }
00809 
00810     //geode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
00811     geode->getOrCreateStateSet()->setAttributeAndModes(new osg::Depth(osg::Depth::LEQUAL), osg::StateAttribute::ON);
00812 
00813     return geode;
00814 }
00815 
00816 void MultiPassTerrainTechnique::generateGeometry(osgTerrain::Locator* masterLocator, const osg::Vec3d& centerModel)
00817 {
00818     _passes = new osg::Group;
00819     if (_transform.valid())
00820     {
00821         _transform->removeChildren( 0, _transform->getNumChildren() );
00822         _transform->addChild(_passes.get());
00823     }
00824 
00825     typedef std::map<int, osg::ref_ptr<osg::Geode> > OrderedGeodes;
00826     OrderedGeodes order;
00827 
00828         osg::ref_ptr<osg::Geometry> prototype = createGeometryPrototype( masterLocator, centerModel );
00829 
00830     // take a thread-safe snapshot of the layer stack:
00831     TileFrame tilef( _tile );
00832 
00833     if ( tilef._colorLayers.size() == 0 )
00834     {
00835         // if there's no data, just make a placeholder pass
00836                 osg::Geode* geode = createPass(0, 0L, masterLocator, centerModel, prototype.get());
00837                 _passes->addChild( geode );
00838         }
00839     else
00840     {
00841         int defaultLayerOrder = 0;
00842 
00843         // create a pass for each layer, and then add them in the proper order:
00844         for( ColorLayersByUID::const_iterator i = tilef._colorLayers.begin(); i != tilef._colorLayers.end(); ++i )
00845         {
00846             const CustomColorLayer& layer = i->second;
00847             osg::Geometry* passGeom = new osg::Geometry( *prototype.get() );
00848             int index = _texCompositor->getRenderOrder( layer.getUID() );
00849             if ( index < 0 ) // true on first-time initialization
00850                 index = defaultLayerOrder++;
00851             osg::Geode* geode = createPass( index, &layer, masterLocator, centerModel, passGeom );
00852             order[index] = geode;
00853 
00854             // record the UID in the geode for lookup later:
00855             geode->setUserData( new LayerData( layer.getUID() ) );
00856         }            
00857 
00858         for( OrderedGeodes::const_iterator j = order.begin(); j != order.end(); ++j )
00859         {
00860             _passes->addChild( j->second.get() );
00861         }
00862     }
00863 
00864     osg::StateSet* stateset = _transform->getOrCreateStateSet();
00865     stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
00866     stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
00867 }
00868 
00869 void MultiPassTerrainTechnique::traverse(osg::NodeVisitor& nv)
00870 {
00871     if (!_tile) return;
00872 
00873     // initialize the terrain tile on startup
00874     if (_tile->getDirty() && !_terrainTileInitialized) 
00875     {
00876         _tile->init();
00877         _terrainTileInitialized = true;
00878 
00879 #if 0
00880 #if OSG_MIN_VERSION_REQUIRED(2,9,8)
00881         _terrainTile->init(~0x0, true);
00882 #else
00883         _terrainTile->init();
00884 #endif
00885 
00886         _terrainTileInitialized = true;
00887 #endif
00888     }
00889     
00890     if ( nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR )
00891     {
00892         updateTransparency();
00893     }
00894 
00895     // traverse the dynamically-generated geometry.
00896     if (_transform.valid()) 
00897         _transform->accept(nv);
00898 }
00899 
00900 void MultiPassTerrainTechnique::updateTransparency()
00901 {       
00902     if ( _passes.valid() )
00903     {
00904         ColorLayersByUID colorLayers;
00905         _tile->getCustomColorLayers( colorLayers );
00906 
00907         for( ColorLayersByUID::const_iterator i = colorLayers.begin(); i != colorLayers.end(); ++i )
00908         {
00909             const CustomColorLayer& colorLayer = i->second;
00910 
00911             float opacity = colorLayer.getMapLayer()->getOpacity();
00912             osg::Geode* geode = s_findGeodeByUID( _passes.get(), colorLayer.getUID() );
00913                         if (geode)
00914                         {
00915                                 osg::Geometry* geometry = geode->getDrawable(0)->asGeometry();
00916                                 osg::Vec4Array* colors = static_cast<osg::Vec4Array*>(geometry->getColorArray());
00917                 if ( (*colors)[0].a() != opacity )
00918                 {
00919                                     (*colors)[0] = osg::Vec4(1.0f, 1.0f, 1.0f, opacity);
00920                     colors->dirty();
00921                 }
00922 
00923                                 if (colorLayer.getMapLayer()->getEnabled())
00924                                 {
00925                                         geode->setNodeMask(0xffffffff);
00926                                 }
00927                                 else
00928                                 {
00929                                         geode->setNodeMask(0x0);
00930                                 }
00931                         }
00932                 }
00933         }
00934 }
00935 
00936 void MultiPassTerrainTechnique::releaseGLObjects(osg::State* state) const
00937 {
00938     if (_transform.valid()) _transform->releaseGLObjects( state );
00939 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines