二进制格式 PLY 模型文件的读取与渲染

PLY 文件头部信息:

ply
format binary_little_endian 1.0
comment VCGLIB generated
element vertex 13469
property float x
property float y
property float z
property float nx
property float ny
property float nz
property uchar red
property uchar green
property uchar blue
property uchar alpha
element face 26934
property list uchar int vertex_indices
end_header

完整可运行的 C++ 代码(基于 GLUT)

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>
#include <cstdlib>
using namespace std;

const int TRANSFORM_NONE = 0;
const int TRANSFORM_ROTATE = 1;
const int TRANSFORM_SCALE = 2;
const int TRANSFORM_TRANSLATE = 3;
static int press_x, press_y;

const int LIGHT_NUM = 3;
int current_light = 0;
static float x_angle = 0.0;
static float y_angle = 0.0;
static float scale_size = 1;
static float x_dist = 0.0;
static float y_dist = 0.0;
static int obj_mode = 0;
static int xform_mode = 0;
static int proj_mode = 0;

// 存储定点信息
struct Vertex
{
    double x, y, z;
    double r, g, b, a;
    double nx, ny, nz;
};

// 存储与表面相关的顶点
struct Face
{
    int v1, v2, v3;
};

vector<Vertex> vertices;
vector<Face>   faces;

// 加载 PLY 文件;此处为了方便硬编码有关格式;格式参考:http://paulbourke.net/dataformats/ply/
bool load_ply()
{
    char fname[] = "data.ply";
    FILE* f = fopen(fname, "rb");
    if (f == NULL)
    {
        cout << "file " << fname << " does not exist" << endl;
        return false;
    }
    int counter = 0;
    while (counter < 17)
    {
        char c;
        fread((void*)(&c), sizeof(c), 1, f);
        if (c == '\n') {
            counter++;
        }
    }
    int vertex_num = 13469;
    int face_num = 26934;
    for (int i = 0; i < vertex_num; i++) {
        float x, y, z;
        fread((void*)(&x), 4, 1, f);
        fread((void*)(&y), 4, 1, f);
        fread((void*)(&z), 4, 1, f);
        float nx, ny, nz;
        fread((void*)(&nx), 4, 1, f);
        fread((void*)(&ny), 4, 1, f);
        fread((void*)(&nz), 4, 1, f);
        unsigned char r, g, b, a;
        fread((void*)(&r), 1, 1, f);
        fread((void*)(&g), 1, 1, f);
        fread((void*)(&b), 1, 1, f);
        fread((void*)(&a), 1, 1, f);
        Vertex vertex;
        vertex.x = x / 1000;
        vertex.y = y / 1000;
        vertex.z = z / 1000;
        vertex.nx = nx;
        vertex.ny = ny;
        vertex.nz = nz;
        vertex.r = r;
        vertex.g = g;
        vertex.b = b;
        vertex.a = a;
        vertices.push_back(vertex);
    }
    for (int i = 0; i < face_num; i++) {
        unsigned char n;
        int v1, v2, v3;
        fread((unsigned char*)(&n), 1, 1, f);
        fread((void*)(&v1), 4, 1, f);
        fread((void*)(&v2), 4, 1, f);
        fread((void*)(&v3), 4, 1, f);
        Face face;
        face.v1 = v1;
        face.v2 = v2;
        face.v3 = v3;
        faces.push_back(face);
    }
    fclose(f);
    return true;
}

void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glutPostRedisplay();
}

