OpenGL 几何造型系统:OBJ 文件读取、细分和极限位置计算
基于 OpenGL 的几何造型系统
该程序实现了以下功能:
- 读取 OBJ 文件:
- 可以读取 OBJ 文件,并根据文件内容识别网格模型的类型(三角网格、四边形网格或多边形网格)。
- 网格模型显示:
- 使用 OpenGL 局部光照显示网格模型,并使用 Laplacian 计算顶点法向量。
- 支持绘制网格边。
- 细分:
- 支持 Catmull-Clark 和 Loop 细分,根据网格模型的类型自动选择细分算法。
- 可以交互式地输入细分次数 l。
- 极限位置计算:
- 可以计算细分 l 次后得到的网格顶点的极限位置。
代码示例
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <GL/glut.h>
// 定义顶点结构体
struct Vertex {
float x, y, z;
};
// 定义面结构体
struct Face {
std::vector<int> vertices; // 顶点索引
};
// 存储模型数据的向量
std::vector<Vertex> vertices;
std::vector<Face> faces;
// 读取obj文件
void readObjFile(const std::string& filename) {
std::ifstream file(filename);
if (!file.is_open()) {
std::cerr << "Failed to open file: " << filename << std::endl;
return;
}
std::string line;
while (std::getline(file, line)) {
std::istringstream iss(line);
std::string prefix;
iss >> prefix;
if (prefix == "v") {
Vertex vertex;
iss >> vertex.x >> vertex.y >> vertex.z;
vertices.push_back(vertex);
} else if (prefix == "f") {
Face face;
std::string vertexStr;
while (iss >> vertexStr) {
std::istringstream viss(vertexStr);
std::string indexStr;
std::getline(viss, indexStr, '/');
int index = std::stoi(indexStr);
face.vertices.push_back(index - 1); // 索引从0开始
}
faces.push_back(face);
}
}
file.close();
}
// 绘制模型
void drawModel() {
for (const Face& face : faces) {
if (face.vertices.size() == 3) { // 三角网格模型
glBegin(GL_TRIANGLES);
} else if (face.vertices.size() == 4) { // 四边形网格模型
glBegin(GL_QUADS);
} else { // 多边形网格模型
glBegin(GL_POLYGON);
}
for (int vertexIndex : face.vertices) {
const Vertex& vertex = vertices[vertexIndex];
glVertex3f(vertex.x, vertex.y, vertex.z);
}
glEnd();
}
}
// 计算顶点法向量
std::vector<Vertex> calculateVertexNormals() {
std::vector<Vertex> normals(vertices.size());
for (const Face& face : faces) {
int numVertices = face.vertices.size();
for (int i = 0; i < numVertices; i++) {
int currIndex = face.vertices[i];
int prevIndex = face.vertices[(i - 1 + numVertices) % numVertices];
int nextIndex = face.vertices[(i + 1) % numVertices];
const Vertex& currVertex = vertices[currIndex];
const Vertex& prevVertex = vertices[prevIndex];
const Vertex& nextVertex = vertices[nextIndex];
Vertex edge1 = {prevVertex.x - currVertex.x, prevVertex.y - currVertex.y, prevVertex.z - currVertex.z};
Vertex edge2 = {nextVertex.x - currVertex.x, nextVertex.y - currVertex.y, nextVertex.z - currVertex.z};
Vertex normal = {
edge1.y * edge2.z - edge1.z * edge2.y,
edge1.z * edge2.x - edge1.x * edge2.z,
edge1.x * edge2.y - edge1.y * edge2.x
};
normals[currIndex].x += normal.x;
normals[currIndex].y += normal.y;
normals[currIndex].z += normal.z;
}
}
for (Vertex& normal : normals) {
float length = std::sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);
normal.x /= length;
normal.y /= length;
normal.z /= length;
}
return normals;
}
// 绘制边
void drawEdges() {
glColor3f(0.0f, 0.0f, 0.0f);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
for (const Face& face : faces) {
glBegin(GL_POLYGON);
for (int vertexIndex : face.vertices) {
const Vertex& vertex = vertices[vertexIndex];
glVertex3f(vertex.x, vertex.y, vertex.z);
}
glEnd();
}
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
// 绘制函数
void display() {
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
// 设置光照属性
GLfloat lightPosition[] = {1.0f, 1.0f, 1.0f, 0.0f};
GLfloat lightAmbient[] = {0.2f, 0.2f, 0.2f, 1.0f};
GLfloat lightDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
GLfloat lightSpecular[] = {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat materialSpecular[] = {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat shininess[] = {50.0f};
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpecular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, materialSpecular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
// 绘制模型
drawModel();
// 绘制边
drawEdges();
glFlush();
glutSwapBuffers();
}
// 初始化函数
void init() {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <obj_file>" << std::endl;
return 1;
}
std::string filename = argv[1];
readObjFile(filename);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(800, 800);
glutCreateWindow("Geometry Modeling System");
glutDisplayFunc(display);
init();
glutMainLoop();
return 0;
}
使用说明
- 将代码保存为
.cpp文件,例如geometry_modeling_system.cpp。 - 确保已安装 OpenGL 和 GLUT 库。
- 编译代码,例如:
$ g++ geometry_modeling_system.cpp -lglut -lGL -o geometry_modeling_system
- 运行程序,并传递 OBJ 文件作为参数,例如:
$ ./geometry_modeling_system model.obj
注意事项
- 该示例代码仅供参考,需要根据具体需求进行修改和完善。
- 代码中还缺少 Catmull-Clark 和 Loop 细分算法的实现,需要自行添加。
- 极限位置的计算需要根据具体的细分算法进行实现。
- 可以使用鼠标或键盘交互式地设置细分次数和调整模型视图。
- 可以添加其他功能,例如:
- 支持多种模型文件格式,例如 PLY、STL 等。
- 支持模型的编辑功能,例如 添加、删除、移动顶点和面。
- 支持模型的材质和纹理设置。
总结
该程序为基于 OpenGL 的几何造型系统提供了基础框架,可以根据实际需求进行扩展和完善。
原文地址: https://www.cveoy.top/t/topic/o8Et 著作权归作者所有。请勿转载和采集!