osgEarth 2.1.1
|
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 }