Vec3D CSceneData::getVertexNormal(int x, int y)const { float a = getVertexHeight(x, y); float b = getVertexHeight(x, y+1); float c = getVertexHeight(x+1, y); Vec3D vVector0(0,(b-a),1); Vec3D vVector1(1,(c-a),0); Vec3D vN = vVector0.cross(vVector1); return vN.normalize(); }
Vec3D CTerrainData::getVertexNormal(int nCellX, int nCellY)const { float a = getVertexHeight(nCellX, nCellY); float b = getVertexHeight(nCellX, nCellY+1); float c = getVertexHeight(nCellX+1, nCellY); Vec3D vVector0(0,(b-a),1); Vec3D vVector1(1,(c-a),0); Vec3D vN = vVector0.cross(vVector1); return vN.normalize(); }
float CSceneData::getHeight(float fX, float fY)const { int nCellX = fX; int nCellY = fY; float u = fX - nCellX; float v = fY - nCellY; float a = getVertexHeight(nCellX, nCellY); float b = getVertexHeight(nCellX+1, nCellY); float c = getVertexHeight(nCellX, nCellY+1); float d = getVertexHeight(nCellX+1, nCellY+1); return bilinearInterpolation(a,b,c,d,u,v); }
//--------------------------------------------------------------------------- float Terrain::getLowestVertex( long& tileR, long& tileC ) { float lowest = 9999999.; // an absurdly big number for ( int i = 0; i < realVerticesMapSide * realVerticesMapSide; ++i ) { float tmp = getVertexHeight( i ); if ( tmp < lowest ) { lowest = tmp; tileR = i/realVerticesMapSide; tileC = i % realVerticesMapSide; } } return lowest; }
//--------------------------------------------------------------------------- float Terrain::getHighestVertex( long& tileR, long& tileC ) { float highest = -9999999.; // an absurdly small number for ( int i = 0; i < realVerticesMapSide * realVerticesMapSide; ++i ) { float tmp = getVertexHeight( i ); if ( tmp > highest ) { highest = tmp; tileR = i/realVerticesMapSide; tileC = i % realVerticesMapSide; } } return highest; }
float Storage::getHeightAt(const osg::Vec3f &worldPos) { int cellX = static_cast<int>(std::floor(worldPos.x() / 8192.f)); int cellY = static_cast<int>(std::floor(worldPos.y() / 8192.f)); ESM::Land* land = getLand(cellX, cellY); if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) return -2048; // Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition // Normalized position in the cell float nX = (worldPos.x() - (cellX * 8192))/8192.f; float nY = (worldPos.y() - (cellY * 8192))/8192.f; // get left / bottom points (rounded down) float factor = ESM::Land::LAND_SIZE - 1.0f; float invFactor = 1.0f / factor; int startX = static_cast<int>(nX * factor); int startY = static_cast<int>(nY * factor); int endX = startX + 1; int endY = startY + 1; endX = std::min(endX, ESM::Land::LAND_SIZE-1); endY = std::min(endY, ESM::Land::LAND_SIZE-1); // now get points in terrain space (effectively rounding them to boundaries) float startXTS = startX * invFactor; float startYTS = startY * invFactor; float endXTS = endX * invFactor; float endYTS = endY * invFactor; // get parametric from start coord to next point float xParam = (nX - startXTS) * factor; float yParam = (nY - startYTS) * factor; /* For even / odd tri strip rows, triangles are this shape: even odd 3---2 3---2 | / | | \ | 0---1 0---1 */ // Build all 4 positions in normalized cell space, using point-sampled height osg::Vec3f v0 (startXTS, startYTS, getVertexHeight(land, startX, startY) / 8192.f); osg::Vec3f v1 (endXTS, startYTS, getVertexHeight(land, endX, startY) / 8192.f); osg::Vec3f v2 (endXTS, endYTS, getVertexHeight(land, endX, endY) / 8192.f); osg::Vec3f v3 (startXTS, endYTS, getVertexHeight(land, startX, endY) / 8192.f); // define this plane in terrain space osg::Plane plane; // FIXME: deal with differing triangle alignment if (true) { // odd row bool secondTri = ((1.0 - yParam) > xParam); if (secondTri) plane = osg::Plane(v0, v1, v3); else plane = osg::Plane(v1, v2, v3); } /* else { // even row bool secondTri = (yParam > xParam); if (secondTri) plane.redefine(v0, v2, v3); else plane.redefine(v0, v1, v2); } */ // Solve plane equation for z return (-plane.getNormal().x() * nX -plane.getNormal().y() * nY - plane[3]) / plane.getNormal().z() * 8192; }