void display(void)
{
    glEnable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glShadeModel(GL_SMOOTH);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60, 1, 0.1, 100);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0, 0, 3, 0, 0, 0, 0, 1, 0);

    // 设置光源
    GLfloat light_position[] = { 0.0, 0.0, 1.0, 1.0 };
    GLfloat light_direction[] = { 0.0, 0.0, -1.0 };
    GLfloat white_color[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat red_color[] = { 1.0, 0.0, 0.0, 1.0 };
    GLfloat green_color[] = { 0.0, 1.0, 0.0, 1.0 };
    GLfloat blue_color[] = { 0.0, 0.0, 1.0, 1.0 };
    GLfloat exponent[] = { 10.0f };
    GLfloat cutoff[] = { 20.0f };
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    switch (current_light)
    {
    case 1:
        cutoff[0] = 45;
        exponent[0] = 20;
        glLightfv(GL_LIGHT0, GL_SPOT_EXPONENT, exponent);
        glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, cutoff);
        glLightfv(GL_LIGHT0, GL_SPECULAR, white_color);
        break;
    case 2:
        glLightfv(GL_LIGHT0, GL_SPECULAR, green_color);
        glLightfv(GL_LIGHT0, GL_DIFFUSE, green_color);
        glLightfv(GL_LIGHT0, GL_AMBIENT, green_color);
        glLightfv(GL_LIGHT0, GL_SPOT_EXPONENT, exponent);
        glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, cutoff);
        glLightfv(GL_LIGHT0, GL_SPECULAR, white_color);
        break;
    default:
        exponent[0] = 0;
        cutoff[0] = 180;
        glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_direction);
        glLightfv(GL_LIGHT0, GL_SPOT_EXPONENT, exponent);
        glLightfv(GL_LIGHT0, GL_SPOT_CUTOFF, cutoff);
        glLightfv(GL_LIGHT0, GL_SPECULAR, white_color);
        glLightfv(GL_LIGHT0, GL_DIFFUSE, white_color);
        glLightfv(GL_LIGHT0, GL_AMBIENT, white_color);
        glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0);
        glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.0);
        glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.0);
        break;
    }

    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHTING);

    glTranslatef(x_dist, -y_dist, 0);
    glRotatef(x_angle, 0, 1, 0);
    glRotatef(y_angle, 1, 0, 0);
    glScalef(scale_size, scale_size, scale_size);
    glEnable(GL_LIGHTING);


    for (int i = 0; i < (int)faces.size(); i++)
    {
        Face f = faces[i];
        Vertex v1 = vertices[f.v1];
        Vertex v2 = vertices[f.v2];
        Vertex v3 = vertices[f.v3];

        glBegin(GL_TRIANGLES);
        glColor3f(1, 0, 0);
        glNormal3f(v1.nx, v1.ny, v1.nz);
        glVertex3f(v1.x, v1.y, v1.z);
        glNormal3f(v2.nx, v2.ny, v2.nz);
        glVertex3f(v2.x, v2.y, v2.z);
        glNormal3f(v3.nx, v3.ny, v3.nz);
        glVertex3f(v3.x, v3.y, v3.z);
        glEnd();

    }
    glutSwapBuffers();
}


void mouse(int button, int state, int x, int y)
{
    if (state == GLUT_DOWN)
    {
        press_x = x; press_y = y;
        if (button == GLUT_LEFT_BUTTON)
            xform_mode = TRANSFORM_ROTATE;
        else if (button == GLUT_MIDDLE_BUTTON)
            xform_mode = TRANSFORM_TRANSLATE;
        else if (button == GLUT_RIGHT_BUTTON)
            xform_mode = TRANSFORM_SCALE;
    }
    else if (state == GLUT_UP)
    {
        xform_mode = TRANSFORM_NONE;
    }
}

void mouseMotion(int x, int y)
{
    if (xform_mode == TRANSFORM_ROTATE)
    {
        x_angle += (x - press_x) / 5.0;

        if (x_angle > 180)
            x_angle -= 360;
        else if (x_angle < -180)
            x_angle += 360;

        press_x = x;

        y_angle += (y - press_y) / 5.0;

        if (y_angle > 180)
            y_angle -= 360;
        else if (y_angle < -180)
            y_angle += 360;

        press_y = y;
    }
    else if (xform_mode == TRANSFORM_SCALE)
    {
        float old_size = scale_size;

        scale_size *= (1 + (y - press_y) / 60.0);

        if (scale_size < 0)
            scale_size = old_size;
        press_y = y;
    }
    else if (xform_mode == TRANSFORM_TRANSLATE)
    {
        x_dist += (x - press_x) / 50.0;
        press_x = x;

        y_dist += (y - press_y) / 50.0;
        press_y = y;
    }

    // force the redraw function
    glutPostRedisplay();
}

void keyboard(unsigned char key, int x, int y)
{
    switch (key)
    {
    case 'l':
        current_light++;
        current_light %= LIGHT_NUM;
        cout << "Change light source:" << current_light << endl;
        break;
    case 'd':
        x_dist += 0.05;
        break;
    case 'a':
        x_dist -= 0.05;
        break;
    case 's':
        y_dist += 0.05;
        break;
    case 'w':
        y_dist -= 0.05;
        break;
    }
    glutPostRedisplay();
}


int main(int argc, char** argv)
{
    cout << "Help:\n1. Press W A S D to move model.\n2. Press L to change light source.\n3. Drag mouse's left button to rotate model.\n4. Drag mouse's right button to move model." << endl;
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize(600, 600);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("Team Project");
    if (!load_ply())
    {
        cerr << "Load ply file failed!" << endl;
        return -1;
    }
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glutDisplayFunc(display);
    glutMouseFunc(mouse);
    glutMotionFunc(mouseMotion);
    glutKeyboardFunc(keyboard);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return 1;
}
上一篇:python+pygame制作一个可自定义的动态时钟和详解


下一篇:python turtle库