📄 meshshapes.cpp
字号:
#include "MeshShapes.h"
#include <float.h>
Mesh::Mesh()
{
numVerts = numFaces = numNorms = 0;
pt = NULL; norm = NULL; face = NULL;
lastVertUsed = lastNormUsed = lastFaceUsed = -1;
meshFileName = "None";
}
Mesh::Mesh(string fname)
{ // read this file to build mesh
numVerts = numFaces = numNorms = 0;
pt = NULL; norm = NULL; face = NULL;
lastVertUsed = lastNormUsed = lastFaceUsed = -1;
meshFileName = "None";
readMesh(fname);
/*
string OBJName = fname.substr(0, fname.find(".")).append(".obj");
outputOBJ(OBJName); */
}
Mesh::~Mesh() { freeMesh(); }
void Mesh::freeMesh()
{ // free up memory used by this mesh.
delete [] pt; // release whole vertex list
delete [] norm;
for(size_t f = 0; f < numFaces; f++) delete[] face[f].vert; // delete the vert[] array of this face
delete [] face;
}
void Mesh::makeExtentPoints(PointCluster& clust) {}
bool Mesh::hit(Ray &r, Intersection &inter)
{
Ray genRay;
xfrmRay(genRay, r);
inter.numHits=0;
float t, bestHitTime = -1;
VertexID *v, *bestV;
for(size_t p=0; p < numFaces; p++)
{
if(face[p].nVerts != 3) return false;
v = face[p].vert;
float a, b, c, d, e, f, g, h, i, j, k, l;
float M, beta, gama;
a = pt[v[0].vertIndex].x - pt[v[1].vertIndex].x;
b = pt[v[0].vertIndex].y - pt[v[1].vertIndex].y;
c = pt[v[0].vertIndex].z - pt[v[1].vertIndex].z;
d = pt[v[0].vertIndex].x - pt[v[2].vertIndex].x;
e = pt[v[0].vertIndex].y - pt[v[2].vertIndex].y;
f = pt[v[0].vertIndex].z - pt[v[2].vertIndex].z;
g = genRay.getDir().x;
h = genRay.getDir().y;
i = genRay.getDir().z;
j = pt[v[0].vertIndex].x - genRay.getStart().x;
k = pt[v[0].vertIndex].y - genRay.getStart().y;
l = pt[v[0].vertIndex].z - genRay.getStart().z;
M = a*(e*i - h*f) + b*(g*f-d*i) + c*(d*h-e*g);
if(M == 0) continue;
beta = j*(e*i-h*f)+ k*(g*f-d*i)+l*(d*h-e*g);
gama = i*(a*k-j*b)+ h*(j*c-a*l)+g*(b*l-k*c);
t = f*(a*k-j*b) + e*(j*c-a*l)+d*(b*l-k*c);
t *= -1/M;
beta /= M;
gama /= M;
if(beta > 0 && gama > 0 &&(beta+gama) < 1)
{
if(t > 0 && (bestHitTime == -1 || t < bestHitTime))
{
bestHitTime = t;
bestV = v;
}
}
}
if(bestHitTime != -1)
{
v = bestV;
t = bestHitTime;
inter.hit[0].hitTime = t;
inter.hit[0].hitObject = this;
// Compute Point of Intersection
Point3 P(genRay.calculatePointOnRay(t));
inter.hit[0].hitPoint.set(P.x, P.y, P.z);
// Interpolate Normal
Vector3 N;
interpolate(v, P, N);
inter.hit[0].hitNormal.set(N.x, N.y, N.z);
// Fill in reamining hit information
// NOTE: The following two lines are NOT correct.
if(genRay.getDir().dot(N) < 0) inter.hit[0].isEntering = true;
else inter.hit[0].isEntering = false;
inter.hit[0].surface = 0;
inter.numHits = 1;
}
if(inter.numHits == 0) return false;
return true;
}
void Mesh::interpolate(VertexID* v, Point3 P, Vector3 &N)
{
float M[9], m[9], n[3], b[3];
M[0] = pt[v[0].vertIndex].x; M[1] = pt[v[1].vertIndex].x; M[2] = pt[v[2].vertIndex].x;
M[3] = pt[v[0].vertIndex].y; M[4] = pt[v[1].vertIndex].y; M[5] = pt[v[2].vertIndex].y;
M[6] = pt[v[0].vertIndex].z; M[7] = pt[v[1].vertIndex].z; M[8] = pt[v[2].vertIndex].z;
gluInvertMatrixf((GLfloat*)M, (GLfloat*)m, 3);
n[0] = P.x; n[1] = P.y; n[2] = P.z;
b[0] = b[1] = b[2] = 0;
// Multiply m and n and put the result in b
for(int i=0; i<3; i++)
{
for(int j=0; j<3; j++)
b[i] += m[3*i + j]*n[j];
}
// Normalize b
double length = sqrt(b[0]*b[0] + b[1]*b[1] + b[2]*b[2]);
b[0] /= length; b[1] /= length; b[2] /= length;
// B represents P in barycentric coordinates. Multiply the normals at the vertices
// by B to get the interpolated normal.
N.x = b[0]*norm[v[0].normIndex].x + b[1]*norm[v[1].normIndex].x + b[2]*norm[v[2].normIndex].x;
N.y = b[0]*norm[v[0].normIndex].y + b[1]*norm[v[1].normIndex].y + b[2]*norm[v[2].normIndex].y;
N.z = b[0]*norm[v[0].normIndex].z + b[1]*norm[v[1].normIndex].z + b[2]*norm[v[2].normIndex].z;
}
GLvoid Mesh::gluMakeIdentityf(GLfloat m[], int dimension)
{
//First, fill with zeros.
for(int i=0; i<dimension; i++)
for(int j=0; j<dimension; j++)
m[i+dimension*j] = 0.0;
//Second, set the diagonal to ones.
for(int i=0; i<dimension; i++)
m[i + dimension*i] = 1.0;
}
int Mesh::gluInvertMatrixf(GLfloat src[], GLfloat inverse[], int dimension)
{
int i, j, k, swap;
double t;
GLfloat** temp = new GLfloat*[dimension];
for (i=0; i<dimension; i++) {
temp[i] = new GLfloat[dimension];
for (j=0; j<dimension; j++) {
temp[i][j] = src[i*dimension+j];
}
}
gluMakeIdentityf(inverse, dimension);
for (i = 0; i < dimension; i++) {
/*
** Look for largest element in column
*/
swap = i;
for (j = i + 1; j < dimension; j++) {
if (fabs(temp[j][i]) > fabs(temp[i][i])) {
swap = j;
}
}
if (swap != i) {
/*
** Swap rows.
*/
for (k = 0; k < dimension; k++) {
t = temp[i][k];
temp[i][k] = temp[swap][k];
temp[swap][k] = t;
t = inverse[i*dimension+k];
inverse[i*dimension+k] = inverse[swap*dimension+k];
inverse[swap*dimension+k] = t;
}
}
if (temp[i][i] == 0) {
/*
** No non-zero pivot. The matrix is singular, which shouldn't
** happen. This means the user gave us a bad matrix.
*/
for(j=0; j<dimension; j++)
delete [] temp[j];
delete [] temp;
return GL_FALSE;
}
t = temp[i][i];
for (k = 0; k < dimension; k++) {
temp[i][k] /= t;
inverse[i*dimension+k] /= t;
}
for (j = 0; j < dimension; j++) {
if (j != i) {
t = temp[j][i];
for (k = 0; k < dimension; k++) {
temp[j][k] -= temp[i][k]*t;
inverse[j*dimension+k] -= inverse[i*dimension+k]*t;
}
}
}
}
for(i=0; i<dimension; i++)
delete [] temp[i];
delete [] temp;
return GL_TRUE;
}
void Mesh::readMesh(string fname)
{
meshFileName = fname;
bool WARNING = false;
fstream inStream;
inStream.open(fname.c_str(), ios ::in);
if(inStream.fail() || inStream.eof())
{
cout << "Error opening file : " << fname << endl;
makeEmpty();
return;
}
inStream >> numVerts >> numNorms >> numFaces;
// make arrays for vertices, normals, and faces
pt = new Point3[numVerts]; assert(pt != NULL);
norm = new Vector3[numNorms]; assert(norm != NULL);
face = new Face[numFaces]; assert(face != NULL);
for(size_t i = 0; i < numVerts; i++) // read in the vertices
inStream >> pt[i].x >> pt[i].y >> pt[i].z;
for(size_t ii = 0; ii < numNorms; ii++) // read in the normals
inStream >> norm[ii].x >> norm[ii].y >> norm[ii].z;
for(size_t f = 0; f < numFaces; f++) // read in face data
{
inStream >> face[f].nVerts;
if(face[f].nVerts != 3 && !WARNING)
{
// Triangulate the face
cout << "WARNING! Only Triangular Meshes are Supported at this time.\n"
<< "The mesh object defined in '" << fname << "' will not be drawn.\n";
WARNING = true;
}
size_t n = face[f].nVerts;
face[f].vert = new VertexID[n]; assert(face[f].vert != NULL);
for(size_t k = 0; k < n; k++) // read vertex indices for this face
inStream >> face[f].vert[k].vertIndex;
for(size_t kk = 0; kk < n; kk++) // read normal indices for this face
inStream >> face[f].vert[kk].normIndex;
}
inStream.close();
}
void Mesh::writeMesh(char * fname)
{ // write this mesh object into a new Chapter 6 format file.
if(numVerts == 0 || numNorms == 0 || numFaces == 0) return; //empty
fstream outStream(fname, ios ::out); // open the output stream
if(outStream.fail()) {cout << "can't make new file: " << fname << endl; return;}
outStream << numVerts << " " << numNorms << " " << numFaces << "\n";
// write the vertex and vertex normal list
for(size_t i = 0; i < numVerts; i++)
outStream << pt[i].x << " " << pt[i].y << " " << pt[i].z << "\n";
for(size_t ii = 0; ii < numNorms; ii++)
outStream << norm[ii].x << " " << norm[ii].y << " " << norm[ii].z << "\n";
// write the face data
for(size_t f = 0; f < numFaces; f++)
{
size_t n = face[f].nVerts;
outStream << n << "\n";
for(size_t v = 0; v < n; v++)// write vertex indices for this face
outStream << face[f].vert[v].vertIndex << " "; outStream << "\n";
for(size_t k = 0; k < n; k++) // write normal indices for this face
outStream << face[f].vert[k].normIndex << " "; outStream << "\n";
}
outStream.close();
}
// Generate and OBJ file from the mesh data in this object
void Mesh::outputOBJ(string fname)
{
// Is there any data to write out?
if(numVerts == 0 || numNorms == 0 || numFaces == 0) return; //empty
// Create the output stream.
ofstream outStream;
outStream.open(fname.c_str()); // open the output stream
if(outStream.fail())
{
cout << "can't make new file: " << fname << endl;
return;
}
// Write a comment identifying the file
outStream << "# Generated by Mesh::outputOBJ() from '" << meshFileName << "'" << endl;
// Write out a default group indicator
outStream << "g default" << endl;
// Write the vertex and vertex normal list
size_t i;
for(i = 0; i < numVerts; i++)
outStream << "v " << pt[i].x << " " << pt[i].y << " " << pt[i].z << endl;
outStream << endl;
for(i = 0; i < numNorms; i++)
outStream << "vn " << norm[i].x << " " << norm[i].y << " " << norm[i].z << endl;
outStream << endl;
// Write the face data
for(size_t f = 0; f < numFaces; f++)
{
outStream << "f ";
for(i = 0; i < face[f].nVerts; i++)
outStream << face[f].vert[i].vertIndex+1 << "//" << face[f].vert[i].normIndex+1 << " ";
outStream << endl;
}
// Close the output
outStream.close();
}
void Mesh::drawOpenGL() {}
int Mesh::isEmpty() { return (numVerts == 0) || (numFaces == 0); } //|| (numNorms == 0);}
void Mesh::makeEmpty() { numVerts = numFaces = numNorms = 0;}
void Mesh::print(void) { cout << "Object: Mesh\n"; }
//@$@$@$@$@$@$@$@$@$@ Tetrahedron class @$@$@$@$@$@$@$@$@$
Tetrahedron::Tetrahedron():Mesh("Data/Tetrahedron.3vn") {}
void Tetrahedron::print()
{
cout << "Object: Tetrahedron" << endl;
transf.print();
}
//@$@$@$@$@$@$@$@$@$@ Octahedron class @$@$@$@$@$@$@$@$@$
Octahedron::Octahedron():Mesh("Data/Octahedron.3vn") {}
void Octahedron::print()
{
cout << "Object: Octahedron" << endl;
transf.print();
}
//@$@$@$@$@$@$@$@$@$@ Dodecahedron class @$@$@$@$@$@$@$@$@$
Dodecahedron::Dodecahedron():Mesh("Data/Dodecahedron.3vn") {}
void Dodecahedron::print()
{
cout << "Object: Dodecahedron" << endl;
transf.print();
}
//@$@$@$@$@$@$@$@$@$@ Icosahedron class @$@$@$@$@$@$@$@$@$
Icosahedron::Icosahedron():Mesh("Data/Icosahedron.3vn") {}
void Icosahedron::print()
{
cout << "Object: Icosahedron" << endl;
transf.print();
}
//@$@$@$@$@$@$@$@$@$@ BuckyBall class @$@$@$@$@$@$@$@$@$
BuckyBall::BuckyBall():Mesh("Data/BuckyBall.3vn") {}
void BuckyBall::print()
{
cout << "Object: BuckyBall" << endl;
transf.print();
}
//@$@$@$@$@$@$@$@$@$@ Diamond class @$@$@$@$@$@$@$@$@$
Diamond::Diamond():Mesh("Data/Diamond.3vn") {}
void Diamond::print()
{
cout << "Object: Diamond" << endl;
transf.print();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -