二进制格式 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 == '
') {
			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:
1. Press W A S D to move model.
2. Press L to change light source.
3. Drag mouse's left button to rotate model.
4. 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;
}
原文地址:https://www.cnblogs.com/justsong/p/12219716.html