From 72488d274f21872f2a9eaefed88b9e05049de4a3 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 2 Jul 2005 08:11:55 +0000 Subject: [PATCH] Added support for equalizing the normals along tile boundaries. --- VisualStudio/examples/osgforest/osgforest.dsp | 4 +- include/osg/Shape | 2 + include/osgTerrain/DataSet | 5 + src/osg/Shape.cpp | 36 ++- src/osgGA/UFOManipulator.cpp | 2 - src/osgTerrain/DataSet.cpp | 245 +++++++++++++++++- 6 files changed, 274 insertions(+), 20 deletions(-) diff --git a/VisualStudio/examples/osgforest/osgforest.dsp b/VisualStudio/examples/osgforest/osgforest.dsp index 0a6ba2796..17b9df55b 100755 --- a/VisualStudio/examples/osgforest/osgforest.dsp +++ b/VisualStudio/examples/osgforest/osgforest.dsp @@ -51,7 +51,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 OpenThreadsWin32.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../../../bin/osgforest.exe" /libpath:"../../../lib" /libpath:"../../../../OpenThreads/lib/win32" /libpath:"../../../../Producer/lib" /libpath:"../../../../3rdParty/lib" +# ADD LINK32 OpenThreadsWin32.lib opengl32.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../../../bin/osgforest.exe" /libpath:"../../../lib" /libpath:"../../../../OpenThreads/lib/win32" /libpath:"../../../../Producer/lib" /libpath:"../../../../3rdParty/lib" !ELSEIF "$(CFG)" == "Example osgforest - Win32 Debug" @@ -76,7 +76,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 OpenThreadsWin32d.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libcmt" /out:"../../../bin/osgforestd.exe" /pdbtype:sept /libpath:"../../../lib" /libpath:"../../../../OpenThreads/lib/win32" /libpath:"../../../../Producer/lib" /libpath:"../../../../3rdParty/lib" +# ADD LINK32 OpenThreadsWin32d.lib opengl32.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libcmt" /out:"../../../bin/osgforestd.exe" /pdbtype:sept /libpath:"../../../lib" /libpath:"../../../../OpenThreads/lib/win32" /libpath:"../../../../Producer/lib" /libpath:"../../../../3rdParty/lib" # SUBTRACT LINK32 /incremental:no !ENDIF diff --git a/include/osg/Shape b/include/osg/Shape index ff2371fa1..5be598256 100644 --- a/include/osg/Shape +++ b/include/osg/Shape @@ -568,6 +568,8 @@ class OSG_EXPORT HeightField : public Shape Vec3 getNormal(unsigned int c,unsigned int r) const; + Vec2 getHeightDelta(unsigned int c,unsigned int r) const; + protected: virtual ~HeightField(); diff --git a/include/osgTerrain/DataSet b/include/osgTerrain/DataSet index 905d645a7..65ff44ab6 100644 --- a/include/osgTerrain/DataSet +++ b/include/osgTerrain/DataSet @@ -735,6 +735,8 @@ class OSGTERRAIN_EXPORT DataSet : public osg::Referenced void addRequiredResolutions(CompositeSource* sourceGraph); void readFrom(CompositeSource* sourceGraph); + + void allocateEdgeNormals(); void equalizeCorner(Position position); void equalizeEdge(Position position); @@ -801,6 +803,9 @@ class OSGTERRAIN_EXPORT DataSet : public osg::Referenced float _terrain_maxSourceResolutionY; bool _complete; + + typedef std::vector HeightDeltaList; + HeightDeltaList _heightDeltas[NUMBER_OF_POSITIONS]; }; diff --git a/src/osg/Shape.cpp b/src/osg/Shape.cpp index 75a482043..3ff2c8fd2 100644 --- a/src/osg/Shape.cpp +++ b/src/osg/Shape.cpp @@ -37,8 +37,7 @@ void HeightField::allocate(unsigned int numColumns,unsigned int numRows) Vec3 HeightField::getNormal(unsigned int c,unsigned int r) const { // four point normal generation. - - float dz_dx; + float dz_dx; if (c==0) { dz_dx = (getHeight(c+1,r)-getHeight(c,r))/getXInterval(); @@ -72,4 +71,37 @@ Vec3 HeightField::getNormal(unsigned int c,unsigned int r) const return normal; } +Vec2 HeightField::getHeightDelta(unsigned int c,unsigned int r) const +{ + // four point normal generation. + Vec2 heightDelta; + if (c==0) + { + heightDelta.x() = (getHeight(c+1,r)-getHeight(c,r)); + } + else if (c==getNumColumns()-1) + { + heightDelta.x() = (getHeight(c,r)-getHeight(c-1,r)); + } + else // assume 0_heightField.get(); + if (!hf) return; + +} + + void DataSet::DestinationTile::equalizeCorner(Position position) { // don't need to equalize if already done. @@ -1735,7 +1743,7 @@ void DataSet::DestinationTile::equalizeCorner(Position position) } } - typedef std::pair HeightFieldCornerPair; + typedef std::pair HeightFieldCornerPair; typedef std::vector HeightFieldCornerList; HeightFieldCornerList heightFieldsToProcess; @@ -1746,7 +1754,7 @@ void DataSet::DestinationTile::equalizeCorner(Position position) TileCornerPair& tcp = *itr; if (tcp.first->_terrain.valid() && tcp.first->_terrain->_heightField.valid()) { - heightFieldsToProcess.push_back(HeightFieldCornerPair(tcp.first->_terrain->_heightField.get(),tcp.second)); + heightFieldsToProcess.push_back(HeightFieldCornerPair(tcp.first->_terrain->_heightField.get(),tcp)); } } @@ -1754,26 +1762,31 @@ void DataSet::DestinationTile::equalizeCorner(Position position) if (heightFieldsToProcess.size()>1) { float height = 0; - // accumulate heights. + osg::Vec2 heightDelta; + // accumulate heights & normals HeightFieldCornerList::iterator hitr; for(hitr=heightFieldsToProcess.begin(); hitr!=heightFieldsToProcess.end(); ++hitr) { HeightFieldCornerPair& hfcp = *hitr; - switch(hfcp.second) + switch(hfcp.second.second) { case LEFT_BELOW: height += hfcp.first->getHeight(0,0); + heightDelta += hfcp.first->getHeightDelta(0,0); break; case BELOW_RIGHT: height += hfcp.first->getHeight(hfcp.first->getNumColumns()-1,0); + heightDelta += hfcp.first->getHeightDelta(hfcp.first->getNumColumns()-1,0); break; case RIGHT_ABOVE: height += hfcp.first->getHeight(hfcp.first->getNumColumns()-1,hfcp.first->getNumRows()-1); + heightDelta += hfcp.first->getHeightDelta(hfcp.first->getNumColumns()-1,hfcp.first->getNumRows()-1); break; case ABOVE_LEFT: height += hfcp.first->getHeight(0,hfcp.first->getNumRows()-1); + heightDelta += hfcp.first->getHeightDelta(0,hfcp.first->getNumRows()-1); break; default : break; @@ -1782,14 +1795,17 @@ void DataSet::DestinationTile::equalizeCorner(Position position) // divide them. height /= heightFieldsToProcess.size(); + heightDelta /= heightFieldsToProcess.size(); - // apply height to corners. + + // apply height and normals to corners. for(hitr=heightFieldsToProcess.begin(); hitr!=heightFieldsToProcess.end(); ++hitr) { HeightFieldCornerPair& hfcp = *hitr; - switch(hfcp.second) + TileCornerPair& tcp = hfcp.second; + switch(tcp.second) { case LEFT_BELOW: hfcp.first->setHeight(0,0,height); @@ -1806,6 +1822,8 @@ void DataSet::DestinationTile::equalizeCorner(Position position) default : break; } + tcp.first->_heightDeltas[tcp.second].clear(); + tcp.first->_heightDeltas[tcp.second].push_back(heightDelta); } } @@ -1967,30 +1985,68 @@ void DataSet::DestinationTile::equalizeEdge(Position position) unsigned int delta2 = 0; int num = 0; + unsigned int i1 = 0; + unsigned int j1 = 0; + unsigned int i2 = 0; + unsigned int j2 = 0; + unsigned int deltai = 0; + unsigned int deltaj = 0; + switch(position) { case LEFT: + i1 = 0; + j1 = 1; + i2 = heightField2->getNumColumns()-1; + j2 = 1; + deltai = 0; + deltaj = 1; + data1 = &(heightField1->getHeight(0,1)); // LEFT hand side delta1 = heightField1->getNumColumns(); data2 = &(heightField2->getHeight(heightField2->getNumColumns()-1,1)); // RIGHT hand side delta2 = heightField2->getNumColumns(); num = (heightField1->getNumRows()==heightField2->getNumRows())?heightField1->getNumRows()-2:0; // note miss out corners. break; + case BELOW: + i1 = 1; + j1 = 0; + i2 = 1; + j2 = heightField2->getNumRows()-1; + deltai = 1; + deltaj = 0; + data1 = &(heightField1->getHeight(1,0)); // BELOW hand side delta1 = 1; data2 = &(heightField2->getHeight(1,heightField2->getNumRows()-1)); // ABOVE hand side delta2 = 1; num = (heightField1->getNumColumns()==heightField2->getNumColumns())?heightField1->getNumColumns()-2:0; // note miss out corners. break; + case RIGHT: + i1 = heightField1->getNumColumns()-1; + j1 = 1; + i2 = 0; + j2 = 1; + deltai = 0; + deltaj = 1; + data1 = &(heightField1->getHeight(heightField1->getNumColumns()-1,1)); // LEFT hand side delta1 = heightField1->getNumColumns(); data2 = &(heightField2->getHeight(0,1)); // LEFT hand side delta2 = heightField2->getNumColumns(); num = (heightField1->getNumRows()==heightField2->getNumRows())?heightField1->getNumRows()-2:0; // note miss out corners. break; + case ABOVE: + i1 = 1; + j1 = heightField1->getNumRows()-1; + i2 = 1; + j2 = 0; + deltai = 1; + deltaj = 0; + data1 = &(heightField1->getHeight(1,heightField1->getNumRows()-1)); // ABOVE hand side delta1 = 1; data2 = &(heightField2->getHeight(1,0)); // BELOW hand side @@ -2000,20 +2056,41 @@ void DataSet::DestinationTile::equalizeEdge(Position position) default : break; } + + _heightDeltas[position].clear(); + _heightDeltas[position].reserve(num); + tile2->_heightDeltas[(position+4)%NUMBER_OF_POSITIONS].clear(); + tile2->_heightDeltas[(position+4)%NUMBER_OF_POSITIONS].reserve(num); for(int i=0;igetHeightDelta(i1,j1) + + heightField2->getHeightDelta(i2,j2))*0.5f; + + // pass the normals on to the tiles. + _heightDeltas[position].push_back(heightDelta); + tile2->_heightDeltas[(position+4)%NUMBER_OF_POSITIONS].push_back(heightDelta); + + i1 += deltai; + i2 += deltai; + j1 += deltaj; + j2 += deltaj; + + + } + } } @@ -2486,9 +2563,7 @@ osg::Node* DataSet::DestinationTile::createPolygonal() { skirtVector.set(0.0f,0.0f,-skirtLength); } - - - + unsigned int vi=0; unsigned int r,c; @@ -2556,7 +2631,11 @@ osg::Node* DataSet::DestinationTile::createPolygonal() } // note normal will need rotating. - if (n.valid()) (*(n.get()))[vi] = grid->getNormal(c,r); + if (n.valid()) + { + (*n)[vi] = grid->getNormal(c,r); + + } t[vi].x() = (c==numColumns-1)? 1.0f : (float)(c)/(float)(numColumns-1); t[vi].y() = (r==numRows-1)? 1.0f : (float)(r)/(float)(numRows-1); @@ -2643,7 +2722,7 @@ osg::Node* DataSet::DestinationTile::createPolygonal() } } -#if 1 +#if 1 osgUtil::SmoothingVisitor sv; sv.smooth(*geometry); // this will replace the normal vector with a new one @@ -2651,7 +2730,144 @@ osg::Node* DataSet::DestinationTile::createPolygonal() n = geometry->getNormalArray(); if (n.valid() && n->size()!=numVertices) n->resize(numVertices); #endif + // now apply the normals computed through equalization + for(unsigned int position=0; positiongetHeight(i,j); + osg::Matrixd normalLocalToWorld; + et->computeLocalToWorldTransformFromLatLongHeight(osg::DegreesToRadians(Y),osg::DegreesToRadians(X),Z,normalLocalToWorld); + osg::Matrixd normalToLocalReferenceFrame(normalLocalToWorld*worldToLocal); + + // need to compute the x and y delta for this point in space. + double X0, Y0, Z0; + double X1, Y1, Z1; + double X2, Y2, Z2; + + et->convertLatLongHeightToXYZ(osg::DegreesToRadians(Y),osg::DegreesToRadians(X),Z, + X0,Y0,Z0); + + et->convertLatLongHeightToXYZ(osg::DegreesToRadians(Y),osg::DegreesToRadians(X+delta_X),Z, + X1,Y1,Z1); + + et->convertLatLongHeightToXYZ(osg::DegreesToRadians(Y+delta_Y),osg::DegreesToRadians(X),Z, + X2,Y2,Z2); + + X1 -= X0; + Y1 -= Y0; + Z1 -= Z0; + + X2 -= X0; + Y2 -= Y0; + Z2 -= Z0; + + float xInterval = sqrt(X1*X1 + Y1*Y1 + Z1*Z1); + float yInterval = sqrt(X2*X2 + Y2*Y2 + Z2*Z2); + + // need to set up the normal from the scaled heightDelta. + normal.x() = -heightDelta.x() / xInterval; + normal.y() = -heightDelta.y() / yInterval; + normal.z() = 1.0f; + + normal = osg::Matrixd::transform3x3(normal,normalToLocalReferenceFrame); + normal.normalize(); + + } + else + { + normal.x() = -heightDelta.x() / grid->getXInterval(); + normal.y() = -heightDelta.y() / grid->getYInterval(); + normal.z() = 1.0f; + normal.normalize(); + } + } + + } + + } + +#if 0 + std::cout<<"Normals"<begin(); + nitr != n->end(); + ++nitr) + { + osg::Vec3& normal = *nitr; + std::cout<<" Local normal = "<getBound().radius()/2000.0f); simplifier.simplify(*geometry, pointsToProtectDuringSimplification); // this will replace the normal vector with a new one - +#endif osgUtil::TriStripVisitor tsv; tsv.setMinStripSize(3);