Opengl学习笔记:(一).Ply文件文件格式和文件读取
来源:互联网 发布:音频矩阵 编辑:程序博客网 时间:2024/06/06 01:23
转载自:http://blog.csdn.net/lxfyzx/article/details/4997627
http://blog.csdn.net/lxfyzx/article/details/4997780
一、Ply简介
这次实验老师要求用opengl读取.ply文件,个人理解,ply里面存储的是多边形模型的数据,包括一些点、面、材质、颜色等属性。
比较严谨的解释:
- PLY作为一种多边形模型数据格式,不同于三维引擎中常用的场景图文件格式和脚本文件,每个PLY文件只用于描述一个多边形模型对象(Object),该模型对象可以通过诸如顶点、面等数据进行描述,每一类这样的数据被称作一种元素(Element)。相比于现代的三维引擎中所用到的各种复杂格式,PLY实在是种简单的不能再简单的文件格式,但是如果仔细研究就会发现,就像设计者所说的,这对于绝大多数的图形应用来说已经是足够用了。
二、Ply中的结构
1、PLY的文件结构:
文件头加上元素数据列表。其中文件头中以行为单位描述文件类型、格式与版本、元素类型、元素的属性等,然后就根据在文件头中所列出元素类型的顺序及其属性,依次记录各个元素的属性数据。
2、 典型的PLY文件结构:
- 1、 头部
- 2、顶点列表
- 3、面片列表
- 4、 其他元素列表
3、简单举例
1) 头部
- a.头部是一系列以回车结尾的文本行,用来描述文件的剩余部分。
- b. 头部包含一个对每个元素类型的描述,包括元素名(如“边”),元素的数量,以及一个与这个元素关联的不同属性的列表。
- c.头部还说明这个文件是二进制的或者是ASCII的。
- d.头部后面的是一个每个元素类型的元素列表,按照在头部中描述的顺序出现。
- e.文件中的注释一般在 “comment”开始的关键词定义行里。
2) 举例:下面是一个立方体的完整ASCII描述。大括号中的注释不是文件的一部分,它们是这个例子的注解。
- a.头部的每个部分都是一个以关键词开头,以回车结尾的ASCII串。
- b.”ply”是文件的头四个字符。
- c.关键词“format”及其后面的是一个特定的ASCII或者二进制的格式,接下来是一个版本号。
- d.end_header 头文件结束
- f.再下面是多边形文件中每个元素的描述,在每个元素里还有多属性的说明。一般元素以下面的格式描述:
element <元素名> <在文件中的个数>
property <数据类型> <属性名-1>
property <数据类型> <属性名-2>
property <数据类型> <属性名-3>
ply format ascii 1.0 { ascii/二进制,格式版本数 } comment made by anonymous { 注释关键词说明,像其他行一样 } comment this file is a cube element vertex 8 { 定义“vertex”(顶点)元素,在文件中有8个 } property float32 x { 顶点包含浮点坐标“x”} property float32 y { y 坐标同样是一个顶点属性 } property float32 z { z 也是坐标 } element face 6 { 在文件里有6个“face”(面片) } property list uint8 int32 vertex_index { “vertex_indices”(顶点素引)是一列整数 } end_header { 划定头部结尾 } 0 0 0 { 顶点列表的开始 } 0 0 1 0 1 1 0 1 0 1 0 0 1 0 1 1 1 1 1 1 0 4 0 1 2 3 { 面片列表开始 } 4 7 6 5 4 4 0 4 5 1 4 1 5 6 2 4 2 6 7 3 4 3 7 4 0
- 3) 其他说明
- 属性罗列在“element”(元素)行后面定义,既包含属性的数据类型,也包含属性在每个元素中出现的次序。一个属性可以有三种数据类型:标量,字符串和列表。属性可能具有的标量数据类型列表如下。
- 这些字节计数很重要,而且在实现过程中不能修改以使这些文件可移植。
- 使用列表数据类型的属性定义有一种特殊的格式:property list <数值类型> <数值类型> <属性名> ,这种格式,一个非负字符表示在属性里包含多少索引,接下来是一个列表包含许多整数。在这个边长列表里的每个整数都是一个顶点的索引。
名称 类型 字节数 ------------------------------- int8 字符 1 uint8 非负字符 1 int16 短整型 2 uint16 非负短整型 2 int32 整型 4 uint32 非负整型 4 float32 单精度浮点数 4 float64 双精度浮点数 8
三、读取.ply文件
读取的方法:
1、在头文件信息中读取顶点数量和面数量(也可同时确定每个顶点的属性种类和数量)。
2、在文件的数据部分读取所有顶点信息,及面信息。
3、由顶点信息绘制图形。
PlyLoader.cpp
#include "PLYLoader.h"CPLYLoader::CPLYLoader(){ this->m_totalConnectedQuads = 0; this->m_totalConnectedPoints = 0; m_ModelData.iTotalConnectedTriangles = 0;}int CPLYLoader::LoadModel(char* filename){ //Loading hint printf("Loading %s...\n",filename); char* pch = strstr(filename,".ply"); //if file isn's null, go on reading if (pch != NULL) { FILE* file = fopen(filename,"r"); if (!file) { printf("load PLY file %s failed\n",filename); return false; } //comfirm the size of the file fseek(file,0,SEEK_END); long fileSize = ftell(file); try { mp_vertexXYZ = (float*) malloc (ftell(file)); mp_vertexNorm = (float*) malloc (ftell(file)); mp_vertexRGB = (float*) malloc(ftell(file)); } catch (char* ) { return -1; } if (mp_vertexXYZ == NULL) return -1; if (mp_vertexNorm == NULL) return -2; if (mp_vertexRGB == NULL) return -3; //go to the begining of the file fseek(file,0,SEEK_SET); if (file) { int i = 0; int temp = 0; int quads_index = 0; int triangle_index = 0; int normal_index = 0; int colorIndex = 0; char buffer[1000]; //read a line once fgets(buffer,300,file); // READ HEADER // ----------------- // Find number of vertexes while ( strncmp( "element vertex", buffer,strlen("element vertex")) != 0 ) { //printf("%s\n", buffer); fgets(buffer,300,file); } strcpy(buffer, buffer+strlen("element vertex")); //the second parament is like regular expression. //%i can automately translate the octonary number into the decimal number. sscanf(buffer,"%i", &this->m_totalConnectedPoints); //print test //printf("totalPoints:%d\n", this->m_totalConnectedPoints); // Find number of face fseek(file,0,SEEK_SET); while ( strncmp( "element face", buffer,strlen("element face")) != 0 ) { //printf("%s\n", buffer); fgets(buffer,300,file); // format } strcpy(buffer, buffer+strlen("element face")); sscanf(buffer,"%i", &this->m_totalFaces); //printf("totalQuads:%d\n", this->m_totalFaces); // go to end_header while ( strncmp( "end_header", buffer,strlen("end_header")) != 0 ) { fgets(buffer,300,file); } //---------------------- // read vertices i =0; for (int iterator = 0; iterator < this->m_totalConnectedPoints; iterator++) { char tmp[1]; fgets(buffer,300,file); //有的顶点元素可能存在3个属性,分别为坐标,法向量、颜色,但是最基本的,如上述正方形,仅有坐标属性 sscanf(buffer,"%f %f %f %f %f %f %c %f %f %f", &mp_vertexXYZ[i], &mp_vertexXYZ[i+1], &mp_vertexXYZ[i+2], &mp_vertexNorm[i], &mp_vertexNorm[i+1], &mp_vertexNorm[i+2], tmp, &mp_vertexRGB[i], &mp_vertexRGB[i+1], &mp_vertexRGB[i+2]); //print test //printf("%f %f %f %f %f %f %c %f %f %f\n", mp_vertexXYZ[i], mp_vertexXYZ[i+1], mp_vertexXYZ[i+2], // mp_vertexNorm[i], mp_vertexNorm[i+1], mp_vertexNorm[i+2], // tmp, // mp_vertexRGB[i], mp_vertexRGB[i+1], mp_vertexRGB[i+2]); // //system("pause"); i += 3; } // read faces i =0; for (int iterator = 0; iterator < this->m_totalFaces; iterator++) { fgets(buffer,300,file); //在面片部分,第一个数字表示此面有几个顶点构成,buffer[0] == ‘3’表示由3个顶点构成 if (buffer[0] == '3') { int vertex1 = 0, vertex2 = 0, vertex3 = 0; buffer[0] = ' '; //读取构成面的三个顶点的索引 sscanf(buffer,"%i%i%i", &vertex1,&vertex2,&vertex3 );//number of vertex eg:5,7,6 //printf("%d, %d, %d\n", vertex1, vertex2, vertex3);//按照面的三个顶点的顺序,依次把每个面的顶点数据存储到m_ModelData中,方便后面绘制顶点 m_ModelData.vecFaceTriangles.push_back( mp_vertexXYZ[3*vertex1]); m_ModelData.vecFaceTriangles.push_back( mp_vertexXYZ[3*vertex1+1]); m_ModelData.vecFaceTriangles.push_back( mp_vertexXYZ[3*vertex1+2]); m_ModelData.vecFaceTriangles.push_back( mp_vertexXYZ[3*vertex2]); m_ModelData.vecFaceTriangles.push_back( mp_vertexXYZ[3*vertex2+1]); m_ModelData.vecFaceTriangles.push_back( mp_vertexXYZ[3*vertex2+2]); m_ModelData.vecFaceTriangles.push_back( mp_vertexXYZ[3*vertex3]); m_ModelData.vecFaceTriangles.push_back( mp_vertexXYZ[3*vertex3+1]); m_ModelData.vecFaceTriangles.push_back( mp_vertexXYZ[3*vertex3+2]); //方法二 //vecFaceIndex.push_back(vertex1); //vecFaceIndex.push_back(vertex2); //vecFaceIndex.push_back(vertex3); m_ModelData.vecFaceTriangleColors.push_back( mp_vertexRGB[3*vertex1] / 255.0f); m_ModelData.vecFaceTriangleColors.push_back( mp_vertexRGB[3*vertex1+1]/ 255.0f); m_ModelData.vecFaceTriangleColors.push_back( mp_vertexRGB[3*vertex1+2]/ 255.0f); m_ModelData.vecFaceTriangleColors.push_back( mp_vertexRGB[3*vertex2] / 255.0f); m_ModelData.vecFaceTriangleColors.push_back( mp_vertexRGB[3*vertex2+1]/ 255.0f); m_ModelData.vecFaceTriangleColors.push_back( mp_vertexRGB[3*vertex2+2]/ 255.0f); m_ModelData.vecFaceTriangleColors.push_back( mp_vertexRGB[3*vertex3] / 255.0f); m_ModelData.vecFaceTriangleColors.push_back( mp_vertexRGB[3*vertex3+1]/ 255.0f); m_ModelData.vecFaceTriangleColors.push_back( mp_vertexRGB[3*vertex3+2]/ 255.0f); m_ModelData.vecNormals.push_back( mp_vertexNorm[3*vertex1]); m_ModelData.vecNormals.push_back( mp_vertexNorm[3*vertex1+1]); m_ModelData.vecNormals.push_back( mp_vertexNorm[3*vertex1+2]); m_ModelData.vecNormals.push_back( mp_vertexNorm[3*vertex2]); m_ModelData.vecNormals.push_back( mp_vertexNorm[3*vertex2+1]); m_ModelData.vecNormals.push_back( mp_vertexNorm[3*vertex2+2]); m_ModelData.vecNormals.push_back( mp_vertexNorm[3*vertex3]); m_ModelData.vecNormals.push_back( mp_vertexNorm[3*vertex3+1]); m_ModelData.vecNormals.push_back( mp_vertexNorm[3*vertex3+2]); triangle_index += 9; m_ModelData.iTotalConnectedTriangles += 3; } i += 3; } fclose(file); printf("%s Loaded!\n",filename); } else { printf("File can't be opened\n"); } } else { printf("File does not have a .PLY extension. "); } return 0;}void CPLYLoader::DrawByLine(){ if (m_ModelData.vecFaceTriangleColors.empty()) { cout << "model data is null"<<endl; exit(-1); } glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3,GL_FLOAT, 0,m_ModelData.vecFaceTriangles.data()); glNormalPointer(GL_FLOAT, 0, m_ModelData.vecNormals.data()); glDrawArrays(GL_LINES, 0, m_ModelData.iTotalConnectedTriangles); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY);}void CPLYLoader::DrawByPoint(){ if (m_ModelData.vecFaceTriangleColors.empty()) { cout << "model data is null"<<endl; exit(-1); } glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3,GL_FLOAT, 0,m_ModelData.vecFaceTriangles.data()); glNormalPointer(GL_FLOAT, 0, m_ModelData.vecNormals.data()); glDrawArrays(GL_POINTS, 0, m_ModelData.iTotalConnectedTriangles); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY);}void CPLYLoader::DrawByPolygon() //implemented in GLPainter, not called again{ if (m_ModelData.vecFaceTriangleColors.empty()) { cout << "model data is null"<<endl; exit(-1); } //需要根据你的.ply文件每个顶点是否存在以下3个属性来绘图 //假如你没有颜色属性,则读取的时候颜色相关数据为空,执行glColorPointer后可能导致绘制的图形无法显示 glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); //glEnableClientState(GL_COLOR_ARRAY); //每3个值为一组(代表一个顶点) glVertexPointer(3,GL_FLOAT, 0,m_ModelData.vecFaceTriangles.data()); //glColorPointer(3,GL_FLOAT,0,m_ModelData.vecFaceTriangleColors.data()); glNormalPointer(GL_FLOAT, 0, m_ModelData.vecNormals.data()); //以GK_TRIANGLES方式,即每3个顶点画一个面 glDrawArrays(GL_TRIANGLES, 0, m_ModelData.iTotalConnectedTriangles); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); //glDisableClientState(GL_COLOR_ARRAY); //方法二: //glEnableClientState(GL_VERTEX_ARRAY); //glVertexPointer(3, GL_FLOAT, 0, mp_vertexXYZ); //glDrawElements(GL_TRIANGLES, m_totalFaces * 3, GL_UNSIGNED_INT, vecFaceIndex.data());}
PlyLoader.h
#ifndef PLYREADER_H_#define PLYREADER_H_#include <vector>#include <iostream>#include <GL/glut.h>#include <GL/glu.h>#include <GL/gl.h>using namespace std;struct SModelData{ vector <float> vecFaceTriangles; // = face * 9 vector <float> vecFaceTriangleColors; // = face * 9 vector <float> vecNormals; // = face * 9 int iTotalConnectedTriangles;};class CPLYLoader {public: CPLYLoader(); int LoadModel(char *filename); void DrawByPoint(); void DrawByLine(); void DrawByPolygon();private: float* mp_vertexXYZ; float* mp_vertexNorm; float* mp_vertexRGB; int m_totalConnectedQuads; int m_totalConnectedPoints; int m_totalFaces; SModelData m_ModelData; vector <int> vecFaceIndex; //顶点索引};#endif
说明:
- 不同的.ply文件,每个顶点包含的属性值可能不一样,较简单的就只包含x y z值,复杂的还包含rgb 和法向量的值,所以绘制的时候要注意。
- 绘制的时候采用顶点数组的方式绘制,具体用法见3链接。
- 顶点数组绘图
1 0
- Opengl学习笔记:(一).Ply文件文件格式和文件读取
- .PLY文件格式剖析(一)
- OpenGL读取PLY模型文件并绘制 Read and draw ply model by OpenGL
- PlY文件读取显示
- Java文件IO学习笔记(五)-删除文件夹和文件
- 《C++ primer plus》第十七章 输入、输出和文件(一):输入和输出 学习笔记
- java 读取磁盘文件和文件
- 文件路径和文件读取方
- Java读取Zip文件和文件内容
- J2EE系列之Struts2学习笔记(二十二)--Struts2多文件上传和文件下载
- PLY文件格式
- ply 文件格式
- PLY文件格式
- PLY文件格式
- PLY文件格式
- PLY文件读取与显示
- Matlab读取ply文件,polydata
- 《Python基础教程》学习笔记(10-11模块和文件)
- 步步为营_Android开发课[5]_Service学习
- Android代码中实现WAP方式联网
- [LeetCode]Maximum number of points on a straight line in 2d plane
- C++ enum的使用
- Lock与synchronized
- Opengl学习笔记:(一).Ply文件文件格式和文件读取
- 黑马程序员-Java基础学习(函数)
- Java实现多项式
- 天题之Regular Expression Matching
- Fir平台上自动更新app的版本
- String类常用功能
- meanShift算法介绍
- 如何开发一个仿微信的 Web IM?
- 第17课时,自测