# I. overview

After class practice code hosting and key remarks of advanced computer 3D modeling. This is the first internship, the topic is to read the content of. ply file, and use opengl to draw the grid. So far, the four internship assignments assigned by the teacher are relatively simple, here is only a brief record, after all, just started.

# 2, Basic ideas

As shown in the figure, it is the file content of stanford bunny

First of all, you need to read the number of vertex and face in the file, initialize the array, and then read in the position coordinates of the points and the index of the corresponding points of each triangle patch. In fact, when drawing a 3D mesh, you do not need to draw every point. The coordinates of the points read here are used to draw line segments. With this information, just draw directly.

# 3, Noteworthy issues

In each practice, the teacher will provide a part of basic code, just add some code on this basis to complete the function.
As shown in the figure below, the reference code provided by the teacher is to draw points, and the requirement is to draw grids.

So, what I thought at the beginning was to use GL? Triangles to draw triangular patches. There is no problem in drawing the result, and this method is also the reference answer given by the teacher later. The result is as shown in the figure:

But I don't feel comfortable looking at myself, it's not the result I want. Because using GL? Triangles to draw a solid triangular face, and what I want is a triangular mesh. So I changed the GL ﹣ triangles into GL ﹣ lines, that is to say:

However, the result after running is as follows:

I'm going to puke. Without careful consideration, I always thought that it must be the wrong GL ﹣ line ﹣ so I changed it to GL ﹣ line ﹣ strip and GL ﹣ line ﹣ loop, but the result is still the same. (although this process is not very helpful for this internship, I have mastered the differences between GL ﹣ lines and GL ﹣ line ﹣ strip, GL ﹣ line ﹣ loop, and GL ﹣ quads and GL ﹣ Quad ﹣ strip.)

Later, I thought about why the lines were crisscross. The original problem was in the block of glBegin(), because in this block, when drawing line segments, each point would be connected to a point, not only every three points would be connected to make a triangle, which would cause different triangles to be connected through a certain line segment. So, knowing the problem, as long as you use the glBegin() block once each time you draw a single triangle, change the drawing code to:

In this way, the problem is solved. The running results are as follows:

In this way, I experimented with GL ﹣ line ﹣ strip and GL ﹣ line ﹣ loop. Sure enough, the results were as good as I expected.

# 4, Full code

I think there is a more troublesome part here, which is the string processing operation of the file content, which requires patience. All codes of this internship are as follows:

main.cpp

