二进制格式 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;
}
【未经允许,禁止转载】