一、概述

高级计算机三维建模的课后实习代码托管及重点部分备注。这是第一次实习,题目是读取.ply文件内容,并利用opengl绘制出网格。目前为止,老师布置的4次实习作业都比较简单,这里只是做简要记录,毕竟刚入门。

二、基本思想

如图,为stanford bunny的文件内容
在这里插入图片描述在这里插入图片描述
首先,需要读取文件中vertex和face的数量,初始化数组,依次将点的位置坐标,以及每个三角面片对应的点的索引读入。实际上,在绘制三维网格的时候,并不需要绘制每个点,这里读取的点的坐标是用来绘制线段的。有了这些信息后,直接画就行了。

三、值得注意的问题

在每个实习中,老师都会提供一部分基础代码,只需要在此基础上增加一些代码来补全功能即可。
如下图,老师提供的参考代码是绘制点,要求是绘制网格。
在这里插入图片描述
所以,我一开始自以为然的,肯定就是想着利用GL_TRIANGLES来绘制三角面片了。绘制结果当然是没问题的,而且这种方法也是后来老师给出的参考答案,结果如图:
在这里插入图片描述
但是这样我个人感觉看着不舒服,不是我想要的结果。因为使用GL_TRIANGLES绘制出来的是实心的三角形面,而我想要的是三角形网格。所以我又自以为然的把GL_TRIANGLES换成了GL_LINES,也就是变成:
在这里插入图片描述
然而,运行之后的结果却是这样:
在这里插入图片描述
这我就要吐了呀。没有仔细思考,一直就想着肯定是GL_LINES不对,所以又换成了GL_LINE_STRIP和GL_LINE_LOOP,可是结果依然如此。(虽然这个过程对这个实习没有太大的帮助,但是我掌握了GL_LINES与GL_LINE_STRIP,GL_LINE_LOOP,以及GL_QUADS与GL_QUAD_STRIP的区别。)

后来想了一下,为什么会出现连线纵横交错的情况,原来问题出现在glBegin()的 块 里面,因为在这个块里面,绘制线段的时候,就会一个点连着一个点,而不仅是每三个点连在一起绘制成三角形,会造成不同的三角形也会通过某个线段连接起来。所以,知道了问题所在,只要每次在绘制单个三角形的时候使用一次glBegin()块就可以了,所以就把绘制代码改成:
在这里插入图片描述
这样解决了这个问题,运行结果如下:
在这里插入图片描述
在这种方式下,我又实验了GL_LINE_STRIP,GL_LINE_LOOP,果然,结果都跟我预想的一样是可以的。

四、完整代码

个人觉得这里还有一个比较麻烦的地方是在于对文件内容的字符串处理操作,需要耐心。本次实习所有代码如下:

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));
}

void LoadMeshPLY(char *FileName)
{
    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];



    //Read in the triangles
    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);
    glLoadIdentity();
    gluPerspective(45, ar, 1.0, 100.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity() ;
}

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

    glLoadIdentity() ;

    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);

    glShadeModel(GL_SMOOTH);

    printf("Loading \"%s\"...\n", g_strModelName);
    LoadMeshPLY(g_strModelName);

    glutMainLoop();

    return EXIT_SUCCESS;
}

简单记录,日后好用。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