基于 OpenGL 的几何造型系统

该程序实现了以下功能:

  1. 读取 OBJ 文件:
    • 可以读取 OBJ 文件,并根据文件内容识别网格模型的类型(三角网格、四边形网格或多边形网格)。
  2. 网格模型显示:
    • 使用 OpenGL 局部光照显示网格模型,并使用 Laplacian 计算顶点法向量。
    • 支持绘制网格边。
  3. 细分:
    • 支持 Catmull-Clark 和 Loop 细分,根据网格模型的类型自动选择细分算法。
    • 可以交互式地输入细分次数 l。
  4. 极限位置计算:
    • 可以计算细分 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;
}

使用说明

  1. 将代码保存为 .cpp 文件,例如 geometry_modeling_system.cpp。
  2. 确保已安装 OpenGL 和 GLUT 库。
  3. 编译代码,例如:
$ g++ geometry_modeling_system.cpp -lglut -lGL -o geometry_modeling_system
  1. 运行程序,并传递 OBJ 文件作为参数,例如:
$ ./geometry_modeling_system model.obj

注意事项

  • 该示例代码仅供参考,需要根据具体需求进行修改和完善。
  • 代码中还缺少 Catmull-Clark 和 Loop 细分算法的实现,需要自行添加。
  • 极限位置的计算需要根据具体的细分算法进行实现。
  • 可以使用鼠标或键盘交互式地设置细分次数和调整模型视图。
  • 可以添加其他功能,例如:
    • 支持多种模型文件格式,例如 PLY、STL 等。
    • 支持模型的编辑功能,例如 添加、删除、移动顶点和面。
    • 支持模型的材质和纹理设置。

总结

该程序为基于 OpenGL 的几何造型系统提供了基础框架,可以根据实际需求进行扩展和完善。

OpenGL 几何造型系统:OBJ 文件读取、细分和极限位置计算

原文地址: https://www.cveoy.top/t/topic/o8Et 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录