PLY文件读取与显示
用OpenGL写了一份读取PLY文件并显示的代码,支持以下关键字:
ply/format/element vertex/property/element face/end_header
以及数据类型:
char(int8)/uchar(uint8)/short(int16)/ushort(uint16)/int(int32)/uint(uint32)/float(float32)/double(float64)
并支持变量:
坐标x y (z可选) (w可选)/法向向量nx ny nz/颜色red green blue (alpha可选)
读取之后,利用OpenGL绘制出来,并绘制坐标轴,允许可以通过方向键旋转坐标、‘-’和‘=’缩小、放大。
希望写成C++风格,但是很久没写C++代码了,如有不妥,还望各位看官斧正。
转载需经过本人同意!
///////////////////////////////////////////////////////////////////////////////////////////////
main.cpp
/******************************************************* *项目名称: *Copyright (C), SCUT HCII-Lab (http://www.hcii-lab.net/) *模块名称:PLY文件读取与显示 *作者:SCUT,EE,石育金 *版本号(Version):V1-20150419 *指导老师:张鑫 ******************************************************* *创建日期:2015.4.19 *功能描述: *1,读取.PLY文件,支持关键字 ply/format/element vertex/property/element face/end_header * 以及数据类型 char(int8)/uchar(uint8)/short(int16)/ushort(uint16)/int(int32)/uint(uint32)/float(float32)/double(float64) * 并支持property x y (z) (w)/nx ny nz/red green blue (alpha) *2,绘制由.ply文件所描绘的立体,同时绘制坐标系。 * 支持箭头↑↓←→旋转坐标系; * 支持=放大,-缩小; *包含文件: *main.cpp/PLYLoader.h/PLYLoader.cpp *修改记录: *2015.04.19修正了读取ubyte数据出错的bug。 * *******************************************************/ #include "PLYLoader.h" GLvoid init(); GLvoid display(); GLvoid reshape(GLint,GLint); GLvoid keyboard(GLubyte,GLint,GLint); GLvoid specialKey(GLint,GLint,GLint); PLYFile *p; void main(int argc, char** argv) { p=new PLYFile("pyramid.ply"); p->print(); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(800, 600); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutSpecialFunc(specialKey); glutMainLoop(); delete p; } GLvoid init() { glClearColor (0.0, 0.0, 0.0, 0.0); glShadeModel (GL_SMOOTH);//渐变模式。GL_FLAT:单色模式 glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } GLvoid display() { //PLY display function p->PLYdisplay(); } GLvoid reshape(GLint w,GLint h) { p->PLYreshape(w,h); } GLvoid keyboard(GLubyte key,GLint x,GLint y) { p->PLYkey(key); } GLvoid specialKey(GLint key,GLint x,GLint y) { p->PLYskey(key); }
PLYLoader.h
/******************************************************* *项目名称: *Copyright (C), SCUT HCII-Lab (http://www.hcii-lab.net/) *模块名称:PLY文件读取与显示 *作者:SCUT,EE,石育金 *版本号(Version):V1-20150419 *指导老师:张鑫 ******************************************************* *创建日期:2015.4.19 *功能描述:定义了PLYFile类,用于读取PLY文件,并定义了4个回调函数用于绘制立体或交互。 * * *******************************************************/ #include <string> #include <iostream> #include <fstream> #include <vector> #include <gl/glut.h> using namespace std; class PLYFile { public: PLYFile(string = ""); ~PLYFile(); GLvoid print(); GLboolean PLYdisplay(); GLboolean PLYreshape(GLint,GLint); GLboolean PLYkey(GLubyte); GLboolean PLYskey(GLint); private: GLboolean PLYLoad(string = ""); string path;/**/ //vertex information.For convinence,using vector as container GLint vertexNum;/*vertex number*/ vector<GLvoid *>array;/*save information of vertex,different element in different array*/ vector<GLsizei>count;/*number of properties each element contains*/ vector<GLenum>propertyType;/*type of property*/ vector<GLenum>elementType;/*type of element,must be GL_VERTEX_ARRAY/GL_NORMAL_ARRAY/GL_COLOR_ARRAY*/ //face information GLint faceNum;/*face number*/ GLuint *indices;/*index of face,indicate the index of vertex that each face contains*/ //detail for projection translation GLdouble max[3];/*max of x,y,z*/ GLdouble min[3];/*min of x,y,z*/ GLdouble size;/*length of diagonal line对角线长度*/ //model translation GLdouble xRotAngle; GLdouble yRotAngle; GLdouble scale[3]; };PLYLoader.cpp
/******************************************************* *项目名称: *Copyright (C), SCUT HCII-Lab (http://www.hcii-lab.net/) *模块名称:PLY文件读取与显示 *作者:SCUT,EE,石育金 *版本号(Version):V1-20150419 *指导老师:张鑫 ******************************************************* *创建日期:2015.4.19 *功能描述:实现PLYFile类 * * *******************************************************/ #include"PLYLoader.h" PLYFile::PLYFile(string p) { path=p; indices=NULL; max[0]=0;max[1]=0;max[2]=0; min[0]=0;min[1]=0;min[2]=0; xRotAngle=0; yRotAngle=0; PLYLoad(); size = sqrt(pow(max[0]-min[0],2)+pow(max[1]-min[1],2)+pow(max[2]-min[2],2)); scale[0]=1; scale[1]=1; scale[2]=1; } PLYFile::~PLYFile() { if(indices) delete []indices; for(int i=0;i<array.size();i++) delete []array[i]; } /******************************************************* *PLYLoad *用于读取ply文件,存入类内的变量 *传入参数p是文件路径,默认为空。如果构建类的时候传入了文件路径,此处可以省略。 *返回值为1表示读取成功,反之失败。 *******************************************************/ GLboolean PLYFile::PLYLoad(string p) { fstream fopen; if(!p.empty()) fopen.open(p,ios::in); else if(!path.empty()) fopen.open(path,ios::in); else return 0; if(!fopen.is_open()) { return 0;//open file fail! cout<<"read file fail!"<<endl; } //start to read string filein; while(!fopen.eof()) { fopen>>filein; if(filein=="ply"||filein=="PLY") { //this is the header of .ply file,add TODO here }else if(filein=="comment") { //this is the comment,add TODO here getline(fopen,filein," "); }else if(filein=="format") { //this is the format information,add TODO here getline(fopen,filein," "); }else if(filein=="element") { //element information,only accept vertex and face.ignore user-defined element fopen>>filein; if(filein=="vertex") { //read the number of vertex fopen>>vertexNum; }else if(filein=="face") { //read the number of face fopen>>faceNum; //ignore this and the next lines getline(fopen,filein," "); getline(fopen,filein," "); }else { //user-defined element cout<<"ignore user-defined element!"<<endl; getline(fopen,filein," "); } }else if(filein=="property") { //property,only accept xyz/nxyz/rgb fopen>>filein;//read in type of element if(filein=="char"||filein=="int8") { propertyType.push_back(GL_BYTE); }else if(filein=="uchar"||filein=="uint8") { propertyType.push_back(GL_UNSIGNED_BYTE); }else if(filein=="short"||filein=="int16") { propertyType.push_back(GL_SHORT); }else if(filein=="ushort"||filein=="uint16") { propertyType.push_back(GL_UNSIGNED_SHORT); }else if(filein=="int"||filein=="int32") { propertyType.push_back(GL_INT); }else if(filein=="uint"||filein=="uint32") { propertyType.push_back(GL_UNSIGNED_INT); }else if(filein=="float"||filein=="float32") { propertyType.push_back(GL_FLOAT); }else if(filein=="double"||filein=="float64") { propertyType.push_back(GL_DOUBLE); }else { //use GLdouble as default cout<<"Undefined property type!"<<endl; propertyType.push_back(GL_DOUBLE); } fopen>>filein; if(filein=="x") { elementType.push_back(GL_VERTEX_ARRAY); getline(fopen,filein," ");//x getline(fopen,filein," ");//y count.push_back(2); }else if(filein=="nx") { elementType.push_back(GL_NORMAL_ARRAY); getline(fopen,filein," ");//nx getline(fopen,filein," ");//ny getline(fopen,filein," ");//nz count.push_back(3); }else if(filein=="red") { elementType.push_back(GL_COLOR_ARRAY); getline(fopen,filein," ");//red getline(fopen,filein," ");//green getline(fopen,filein," ");//blue count.push_back(3); }else if(/*filein=="y"||*/filein=="z"||filein=="w"/*||filein=="green"||filein=="blue"*/||filein=="alpha") { count[count.size()-1]+=1; propertyType.pop_back(); }else { cout<<"Unknown property!"<<endl; } }else if(filein=="end_header") { //header end,add TODO here //ckeck if(count.size()!=propertyType.size()||count.size()!=elementType.size()) { cout<<"the number of element collision"<<endl; return 0; } //start to read element information //initialise the array GLvoid *subarray=NULL; for(int i=0;i<propertyType.size();i++) { switch(propertyType[i]) { case GL_BYTE:subarray=new GLbyte[vertexNum*count[i]]; array.push_back(subarray);break; case GL_UNSIGNED_BYTE:subarray=new GLubyte[vertexNum*count[i]]; array.push_back(subarray);break; case GL_SHORT:subarray=new GLshort[vertexNum*count[i]]; array.push_back(subarray);break; case GL_UNSIGNED_SHORT:subarray=new GLushort[vertexNum*count[i]]; array.push_back(subarray);break; case GL_INT:subarray=new GLint[vertexNum*count[i]]; array.push_back(subarray);break; case GL_UNSIGNED_INT:subarray=new GLuint[vertexNum*count[i]]; array.push_back(subarray);break; case GL_FLOAT:subarray=new GLfloat[vertexNum*count[i]]; array.push_back(subarray);break; case GL_DOUBLE:subarray=new GLdouble[vertexNum*count[i]]; array.push_back(subarray);break; } } if(faceNum) indices=new GLuint[faceNum*3]; //read vertex information int totalelement=0; for(int i=0;i<count.size();i++) totalelement+=count[i]; for(int i=0;i<vertexNum;i++)//接下来的vertexNum行都是顶点信息 { for(int j=0;j<count.size();j++)//每行包括顶点的count.size()(<=3)种信息 for(int k=0;k<count[j];k++)//每种信息包括count[j]个property { switch(propertyType[j]) { case GL_BYTE:{ GLdouble tem = 0;//(GLdouble)(((GLbyte*)(array[j]))[i*count[j]+k]); fopen>>tem; ((GLbyte*)(array[j]))[i*count[j]+k] = GLbyte(tem); if(elementType[j] == GL_VERTEX_ARRAY && k < 3) { if(tem > max[k])max[k] = tem; if(tem < min[k])min[k] = tem; } break;} case GL_UNSIGNED_BYTE:{ GLint tem = 0;//(GLdouble)(((GLubyte*)(array[j]))[i*count[j]+k]); fopen>>tem; ((GLubyte*)(array[j]))[i*count[j]+k] = GLubyte(tem); if(elementType[j] == GL_VERTEX_ARRAY && k < 3) { if(tem > max[k])max[k] = tem; if(tem < min[k])min[k] = tem; } break;} case GL_SHORT: fopen>>((GLshort*)(array[j]))[i*count[j]+k]; if(elementType[j] == GL_VERTEX_ARRAY && k < 3) { GLdouble tem = (GLdouble)(((GLshort*)(array[j]))[i*count[j]+k]); if(tem > max[k])max[k] = tem; if(tem < min[k])min[k] = tem; } break; case GL_UNSIGNED_SHORT: fopen>>((GLushort*)(array[j]))[i*count[j]+k]; if(elementType[j] == GL_VERTEX_ARRAY && k < 3) { GLdouble tem = (GLdouble)(((GLushort*)(array[j]))[i*count[j]+k]); if(tem > max[k])max[k] = tem; if(tem < min[k])min[k] = tem; } break; case GL_INT: fopen>>((GLint*)(array[j]))[i*count[j]+k]; if(elementType[j] == GL_VERTEX_ARRAY && k < 3) { GLdouble tem = (GLdouble)(((GLint*)(array[j]))[i*count[j]+k]); if(tem > max[k])max[k] = tem; if(tem < min[k])min[k] = tem; } break; case GL_UNSIGNED_INT: fopen>>((GLuint*)(array[j]))[i*count[j]+k]; if(elementType[j] == GL_VERTEX_ARRAY && k < 3) { GLdouble tem = (GLdouble)(((GLuint*)(array[j]))[i*count[j]+k]); if(tem > max[k])max[k] = tem; if(tem < min[k])min[k] = tem; } break; case GL_FLOAT:{ fopen>>((GLfloat*)(array[j]))[i*count[j]+k]; if(elementType[j] == GL_VERTEX_ARRAY && k < 3) { GLdouble tem = (GLdouble)(((GLfloat*)(array[j]))[i*count[j]+k]); if(tem > max[k])max[k] = GLdouble(tem); if(tem < min[k])min[k] = GLdouble(tem); } break;} case GL_DOUBLE: fopen>>((GLdouble*)(array[j]))[i*count[j]+k]; if(elementType[j] == GL_VERTEX_ARRAY && k < 3) { GLdouble tem = ((GLdouble*)(array[j]))[i*count[j]+k]; if(tem > max[k])max[k] = tem; if(tem < min[k])min[k] = tem; } break; } } } //read face information int front=0,i=0;; fopen>>front; while(front==3 && i<faceNum) { fopen>>indices[i*3]>>indices[i*3+1]>>indices[i*3+2]; fopen>>front; i++; } }else { continue; } } fopen.close(); return 1;//finished } /******************************************************* *PLYdisplay *显示函数,需放在glutDisplayFunc()定义的回调函数内调用 *返回值可以忽略 *******************************************************/ GLboolean PLYFile::PLYdisplay() { glClearColor(0.0, 0.0, 0.0, 0.0); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); //scale glScalef(scale[0],scale[1],scale[2]); //rotate glRotatef(xRotAngle,1.0,0.0,0.0); glRotatef(yRotAngle,0.0,1.0,0.0); //smooth glEnable(GL_POINT_SMOOTH); glHint(GL_POINT_SMOOTH,GL_NICEST); glEnable(GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH,GL_NICEST); glEnable(GL_POLYGON_SMOOTH); glHint(GL_POLYGON_SMOOTH,GL_NICEST); //draw coordinate system glColor3f(1.0,1.0,1.0); glBegin(GL_LINES); glVertex3f((min[0]<0)?(1.4*(min[0])):(-0.8*min[0]),0.0,0.0); glVertex3f(1.8*(max[0]),0.0,0.0); glVertex3f(0.0,(min[1]<0)?(1.4*(min[1])):(-0.8*min[1]),0.0); glVertex3f(0.0,1.8*(max[1]),0.0); glVertex3f(0.0,0.0,(min[2]<0)?(1.4*(min[2])):(-0.8*min[2])); glVertex3f(0.0,0.0,1.8*(max[2])); glEnd(); glPushMatrix(); glTranslatef(1.8*(max[0]),0.0,0.0); glRotatef(90.0,0.0,1.0,0.0); glutSolidCone(0.02*size,0.04*size,10,10); glPopMatrix(); glPushMatrix(); glTranslatef(0.0,1.8*(max[1]),0.0); glRotatef(-90.0,1.0,0.0,0.0); glutSolidCone(0.02*size,0.04*size,10,10); glPopMatrix(); glPushMatrix(); glTranslatef(0.0,0.0,1.8*(max[2])); glRotatef(90.0,0.0,0.0,1.0); glutSolidCone(0.02*size,0.04*size,10,10); glPopMatrix(); //draw object glColor3f(1.0,1.0,1.0); //enable and assign for(int i=0;i<(elementType.size());i++) { switch(elementType[i]) { case GL_VERTEX_ARRAY: glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(count[i],propertyType[i],0,array[i]); break; case GL_NORMAL_ARRAY: glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(propertyType[i],0,array[i]); break; case GL_COLOR_ARRAY: glEnableClientState(GL_COLOR_ARRAY); glColorPointer(count[i],propertyType[i],0,array[i]); break; } } //use array for(int i=0;i<faceNum;i++) { glDrawElements(GL_TRIANGLES,3,GL_UNSIGNED_INT,&(indices[i*3])); } glPopMatrix(); glutSwapBuffers(); return 1; } /******************************************************* *PLYreshape *重绘函数,需放在glutReshapeFunc()定义的回调函数内调用 *返回值可以忽略 *******************************************************/ GLboolean PLYFile::PLYreshape(GLint w,GLint h) { glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective(60.0, (GLfloat) w/(GLfloat) h, size * 0.05, size*5); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt (max[0]*3, max[1]*3, max[2]*3,/*eye position, changeable*/ 0.0, 0.0, 0.0,/*a point that on the sight line. FIXED to zero point*/ -max[0]*3, -max[1]*3, (pow(max[0],2)+max[1],2)*3/max[2]/*Specifies the direction of the up vector, vertical to the sight line*/); return 1; } /******************************************************* *PLYkey *普通按键处理函数,需放在glutKeyboardFunc()定义的回调函数内调用 *返回值可以忽略 *******************************************************/ GLboolean PLYFile::PLYkey(GLubyte key) { switch(key) { case "=": scale[0]*=1.1; scale[1]*=1.1; scale[2]*=1.1; break; case "-": scale[0]*=0.9; scale[1]*=0.9; scale[2]*=0.9; break; } glutPostRedisplay(); return 1; } /******************************************************* *PLYskey *特殊按键处理函数,需放在glutSpecialFunc()定义的回调函数内调用 *返回值可以忽略 *******************************************************/ GLboolean PLYFile::PLYskey(GLint key) { switch(key) { case GLUT_KEY_UP:xRotAngle-=5.0;break; case GLUT_KEY_DOWN:xRotAngle+=5.0;break; case GLUT_KEY_RIGHT:yRotAngle+=5.0;break; case GLUT_KEY_LEFT:yRotAngle-=5.0;break; } glutPostRedisplay(); return 1; } /******************************************************* *print *打印函数。将读入的问件内容显示出来。用于调试。 *******************************************************/ GLvoid PLYFile::print() { cout<<"PLY file"<<endl; cout<<"path:"<<path<<endl; cout<<"VertexNum:"<<vertexNum<<endl; cout<<"property number:"<<array.size()<<endl<< count.size()<<endl<< propertyType.size()<<endl<< elementType.size()<<endl; cout<<"count:"<<endl; for(int i=0;i<count.size();i++) cout<<i<<" : "<<count[i]<<endl; cout<<"propertyType"<<endl; for(int i=0;i<propertyType.size();i++) cout<<i<<" : "<<propertyType[i]<<endl; cout<<"elementType"<<endl; for(int i=0;i<elementType.size();i++) cout<<i<<" : "<<elementType[i]<<endl; cout<<"max:"<<endl; cout<<max[0]<<" "<<max[1]<<" "<<max[2]<<" "<<endl; cout<<"min:"<<endl; cout<<min[0]<<" "<<min[1]<<" "<<min[2]<<" "<<endl; cout<<"size: "<<size<<endl; cout<<"faceNum:"<<faceNum<<endl; //cout<<"array:"<<endl; //for(int i=0;i<array.size();i++) //{ // for(int j=0;j<vertexNum*count[i];j++) // cout<<array[i][j]<<endl; //} //cout<<"indices:"<<endl; //for(int i=0;i<faceNum;i++) //{ // for(int j=0;j<3;j++) // cout<<indices[i*3+j]<<" "; // cout<<endl; //} }
比如读取下面这个文件:
pyramid.ply
ply format ascii 1.0 comment created by MATLAB ply_write element vertex 5 property float x property float y property float z property float red property float green property float blue element face 6 property list uchar char vertex_indices end_header 0.000000 0.000000 0.000000 1.0 1.0 1.0 1.000000 0.000000 0.000000 1.0 0.0 0.0 1.000000 1.000000 0.000000 0.0 0.0 1.0 0.000000 1.000000 0.000000 0.0 1.0 0.0 0.500000 0.500000 1.600000 1.0 1.0 0.0 3 1 0 3 3 1 3 2 3 0 1 4 3 0 4 3 3 3 4 2 3 1 2 4效果如图:
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
- 上一篇: linux用nohup在后台常驻运行php脚本
- 下一篇: MAC OS 关于内存使用状态的问题