```#include <GL/glut.h>
#include <cstdio>
#include <cmath>

typedef struct VERTEX_3D
{
float x;
float y;
float z;
} VERTEX3D;

typedef struct _TRIANGLE
{
int A;//Index of vertex 0
int B;//Index of vertex 1
int C;//Index of vertex 2
} TRIANGLE;

VERTEX3D *g_vet;
VERTEX3D *g_norm;
VERTEX3D *g_color;

TRIANGLE *tri;

float g_rotx = 20.0f, g_roty = 30.0f, g_rotz = 0.0f;
float g_modelPos[3] = {0, 0, -15.0f};
float g_scale = 10.0f;

const float g_lightPos[] = { 1.0f, 1.0f, 1.0f, 0.0f };

char g_strModelName[512] = "plant.ply"; /*Problem happens when left the [512] being empty []*/
int g_nVerticesNumber;
int g_nFacesNumber;

void GetMinMax(VERTEX3D &vMin, VERTEX3D &vMax, VERTEX3D v)
{
if(v.x < vMin.x ) vMin.x = v.x;
if(v.y < vMin.y ) vMin.y = v.y;
if(v.z < vMin.z ) vMin.z = v.z;
if(v.x > vMax.x ) vMax.x = v.x;
if(v.y > vMax.y ) vMax.y = v.y;
if(v.z > vMax.z ) vMax.z = v.z;
}

void FormatGeometry(VERTEX3D &v, VERTEX3D vMin, VERTEX3D vMax, float scale)
{
v.x = scale*(v.x - 0.5*(vMin.x + vMax.x));
v.y = scale*(v.y - 0.5*(vMin.y + vMax.y));
v.z = scale*(v.z - 0.5*(vMin.z + vMax.z));
}

{
int i, j;
VERTEX3D vMin, vMax;
char strBuff[512];
char type[512] = "";
bool bStartPropertyCount = true;
float alpha;

vMin.x = vMin.y = vMin.z = 99999.0;
vMax.x = vMax.y = vMax.z = -99999.0;

FILE* fp=fopen(FileName,"r");

if (fp==NULL)
{
printf("ERROR: unable to open model [%s]!\n",FileName);
exit(0);
}

fgets(strBuff, 256, fp);
fgets(strBuff, 256, fp);
fgets(strBuff, 256, fp);

fscanf(fp, "element vertex %d\n", &g_nVerticesNumber);
printf("Number of Vertices: %d\n", g_nVerticesNumber);

/*int i=0;
for(i=0; i<2+g_nVerticesNumber; i++)
{
fgets(strBuff, 256, fp);
}

tri = new TRIANGLE[g_nFacesNumber];
for(i=0; i<g_nFacesNumber; i++)
{
fscanf(fp, "3 %d %d %d", &tri[i].A, &tri[i].B, &tri[i].C);
}*/

j = 0;
char ch;
while (strcmp(type,"element")!=0)
{
//printf("helloworld ");
fgets(strBuff, 256, fp);
i = 0;
while(strBuff[i]!='\0'&&strBuff[i]!=' '&&strBuff[i]!='\n')
{
type[i] = strBuff[i];
i++;
}
if (bStartPropertyCount&&strcmp(type,"property")==0)
j++;
else
bStartPropertyCount = false;
type[i] = '\0';

if(strcmp(type, "element")==0)
{
g_nFacesNumber = atoi(strBuff+13);
printf("Number of Faces: %d \n",g_nFacesNumber);
}
}
fgets(strBuff, 256, fp);
fgets(strBuff, 256, fp);

//Allocate the triangle array
g_vet = new VERTEX3D[g_nVerticesNumber];
g_norm = new VERTEX3D[g_nVerticesNumber];
g_color = new VERTEX3D[g_nVerticesNumber];

for (i=0; i<g_nVerticesNumber; i++)
{
if (j==3)
fscanf(fp, "%f %f %f", &g_vet[i].x, &g_vet[i].y, &g_vet[i].z);
else if(j==6)
fscanf(fp, "%f %f %f %f %f %f", &g_vet[i].x, &g_vet[i].y, &g_vet[i].z, &g_norm[i].x, &g_norm[i].y, &g_norm[i].z);
else if (j==7)
fscanf(fp, "%f %f %f %f %f %f %f", &g_vet[i].x, &g_vet[i].y, &g_vet[i].z, &g_color[i].x, &g_color[i].y, &g_color[i].z, &alpha);
else if (j==10)
fscanf(fp, "%f %f %f %f %f %f %f %f %f %f", &g_vet[i].x, &g_vet[i].y, &g_vet[i].z,
&g_norm[i].x, &g_norm[i].y, &g_norm[i].z,
&g_color[i].x, &g_color[i].y, &g_color[i].z, &alpha);
else
{
printf("Warning: the viewer cann't read the colors of models\n");
exit(1);
}
GetMinMax(vMin, vMax, g_vet[i]);
}

int tem;
tri = new TRIANGLE[g_nFacesNumber];
for(i=0; i<g_nFacesNumber; i++)
{
fscanf(fp, "%d %d %d %d\n", &tem, &tri[i].A, &tri[i].B, &tri[i].C);
}
printf("i is %d", tri[10].B);

/*
for (i=0; i<g_nVerticesNumber; i++)
{
g_color[i].x = (g_vet[i].x - vMin.x)/(vMax.x - vMin.x);
g_color[i].y = (g_vet[i].y - vMin.y)/(vMax.y - vMin.y);
g_color[i].z = (g_vet[i].z- vMin.z)/(vMax.z - vMin.z);
}*/

if((vMax.x - vMin.x) > (vMax.y-vMin.y))
{
if ((vMax.x - vMin.x) > (vMax.z - vMin.z))
g_scale = g_scale/(vMax.x - vMin.x);
else
g_scale = g_scale/(vMax.z - vMin.z);
}
else
{
if ((vMax.y - vMin.y) > (vMax.z - vMin.z))
g_scale = g_scale/(vMax.y - vMin.y);
else
g_scale = g_scale/(vMax.z - vMin.z);
}

for (i=0; i<g_nVerticesNumber; i++)
FormatGeometry(g_vet[i], vMin, vMax, g_scale);

fclose(fp);
}

void DrawVertices()
{
int i;

/* glEnable(GL_LIGHTING);
glPointSize(2.0);
glBegin(GL_POINTS);
for (i=0; i<g_nVerticesNumber; i++)
{
//glColor3f(g_color[i].x, g_color[i].y, g_color[i].z);
glNormal3f(g_norm[i].x, g_norm[i].y, g_norm[i].z);
glVertex3f(g_vet[i].x, g_vet[i].y, g_vet[i].z);
}
glEnd();*/

glEnable(GL_LIGHTING);
for(i=0;i<g_nFacesNumber;i++)
{
glBegin(GL_LINES);
{
glVertex3d(g_vet[tri[i].A].x,g_vet[tri[i].A].y,g_vet[tri[i].A].z);
glVertex3d(g_vet[tri[i].B].x,g_vet[tri[i].B].y,g_vet[tri[i].B].z);
glVertex3d(g_vet[tri[i].C].x,g_vet[tri[i].C].y,g_vet[tri[i].C].z);
}
glEnd();
}
}

static void resize(int width, int height)
{
const float ar = (float) width / (float) height;

glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
gluPerspective(45, ar, 1.0, 100.0);

glMatrixMode(GL_MODELVIEW);
}

static void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glTranslatef(g_modelPos[0], g_modelPos[1], g_modelPos[2]);
glRotatef(g_rotx, 1.0, 0.0, 0.0);
glRotatef(g_roty, 0.0, 1.0, 0.0);
glRotatef(g_rotz, 0.0, 0.0, 1.0);

DrawVertices();

glutSwapBuffers();
}

static void key(unsigned char key, int x, int y)
{
switch (key)
{
case 27 :
exit(0);
break;
case 'w':
g_rotx += 5;
break;
case 's':
g_rotx -= 5;
break;
case 'a':
g_roty += 5;
break;
case 'd':
g_roty -= 5;
break;
case 'q':
g_rotz += 5;
break;
case 'e':
g_rotz -= 5;
break;
case 'z':
g_modelPos[2] += 1;
break;
case 'x':
g_modelPos[2] -= 1;
break;
}

glutPostRedisplay();
}

static void idle(void)
{
glutPostRedisplay();
}

int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(10,10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

printf("Tips: use 'w', 's', 'a', 'd', 'z', 'x', 'q', 'e' keys to control the model\n");
if(argc<2)
{
printf("Input the file name (without postfix e.g. .ply) of points:");
scanf("%s", g_strModelName);
strcat(g_strModelName, ".ply");
}
else
{
printf("%s\n", argv[1]);
strcpy(g_strModelName, argv[1]);
}

glutCreateWindow("PLY Model Viewer");

glutReshapeFunc(resize);
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutIdleFunc(idle);

glClearColor(0.2, 0.55,1.0,1);
glDisable(GL_CULL_FACE);

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);

glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0, GL_POSITION, g_lightPos);