|
使用glut,编写一个wrl和obj模型文件浏览工具,可以通过鼠标左键进行上下左右旋转3D模型,x键放大y键缩小。有基础的全局环境光照和透视效果。
让这个代码支持stp stl文件
回到最初的代码,让opengl显示出模型棱角的线条
- #include <GL/glut.h>
- #include <iostream>
- #include <fstream>
- #include <sstream>
- #include <vector>
- #include <string>
- #include <cstring>
- #include <stdlib.h>
- // 模型数据
- std::vector<float> vertices;
- std::vector<int> indices;
- // 旋转角度
- float rotateX = 0.0f;
- float rotateY = 0.0f;
- // 缩放因子
- float scaleFactor = 1.0f;
- // 鼠标状态
- bool mouseLeftDown = false;
- int lastMouseX = 0;
- int lastMouseY = 0;
- // 读取OBJ文件
- void loadOBJ(const std::string& filename) {
- std::ifstream file(filename.c_str());
- if (!file.is_open()) {
- std::cerr << "无法打开文件: " << filename << std::endl;
- return;
- }
- std::string line;
- while (std::getline(file, line)) {
- std::istringstream iss(line);
- std::string type;
- iss >> type;
- if (type == "v") {
- float x, y, z;
- iss >> x >> y >> z;
- vertices.push_back(x);
- vertices.push_back(y);
- vertices.push_back(z);
- } else if (type == "f") {
- int v1, v2, v3;
- std::string vertex1, vertex2, vertex3;
- iss >> vertex1 >> vertex2 >> vertex3;
- v1 = atol(vertex1.substr(0, vertex1.find('/')).c_str()) - 1;
- v2 = atol(vertex2.substr(0, vertex2.find('/')).c_str()) - 1;
- v3 = atol(vertex3.substr(0, vertex3.find('/')).c_str()) - 1;
- indices.push_back(v1);
- indices.push_back(v2);
- indices.push_back(v3);
- }
- }
- file.close();
- }
- // 读取 ASCII STL 文件
- void loadASCIISTL(const std::string& filename) {
- std::ifstream file(filename.c_str());
- if (!file.is_open()) {
- std::cerr << "无法打开文件: " << filename << std::endl;
- return;
- }
- std::string line;
- while (std::getline(file, line)) {
- std::istringstream iss(line);
- std::string type;
- iss >> type;
- if (type == "vertex") {
- float x, y, z;
- iss >> x >> y >> z;
- vertices.push_back(x);
- vertices.push_back(y);
- vertices.push_back(z);
- indices.push_back(vertices.size() / 3 - 1);
- }
- }
- file.close();
- }
- // 读取二进制 STL 文件
- void loadBinarySTL(const std::string& filename) {
- std::ifstream file(filename.c_str(), std::ios::binary);
- if (!file.is_open()) {
- std::cerr << "无法打开文件: " << filename << std::endl;
- return;
- }
- char header[80];
- file.read(header, 80);
- unsigned int numTriangles;
- file.read(reinterpret_cast<char*>(&numTriangles), 4);
- for (unsigned int i = 0; i < numTriangles; ++i) {
- float normal[3];
- file.read(reinterpret_cast<char*>(normal), 12);
- for (int j = 0; j < 3; ++j) {
- float vertex[3];
- file.read(reinterpret_cast<char*>(vertex), 12);
- vertices.push_back(vertex[0]);
- vertices.push_back(vertex[1]);
- vertices.push_back(vertex[2]);
- indices.push_back(vertices.size() / 3 - 1);
- }
- unsigned short attributeByteCount;
- file.read(reinterpret_cast<char*>(&attributeByteCount), 2);
- }
- file.close();
- }
- // 自动检测并加载 STL 文件
- void loadSTL(const std::string& filename) {
- std::ifstream file(filename.c_str());
- std::string firstLine;
- std::getline(file, firstLine);
- file.close();
- if (firstLine.find("solid") != std::string::npos) {
- loadASCIISTL(filename);
- } else {
- loadBinarySTL(filename);
- }
- }
- // 初始化OpenGL设置
- void init() {
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
- glEnable(GL_DEPTH_TEST);
- // 启用光照
- glEnable(GL_LIGHTING);
- glEnable(GL_LIGHT0);
- // 设置环境光
- GLfloat ambientLight[] = {0.2f, 0.2f, 0.2f, 1.0f};
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);
- // 设置光源位置
- GLfloat lightPosition[] = {1.0f, 1.0f, 1.0f, 0.0f};
- glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
- // 设置材质属性
- GLfloat materialDiffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
- glMaterialfv(GL_FRONT, GL_DIFFUSE, materialDiffuse);
- // 设置多边形渲染模式为线框模式
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- }
- // 显示回调函数
- void display() {
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- // 设置相机位置
- gluLookAt(0.0f, 0.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
- // 应用旋转和缩放
- glRotatef(rotateX, 1.0f, 0.0f, 0.0f);
- glRotatef(rotateY, 0.0f, 1.0f, 0.0f);
- glScalef(scaleFactor, scaleFactor, scaleFactor);
- // 绘制模型
- glBegin(GL_TRIANGLES);
- for (size_t i = 0; i < indices.size(); i++) {
- int index = indices[i];
- glVertex3f(vertices[index * 3], vertices[index * 3 + 1], vertices[index * 3 + 2]);
- }
- glEnd();
- glutSwapBuffers();
- }
- // 调整窗口大小回调函数
- void reshape(int width, int height) {
- if (height == 0) height = 1;
- float aspect = (float)width / (float)height;
- glViewport(0, 0, width, height);
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPerspective(45.0f, aspect, 0.1f, 100.0f);
- }
- // 鼠标事件回调函数
- void mouse(int button, int state, int x, int y) {
- if (button == GLUT_LEFT_BUTTON) {
- if (state == GLUT_DOWN) {
- mouseLeftDown = true;
- lastMouseX = x;
- lastMouseY = y;
- } else {
- mouseLeftDown = false;
- }
- }
- }
- // 鼠标移动事件回调函数
- void motion(int x, int y) {
- if (mouseLeftDown) {
- int dx = x - lastMouseX;
- int dy = y - lastMouseY;
- rotateX += dy * 0.5f;
- rotateY += dx * 0.5f;
- lastMouseX = x;
- lastMouseY = y;
- glutPostRedisplay();
- }
- }
- // 键盘事件回调函数
- void keyboard(unsigned char key, int x, int y) {
- switch (key) {
- case 'x':
- scaleFactor *= 1.1f;
- glutPostRedisplay();
- break;
- case 'y':
- scaleFactor /= 1.1f;
- glutPostRedisplay();
- break;
- case 27: // ESC键退出
- exit(0);
- break;
- }
- }
- // 检测文件扩展名并加载相应文件
- void loadFile(const std::string& filename) {
- size_t dotPos = filename.find_last_of('.');
- if (dotPos != std::string::npos) {
- std::string extension = filename.substr(dotPos + 1);
- if (extension == "obj") {
- loadOBJ(filename);
- } else if (extension == "stl") {
- loadSTL(filename);
- } else {
- std::cerr << "不支持的文件格式: " << extension << std::endl;
- }
- } else {
- std::cerr << "无法识别文件扩展名" << std::endl;
- }
- }
- int main(int argc, char** argv) {
- if (argc < 2) {
- std::cerr << "用法: " << argv[0] << " <文件路径>" << std::endl;
- return 1;
- }
- // 加载文件
- loadFile(argv[1]);
- // 初始化GLUT
- glutInit(&argc, argv);
- glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
- glutInitWindowSize(800, 600);
- glutCreateWindow("3D模型浏览工具");
- // 初始化OpenGL
- init();
- // 设置回调函数
- glutDisplayFunc(display);
- glutReshapeFunc(reshape);
- glutMouseFunc(mouse);
- glutMotionFunc(motion);
- glutKeyboardFunc(keyboard);
- // 进入主循环
- glutMainLoop();
- return 0;
- }
复制代码 |
|