之前在网上查找了很长一段时间关于ply模型载入的资料,发现对鹿鹿鹿有用的实在太少,有个挺火的代码各个网站都有转载,但可惜的是鹿鹿鹿没有他的bird.ply模型,并且他代码也不是纯C++的,有很多C的东西。昨天偶然翻墙到一个貌似台湾的博客,贴出了源代码,试了试没想到还跑出来了。所以这里分享一下,希望给也在寻找ply模型载入的小伙伴一点帮助。代码来自痞客邦里面名叫tinylin的博主,转载请声明。
/*
2: 操作說明:
3: 鍵盤按下
4: r=會變成紅色
5: g=會變成綠色
6: b=會變成藍色
7: p=ploygon組成
8: l=line組成
9: model本身會自動旋轉
10: */
#include <iostream>
#include <fstream>
#include <string>
#include <GL/glut.h>
#include <math.h>
using namespace std;
void LoadPly(char *file_name,int style);//讀取並畫出ply函式
double r_ang=0.5;//旋轉角度變數
double R=255.0, G=0.0, B=0.0;//顏色儲存變數
int style=GL_POLYGON;//畫出model的方式
/*lighting 變數*/
const GLfloat light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
const GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat light_position[] = { 2.0f, 5.0f, 15.0f, 0.0f };
const GLfloat mat_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
const GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f };
const GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat high_shininess[] = { 1.0f };
void LoadPly(char *file_name,int style)
{
ifstream fin ( file_name, ios_base::in );//開檔
if ( !fin.is_open ( ) )
{
cout << "Cannot read the file." << endl;
cout << "Please check again." << endl;
exit(0);
}
string str;
int vertex, face;
char ch;
/*讀取header*/
while ( !fin.eof ( ) )
{
fin.get ( ch );
if( ch != ' ' && ch != '\t' && ch != '\n' )
{
str.push_back ( ch );
}
else
{
//取得vertex個數
if(str == "vertex")
{
str.clear ( );
getline ( fin, str, '\n' );
vertex = atoi(str.c_str());
}
//取得face個數
else if(str == "face")
{
str.clear ( );
getline ( fin, str, '\n' );
face = atoi(str.c_str());
}
else if(str == "end_header")
{
str.clear ( );
break;
}
else
str.clear ( );
}
}
//動態產生array
double *vertex_arrayX = new double[vertex];
double *vertex_arrayY = new double[vertex];
double *vertex_arrayZ = new double[vertex];
int pos = 0;
int counter = 0;
double number;
double max_edge = 0;
static double temp_max = 0;
/*讀取Vertex*/
while ( !fin.eof ( ) )
{
fin.get ( ch );
if( ch != ' ' && ch != '\t' && ch != '\n' )
str.push_back ( ch );
else
{
if(counter == vertex) break;
/*儲存vertex資料*/
if(str == "") continue;
else if(pos%3 == 0)
{
number = atof(str.c_str());
vertex_arrayX[counter] = number;
str.clear ( );
}
else if(pos%3 == 1)
{
number = atof(str.c_str());
vertex_arrayY[counter] = number;
str.clear ( );
}
else if(pos%3 == 2)
{
number = atof(str.c_str());
vertex_arrayZ[counter] = number;
str.clear ( );
counter++;
}
pos++;
//紀錄最大的邊
if(abs((int)number) > max_edge)
max_edge = abs((int)number);
}
}
int point[4];
int i = 0;
counter = 0;
/*畫Polygon*/
while ( !fin.eof ( ) )
{
fin.get ( ch );
if( ch != ' ' && ch != '\t' && ch != '\n' )
str.push_back ( ch );
else
{
if(counter == face) break;
if(ch == '\n')
{
// 計算法線向量 (打光)
GLfloat vc1[3],vc2[3];
GLfloat a,b,c;
GLdouble r;
vc1[0]= vertex_arrayX[point[2]] - vertex_arrayX[point[1]];
vc1[1]= vertex_arrayY[point[2]] - vertex_arrayY[point[1]];
vc1[2]= vertex_arrayZ[point[2]] - vertex_arrayZ[point[1]];
vc2[0]= vertex_arrayX[point[3]] - vertex_arrayX[point[1]];
vc2[1]= vertex_arrayY[point[3]] - vertex_arrayY[point[1]];
vc2[2]= vertex_arrayZ[point[3]] - vertex_arrayZ[point[1]];
a = vc1[1] * vc2[2] - vc2[1] * vc1[2];
b = vc2[0] * vc1[2] - vc1[0] * vc2[2];
c = vc1[0] * vc2[1] - vc2[0] * vc1[1];
r = sqrt( a * a + b* b + c * c);
float nor[3];
nor[0] = a / r;
nor[1] = b / r;
nor[2] = c / r;
glNormal3f(nor[0],nor[1],nor[2]);
//畫出所有face
glBegin(style);
for(int i=1;i<=point[0];i++)
glVertex3f(vertex_arrayX[point[i]], vertex_arrayY[point[i]],vertex_arrayZ[point[i]]);
glEnd();
counter++;
}
else if(str == "") continue;
else
{
point[i%4] = atoi(str.c_str());
i++;
str.clear ( );
}
}
}
fin.close();
//調整視角
if(max_edge > temp_max)
{
glLoadIdentity ();
glOrtho(-(max_edge*2), (max_edge*2), -(max_edge*2), (max_edge*2), -(max_edge*2), (max_edge*2));
}
temp_max = max_edge;
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glRotatef(r_ang, 0.0, 1.0, 1.0);
glColor3f(R,G,B);
LoadPly("ant.ply",style);
glFlush();
glutSwapBuffers();
}
void init()
{
glClearColor (0.0, 0.0, 0.0, 1.0);
glLoadIdentity ();
glOrtho(-5.0, 5.0, -5.0, 5.0, -5.0, 5.0);
}
void keyboard(unsigned char key, int x, int y)
{
//按esc離開
switch (key)
{
case 27 : exit(0);
break;
case 'r': R=255;G=0;B=0;
break;
case 'g': R=0;G=255;B=0;
break;
case 'b': R=0;G=0;B=255;
break;
case 'p': style = GL_POLYGON;
break;
case 'l': style = GL_LINES;
break;
}
glutPostRedisplay();
}
void idle(void)
{
glutPostRedisplay();
}
int main(int argc, char** argv)
{
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize (600, 600);
glutInitWindowPosition (300, 50);
glutCreateWindow("Load Ply Model");
glutDisplayFunc(display);
glutIdleFunc(idle);
glutKeyboardFunc(keyboard);//偵測keyboard
init();
//使用lighting 相關函式
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
glutMainLoop();
return EXIT_SUCCESS;
}