#ifndef _LOADOBJ_H_
#define _LOADOBJ_H_
#include <math.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
#define dot(u,v) ((u).x * (v).x + (u).y * (v).y + (u).z*(v).z)
#define norm2(v) dot(v,v) // norm2 = squared length of vector
#define norm(v) sqrt(norm2(v)) // norm = length of vector
#define d(u,v) norm(u-v) // distance = norm of difference
// Obj loader
struct TriangleFace
{
int v[3]; // vertex indices
};
class float3
{
public:
float x;
float y;
float z;
public:
float3(){x=0;y=0;z=0;}
float3(float mx,float my,float mz){x=mx;y=my;z=mz;}
~float3(){}
float3 operator+(float3);
float3 operator-(float3);
float3 operator/(float);
friend float3 operator*(float m,float3 f3)
{
return float3(f3.x*m,f3.y*m,f3.z*m);
}
friend float3 operator*(float3 f3,float m)
{
return float3(f3.x*m,f3.y*m,f3.z*m);
}
float3 operator=(float3);
float3& operator += (float3);
};
float3 float3::operator +(float3 m)
{
float3 result;
result.x = x+m.x;
result.y = y+m.y;
result.z = z+m.z;
return result;
}
float3 float3::operator - (float3 m)
{
float3 result;
result.x = x-m.x;
result.y = y-m.y;
result.z = z-m.z;
return result;
}
float3 float3::operator /(float m)
{
if(m==0){
printf("error /");
return float3(x,y,z);
}
else
return float3(x/m,y/m,z/m);
}
float3 float3::operator =(float3 f3)
{
x = f3.x;
y = f3.y;
z = f3.z;
return float3(x,y,z);
}
struct TriangleMesh
{
vector<float3> verts;
vector<TriangleFace> faces;
//模型的包围盒
float3 bounding_box[2];
//模型的包围球参数
float3 bounding_sphere_c;
float bounding_sphere_r;
};
TriangleMesh mesh;
int total_number_of_triangles = 0;
// Scene bounding box
float3 scene_aabbox_min;
float3 scene_aabbox_max;
void loadObj(const std::string filename, TriangleMesh &mesh);
void loadObj( const std::string filename, TriangleMesh &mesh )
{
std::ifstream in(filename.c_str());
if(!in.good())
{
cout << "ERROR: loading obj:(" << filename << ") file is not good" << "\n";
exit(0);
}
char buffer[256], str[255];
float f1,f2,f3;
while(!in.getline(buffer,255).eof())
{
buffer[255]='\0';
sscanf_s(buffer,"%s",str,255);
// reading a vertex
if (buffer[0]=='v' && (buffer[1]==' ' || buffer[1]==32) )
{
if ( sscanf(buffer,"v %f %f %f",&f1,&f2,&f3)==3)
{
mesh.verts.push_back(float3(f1,f2,f3));
}
else
{
cout << "ERROR: vertex not in wanted format in OBJLoader" << "\n";
exit(-1);
}
}
// reading FaceMtls
else if (buffer[0]=='f' && (buffer[1]==' ' || buffer[1]==32) )
{
TriangleFace f;
int nt = sscanf(buffer,"f %d %d %d",&f.v[0],&f.v[1],&f.v[2]);
if( nt!=3 )
{
cout << "ERROR: I don't know the format of that FaceMtl" << "\n";
exit(-1);
}
mesh.faces.push_back(f);
}
}
float xmin,ymin,zmin,xmax,ymax,zmax;
int Pxmin,Pxmax,Pymin,Pymax,Pzmin,Pzmax;
//calculate the bounding sphere
xmin = xmax = mesh.verts[0].x;
ymin = ymax = mesh.verts[0].y;
zmin = zmax = mesh.verts[0].z;
Pxmin = Pxmax = Pymin = Pymax = Pzmin = Pzmax = 0;
//calculate the bounding box
mesh.bounding_box[0] = float3(mesh.verts[0].x,mesh.verts[0].y,mesh.verts[0].z);
mesh.bounding_box[1] = float3(mesh.verts[0].x,mesh.verts[0].y,mesh.verts[0].z);
for(unsigned int i = 1; i < mesh.verts.size(); i++)
{
//update min value
mesh.bounding_box[0].x = min(mesh.verts[i].x,mesh.bounding_box[0].x);
mesh.bounding_box[0].y = min(mesh.verts[i].y,mesh.bounding_box[0].y);
mesh.bounding_box[0].z = min(mesh.verts[i].z,mesh.bounding_box[0].z);
//update max value
mesh.bounding_box[1].x = max(mesh.verts[i].x,mesh.bounding_box[1].x);
mesh.bounding_box[1].y = max(mesh.verts[i].y,mesh.bounding_box[1].y);
mesh.bounding_box[1].z = max(mesh.verts[i].z,mesh.bounding_box[1].z);
//update the x min and max
if (mesh.verts[i].x < xmin){
xmin = mesh.verts[i].x;
Pxmin = i;
}
else if(mesh.verts[i].x > xmax){
xmax = mesh.verts[i].x;
Pxmax = i;
}
//update the y min and max
if (mesh.verts[i].y < ymin){
ymin = mesh.verts[i].y;
Pymin = i;
}
else if(mesh.verts[i].y > ymax){
ymax = mesh.verts[i].y;
Pymax = i;
}
//update the z min and max
if(mesh.verts[i].z < zmin){
zmin = mesh.verts[i].z;
Pzmin = i;
}
else if(mesh.verts[i].z > zmax){
zmax = mesh.verts[i].z;
Pzmax = i;
}
}
//calculate the bounding sphere
float3 dVx = mesh.verts[Pxmax] - mesh.verts[Pxmin];
float3 dVy = mesh.verts[Pymax] - mesh.verts[Pymin];
float3 dVz = mesh.verts[Pzmax] - mesh.verts[Pzmin];
float dx2 = norm2(dVx);
float dy2 = norm2(dVy);
float dz2 = norm2(dVz);
float3 center;
float radius2;
float radius;
if (dx2 >= dy2 && dx2>=dz2) { // x direction is largest extent
center = mesh.verts[Pxmin] + (dVx / 2.0); // Center = midpoint of extremes
radius2 = norm2(mesh.verts[Pxmax] - center);// radius squared
}
else if (dy2 >= dx2 && dy2>=dz2){ // y direction is largest extent
center = mesh.verts[Pymin] + (dVy / 2.0); // Center = midpoint of extremes
radius2 = norm2(mesh.verts[Pymax] - center);// radius squared
}
else{
center = mesh.verts[Pzmin] + (dVz / 2.0); // Center = midpoint of extremes
radius2 = norm2(mesh.verts[Pzmax] - center);// radius squared
}
radius = sqrt(radius2);
// now check that all points V[i] are in the ball
// and if not, expand the ball just enough to include them
float3 dV;
float dist2,dist;
for (unsigned int i=0;i<mesh.verts.size();i++)
{
dV = mesh.verts[i] - center;
dist2 = norm2(dV);
if (dist2 <= radius2) // V[i] is inside the ball already
continue;
// V[i] not in ball, so expand ball to include it
dist = sqrt(dist2);
radius = (radius + dist) / 2.0; // enlarge radius just enough
radius2 = radius * radius;
center = center + ((dist-radius)/dist) * dV; // shift Center toward V[i]
}
mesh.bounding_sphere_c = center;
mesh.bounding_sphere_r = radius;
cout<< "----------obj file loaded-------------"<<endl;
cout<<"number of faces:" << mesh.faces.size() << " number of vertices:" << mesh.verts.size() << endl;
cout<< "obj bounding box: min:("
<< mesh.bounding_box[0].x << "," << mesh.bounding_box[0].y << "," << mesh.bounding_box[0].z <<") max:("
<< mesh.bounding_box[1].x << "," << mesh.bounding_box[1].y << "," << mesh.bounding_box[1].z <<")" << endl
<<"obj bounding sphere center:"<<mesh.bounding_sphere_c.x<<","<<mesh.bounding_sphere_c.y<<","<<mesh.bounding_sphere_c.z<<endl
<<"obj bounding sphere radius:"<<mesh.bounding_sphere_r<<endl;
}
#endif
用法:
#include "LoadObj.h"
void main()
{
std::string filename = "E:\\codeLab\\cube.obj";
TriangleMesh mesh;
loadObj(filename, mesh);
}
注意:请使用英文目录。