Lesson 10: Loading Stanford PLY 3D Models
Stanford PLY 3D models are similiar to Wavefront OBJs. Both are static objects. However, models stored in the PLY format are generally in binary format (e.g. unreadable with a normal text editor), but an ascii version of the format also exists. The files themselves store vertexes and faces. If you are unfamiliar with these, please read the previous tutorial. To load and display them, we can use this code:
/* Demonstrates how to load PLY files * Needs some refactoring. * * https://talkera.org/opengl/ * Model needs to be triangulated * Use blender * * Just the class for loading PLY files. * */ #include#include #include #include #include #include #include class Model_PLY { public: int Model_PLY::Load(char *filename); void Model_PLY::Draw(); float* Model_PLY::calculateNormal( float *coord1, float *coord2, float *coord3 ); Model_PLY(); float* Faces_Triangles; float* Faces_Quads; float* Vertex_Buffer; float* Normals; int TotalConnectedTriangles; int TotalConnectedQuads; int TotalConnectedPoints; int TotalFaces; }; Model_PLY::Model_PLY() { } float* Model_PLY::calculateNormal( float *coord1, float *coord2, float *coord3 ) { /* calculate Vector1 and Vector2 */ float va[3], vb[3], vr[3], val; va[0] = coord1[0] - coord2[0]; va[1] = coord1[1] - coord2[1]; va[2] = coord1[2] - coord2[2]; vb[0] = coord1[0] - coord3[0]; vb[1] = coord1[1] - coord3[1]; vb[2] = coord1[2] - coord3[2]; /* cross product */ vr[0] = va[1] * vb[2] - vb[1] * va[2]; vr[1] = vb[0] * va[2] - va[0] * vb[2]; vr[2] = va[0] * vb[1] - vb[0] * va[1]; /* normalization factor */ val = sqrt( vr[0]*vr[0] + vr[1]*vr[1] + vr[2]*vr[2] ); float norm[3]; norm[0] = vr[0]/val; norm[1] = vr[1]/val; norm[2] = vr[2]/val; return norm; } int Model_PLY::Load(char* filename) { this->TotalConnectedTriangles = 0; this->TotalConnectedQuads = 0; this->TotalConnectedPoints = 0; char* pch = strstr(filename,".ply"); if (pch != NULL) { FILE* file = fopen(filename,"r"); fseek(file,0,SEEK_END); long fileSize = ftell(file); try { Vertex_Buffer = (float*) malloc (ftell(file)); } catch (char* ) { return -1; } if (Vertex_Buffer == NULL) return -1; fseek(file,0,SEEK_SET); Faces_Triangles = (float*) malloc(fileSize*sizeof(float)); Normals = (float*) malloc(fileSize*sizeof(float)); if (file) { int i = 0; int temp = 0; int quads_index = 0; int triangle_index = 0; int normal_index = 0; char buffer[1000]; fgets(buffer,300,file); // ply // READ HEADER // ----------------- // Find number of vertexes while ( strncmp( "element vertex", buffer,strlen("element vertex")) != 0 ) { fgets(buffer,300,file); // format } strcpy(buffer, buffer+strlen("element vertex")); sscanf(buffer,"%i", &this->TotalConnectedPoints); // Find number of vertexes fseek(file,0,SEEK_SET); while ( strncmp( "element face", buffer,strlen("element face")) != 0 ) { fgets(buffer,300,file); // format } strcpy(buffer, buffer+strlen("element face")); sscanf(buffer,"%i", &this->TotalFaces); // go to end_header while ( strncmp( "end_header", buffer,strlen("end_header")) != 0 ) { fgets(buffer,300,file); // format } //---------------------- // read verteces i =0; for (int iterator = 0; iterator TotalConnectedPoints; iterator++) { fgets(buffer,300,file); sscanf(buffer,"%f %f %f", &Vertex_Buffer[i], &Vertex_Buffer[i+1], &Vertex_Buffer[i+2]); i += 3; } // read faces i =0; for (int iterator = 0; iterator TotalFaces; iterator++) { fgets(buffer,300,file); if (buffer[0] == '3') { int vertex1 = 0, vertex2 = 0, vertex3 = 0; //sscanf(buffer,"%i%i%i\n", vertex1,vertex2,vertex3 ); buffer[0] = ' '; sscanf(buffer,"%i%i%i", &vertex1,&vertex2,&vertex3 ); /*vertex1 -= 1; vertex2 -= 1; vertex3 -= 1; */ // vertex == punt van vertex lijst // vertex_buffer -> xyz xyz xyz xyz printf("%f %f %f ", Vertex_Buffer[3*vertex1], Vertex_Buffer[3*vertex1+1], Vertex_Buffer[3*vertex1+2]); Faces_Triangles[triangle_index] = Vertex_Buffer[3*vertex1]; Faces_Triangles[triangle_index+1] = Vertex_Buffer[3*vertex1+1]; Faces_Triangles[triangle_index+2] = Vertex_Buffer[3*vertex1+2]; Faces_Triangles[triangle_index+3] = Vertex_Buffer[3*vertex2]; Faces_Triangles[triangle_index+4] = Vertex_Buffer[3*vertex2+1]; Faces_Triangles[triangle_index+5] = Vertex_Buffer[3*vertex2+2]; Faces_Triangles[triangle_index+6] = Vertex_Buffer[3*vertex3]; Faces_Triangles[triangle_index+7] = Vertex_Buffer[3*vertex3+1]; Faces_Triangles[triangle_index+8] = Vertex_Buffer[3*vertex3+2]; float coord1[3] = { Faces_Triangles[triangle_index], Faces_Triangles[triangle_index+1],Faces_Triangles[triangle_index+2]}; float coord2[3] = {Faces_Triangles[triangle_index+3],Faces_Triangles[triangle_index+4],Faces_Triangles[triangle_index+5]}; float coord3[3] = {Faces_Triangles[triangle_index+6],Faces_Triangles[triangle_index+7],Faces_Triangles[triangle_index+8]}; float *norm = this->calculateNormal( coord1, coord2, coord3 ); Normals[normal_index] = norm[0]; Normals[normal_index+1] = norm[1]; Normals[normal_index+2] = norm[2]; Normals[normal_index+3] = norm[0]; Normals[normal_index+4] = norm[1]; Normals[normal_index+5] = norm[2]; Normals[normal_index+6] = norm[0]; Normals[normal_index+7] = norm[1]; Normals[normal_index+8] = norm[2]; normal_index += 9; triangle_index += 9; TotalConnectedTriangles += 3; } i += 3; } fclose(file); } else { printf("File can't be opened\n"); } } else { printf("File does not have a .PLY extension. "); } return 0; } void Model_PLY::Draw() { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3,GL_FLOAT, 0,Faces_Triangles); glNormalPointer(GL_FLOAT, 0, Normals); glDrawArrays(GL_TRIANGLES, 0, TotalConnectedTriangles); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); }