terrainpatch.cc
来自「机器人人3D仿真工具,可以加入到Simbad仿真环境下应用。」· CC 代码 · 共 478 行
CC
478 行
/* * Gazebo - Outdoor Multi-Robot Simulator * Copyright (C) 2003 * Nate Koenig & Andrew Howard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *//* Desc: A single patch of terrain * Author: Nate Keonig * Date: 30 April 2004 * CVS: $Id: TerrainPatch.cc,v 1.9 2004/11/15 17:11:45 natepak Exp $ *//*#ifdef HAVE_CONFIG_H#include "config.h"#endif*/#include <float.h>#include "Terrain.hh"#include "TerrainPatch.hh"//////////////////////////////////////////////////////////////////////////////// ConstructorTerrainPatch::TerrainPatch( unsigned int size, double err, GLfloat *vertices ) : errBound(err), tessLevel(0), vertices(vertices){ int i=0; // Size of the square patch (just on side) this->size = size; this->allIndices = new int[this->size*this->size]; // Indices used for rendering this->numFinalIndices = 0; this->maxFinalIndices = this->size; this->finalIndices = (GLuint*) malloc( this->maxFinalIndices * sizeof(this->finalIndices[0])); for (i=0; i<4; i++) this->neighbors[i] = NULL; this->minCoordsX = FLT_MAX; this->minCoordsY = FLT_MAX; this->minCoordsZ = FLT_MAX; this->maxCoordsX = -FLT_MAX; this->maxCoordsY = -FLT_MAX; this->maxCoordsZ = -FLT_MAX;}//////////////////////////////////////////////////////////////////////////////// DestructorTerrainPatch::~TerrainPatch(){ if (this->finalIndices) free(this->finalIndices); delete [] this->allIndices;}//////////////////////////////////////////////////////////////////////////////// Initialize the patch.void TerrainPatch::Init(){ float heightTopLeft, heightTopRight, heightBottomRight, heightBottomLeft; float tessHeight; unsigned int x0,y0,xi,yi,x,y, totErr, skip; float distFromLeft, distFromRight, distFromTop, distFromBottom; float sumErr; int numErrors = (int)sqrt(this->size)+1; float *errors = new float[numErrors]; for (int i=0; i<numErrors; i++) errors[i] = 0; // Calculate height errors for each tesselation level for (int i=1; i<numErrors; i++) { tessHeight =0; skip = (int)pow(2,i); sumErr = 0; totErr = 0; for (y0=0; y0<this->size-skip; y0+=skip) { for (x0=0; x0<this->size-skip; x0+=skip) { for (yi=1; yi<skip; yi++) { for (xi=1; xi<skip; xi++) { x = xi + x0; y = yi + y0; // Precentage distances from each side of the enclosing box distFromLeft = (float)xi / (float)skip; distFromRight = 1-distFromLeft; distFromTop = (float)yi / (float)skip; distFromBottom = 1-distFromTop; // Heights, moving clockwise around the square starting from the // top left. heightTopLeft = this->GetVertexPosZ( this->allIndices[y0*this->size+x0]); heightTopRight = this->GetVertexPosZ( this->allIndices[y0*this->size+x0+skip]); heightBottomRight = this->GetVertexPosZ( this->allIndices[(y0+skip)*this->size+x0+skip]); heightBottomLeft = this->GetVertexPosZ( this->allIndices[(y0+skip)*this->size+x0]); // The height of the triangle above/below this vertex(x,y) // when rendered at this (i) tesselation level. tessHeight = distFromLeft * distFromTop * heightTopLeft + distFromRight * distFromTop * heightTopRight + distFromRight * distFromBottom * heightBottomRight + distFromLeft * distFromBottom * heightBottomLeft; sumErr += fabs(this->GetVertexPosZ(this->allIndices[y*this->size+x]) - tessHeight); totErr++; } } } } errors[i] = sumErr / totErr; } // Find the appropriate tesselation level for (int i=0; i<numErrors; i++) { if (errors[i] < this->errBound) this->tessLevel=i; } delete [] errors;}//////////////////////////////////////////////////////////////////////////////// Attach a neighbor to a directionvoid TerrainPatch::SetNeighbor( TerrainPatch *neigh, Direction dir){ this->neighbors[dir] = neigh;}//////////////////////////////////////////////////////////////////////////////// Set the vertex index for the local x,y coordinate inside the patchvoid TerrainPatch::SetVertex(short x, short y, unsigned int vertex){ this->allIndices[y*this->size+x] = vertex; double coordX = this->GetVertexPosX(vertex); double coordY = this->GetVertexPosY(vertex); double coordZ = this->GetVertexPosZ(vertex); // Min and max vertex coordinates if (coordX < this->minCoordsX) this->minCoordsX = coordX; if (coordX > this->maxCoordsX) this->maxCoordsX = coordX; if (coordY < this->minCoordsY) this->minCoordsY = coordY; if (coordY > this->maxCoordsY) this->maxCoordsY = coordY; if (coordZ < this->minCoordsZ) this->minCoordsZ = coordZ; if (coordZ > this->maxCoordsZ) this->maxCoordsZ = coordZ;}//////////////////////////////////////////////////////////////////////////////// Create the triangle strip for this patchvoid TerrainPatch::CreateStrip(unsigned int index, IndexList *indexList, IndexList *odeIndexList, bool &facing){ unsigned int x,y; int i=0; int skip = (int)pow(2,this->tessLevel); int v[6]; // Adjust the border allIndices to fix any gaps this->FixBorders(); for (y=0; y< this->size-1; y+=skip) { // Need to double-up the beginning vertex of each row other than the // first and last. This creates degenerate triangles used to stich // together the rows of the patch if (y>0 || index > 0) { this->AddStripIndex(this->allIndices[(y+skip)*this->size], indexList); } // Generate the indices for (x=0; x<this->size; x+=skip) { if (x+skip < this->size) { v[0] = this->allIndices[(y+skip)*this->size+x]; v[1] = this->allIndices[y*this->size+x]; v[2] = this->allIndices[(y+skip)*this->size+x+skip]; v[3] = this->allIndices[(y+skip)*this->size+x+skip]; v[4] = this->allIndices[y*this->size+x]; v[5] = this->allIndices[y*this->size+x+skip]; if (this->IsValidTriangle(v[0], v[1], v[2])) for (i=0;i<3;i++) odeIndexList->Push(v[i]); if (this->IsValidTriangle(v[3], v[4], v[5])) for (i=3;i<6;i++) odeIndexList->Push(v[i]); } this->AddStripIndex(this->allIndices[(y+skip)*this->size+x], indexList); this->AddStripIndex(this->allIndices[y*this->size+x], indexList); if (x+skip > this->size-1) this->AddStripIndex(this->allIndices[y*this->size+x], indexList); } } // Calculate the normals for (i=0; i<this->numFinalIndices-3; i++) { if (this->IsValidTriangle(this->finalIndices[i], this->finalIndices[i+1],this->finalIndices[i+2])) { // Triangles alternate rotation. // Calculate normal for each triangle and add the normal to the // triangle's allIndices if (facing) this->CalcNormal(this->finalIndices[i], this->finalIndices[i+2], this->finalIndices[i+1]); else this->CalcNormal(this->finalIndices[i], this->finalIndices[i+1], this->finalIndices[i+2]); } facing = !facing; } facing = !facing;}//////////////////////////////////////////////////////////////////////////////// Return the tesselation levelunsigned short TerrainPatch::GetTessLevel(){ return this->tessLevel;}//////////////////////////////////////////////////////////////////////////////// Adjust the border allIndices to fix any gapsvoid TerrainPatch::FixBorders(){ int mySkip = (int)pow(2,this->tessLevel); int neighSkip = mySkip; int x,y; int idist; float fdist; // Fix the TOP border of the top neighbor has coarser tesselation level if (this->neighbors[TOP] && this->neighbors[TOP]->GetTessLevel() > this->tessLevel) { neighSkip = (int)pow(2,this->neighbors[TOP]->GetTessLevel()); y=this->size-1; for (x=this->size-1; x>=0; x-=mySkip) { fdist = (float)x/neighSkip; idist = (int)(x/neighSkip); if ( fdist != idist) { if (fabs(idist-fdist)<=.5) { this->allIndices[y*this->size+x] = this->allIndices[(y*this->size+(idist*neighSkip - x))+x]; } else { this->allIndices[y*this->size+x] = this->allIndices[(y*this->size+((idist+1)*neighSkip - x))+x]; } } } } // Fix the RIGHT border of the top neighbor has coarser tesselation level if (this->neighbors[RIGHT] && this->neighbors[RIGHT]->GetTessLevel() > this->tessLevel) { neighSkip = (int)pow(2,this->neighbors[RIGHT]->GetTessLevel()); x=this->size-1; for (y=mySkip; y<(int)(this->size); y+=mySkip) { fdist = (float)y/neighSkip; idist = (int)(y/neighSkip); if ( fdist != idist) { if (fabs(idist-fdist)<=.5) { this->allIndices[y*this->size+x] = this->allIndices[(y+(idist*neighSkip - y))*this->size+x]; } else { this->allIndices[y*this->size+x] = this->allIndices[(y+((idist+1)*neighSkip - y))*this->size+x]; } } } } // Fix the BOTTOM border of the top neighbor has coarser tesselation level if (this->neighbors[BOTTOM] && this->neighbors[BOTTOM]->GetTessLevel() > this->tessLevel) { neighSkip = (int)pow(2,this->neighbors[BOTTOM]->GetTessLevel()); y=0; for (x=this->size-1; x>=0; x-=mySkip) { fdist = (float)x/neighSkip; idist = (int)(x/neighSkip); if ( fdist != idist) { if (fabs(idist-fdist)<=.5) { this->allIndices[y*this->size+x] = this->allIndices[(y*this->size+(idist*neighSkip - x))+x]; } else { this->allIndices[y*this->size+x] = this->allIndices[(y*this->size+((idist+1)*neighSkip - x))+x]; } } } } // Fix the LEFT border of the top neighbor has coarser tesselation level if (this->neighbors[LEFT] && this->neighbors[LEFT]->GetTessLevel() > this->tessLevel) { neighSkip = (int)pow(2,this->neighbors[LEFT]->GetTessLevel()); x=0; for (y=mySkip; y<(int)(this->size); y+=mySkip) { fdist = (float)y/neighSkip; idist = (int)(y/neighSkip); if ( fdist != idist) { if (fabs(idist-fdist)<=.5) { this->allIndices[y*this->size+x] = this->allIndices[(y+(idist*neighSkip - y))*this->size+x]; } else { this->allIndices[y*this->size+x] = this->allIndices[(y+((idist+1)*neighSkip - y))*this->size+x]; } } } }}//////////////////////////////////////////////////////////////////////////////// Triangle is valid (not degenerate) if the points do not coincidebool TerrainPatch::IsValidTriangle( int i1, int i2, int i3 ){ return i1 != i2 && i1!=i3 && i2!=i3;}//////////////////////////////////////////////////////////////////////////////// Add a vertex to the index arrayvoid TerrainPatch::AddStripIndex(unsigned int index, IndexList *indexList){ if (this->numFinalIndices >= this->maxFinalIndices) { this->maxFinalIndices += 10; this->finalIndices = (GLuint*) realloc( this->finalIndices, this->maxFinalIndices * sizeof(this->finalIndices[0])); } this->finalIndices[this->numFinalIndices++] = index; indexList->Push(index);}//////////////////////////////////////////////////////////////////////////////// Render this patchvoid TerrainPatch::Render(){ //glDrawElements( GL_TRIANGLE_STRIP, this->numFinalIndices , GL_UNSIGNED_INT, this->finalIndices );}//////////////////////////////////////////////////////////////////////////////// Return the X Coord of the vertex[index]double TerrainPatch::GetVertexPosX(unsigned int index){ return this->vertices[index*12+9];}//////////////////////////////////////////////////////////////////////////////// Return the Y Coord of the vertex[index]double TerrainPatch::GetVertexPosY(unsigned int index){ return this->vertices[index*12+10];}//////////////////////////////////////////////////////////////////////////////// Return the Z Coord of the vertex[index]double TerrainPatch::GetVertexPosZ(unsigned int index){ return this->vertices[index*12+11];}//////////////////////////////////////////////////////////////////////////////// Calcuate the normal for a single trianglevoid TerrainPatch::CalcNormal(unsigned int one, unsigned int two, unsigned int three){ double aX, aY, aZ; double bX, bY, bZ; double normX, normY, normZ; aX = this->vertices[one*12+9] - this->vertices[two*12+9]; aY = this->vertices[one*12+10] - this->vertices[two*12+10]; aZ = this->vertices[one*12+11] - this->vertices[two*12+11]; bX = this->vertices[one*12+9] - this->vertices[three*12+9]; bY = this->vertices[one*12+10] - this->vertices[three*12+10]; bZ = this->vertices[one*12+11] - this->vertices[three*12+11]; // Cross Product normX = aY * bZ - aZ * bY; normY = -aX * bZ + aZ * bX; normZ = aX * bY - aY * bX; this->vertices[one*12+6] += normX; this->vertices[one*12+7] += normY; this->vertices[one*12+8] += normZ; this->vertices[two*12+6] += normX; this->vertices[two*12+7] += normY; this->vertices[two*12+8] += normZ; this->vertices[three*12+6] += normX; this->vertices[three*12+7] += normY; this->vertices[three*12+8] += normZ;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?