一、 .obj文件格式简介
.obj是一种常见的3D模型文件格式,它由Wavefront Technologies公司开发,是一种文本格式。
.obj文件通常包含了一个3D模型的网格数据、纹理坐标、法向量和多组材质定义等信息,可以被大部分3D软件支持。
下面是一份简单的.obj文件示例:
v 0.0 0.0 0.0 v 1.0 0.0 0.0 v 0.0 1.0 0.0 f 1 2 3
二、 学习.obj文件中的基本概念
1. 顶点(Vertex)
在.obj文件中,顶点是指一个3D模型中的一个坐标点。.obj文件中用“v”表示顶点,后面跟随着顶点的xyz坐标值。
v 0.0 0.0 0.0 v 1.0 0.0 0.0 v 0.0 1.0 0.0
2. 法向量(Normal)
法向量是一个3D模型表面的一个向量,它垂直于表面。
.obj文件中使用“vn”表示顶点法向量,后面跟随着法向量的xyz坐标值。
vn 0.0 0.0 1.0 vn 0.0 0.0 1.0 vn 0.0 0.0 1.0
3. 纹理坐标(Texture Coordinate)
纹理坐标是3D模型表面的一个点,指定了该点在纹理图像上的位置。
.obj文件中使用“vt”表示纹理坐标,后面跟随着纹理坐标的uv值。
vt 0.0 0.0 vt 1.0 0.0 vt 0.0 1.0
4. 面(Face)
面是由多个顶点组成的一个平面,它一般由三角形或四边形构成。
.obj文件中使用“f”表示面,后面跟随着组成该面的顶点、纹理、法向量索引。
f 1/1/1 2/2/1 3/3/1
三、读取和处理.obj文件
1. 读取.obj文件
读取一个.obj文件可以分为以下几个步骤:
- 打开文件。
- 按行读取文件内容。
- 根据每行内容解析出相应的顶点、法向量和纹理坐标等信息。
下面给出一个C++的读取.obj文件的示例代码:
#include <iostream> #include <fstream> #include <vector> struct Vertex { float x, y, z; }; struct TextureCoord { float u, v; }; struct Normal { float x, y, z; }; struct Face { std::vector<int> vertexIndices; std::vector<int> textureIndices; std::vector<int> normalIndices; }; int main() { std::vector<Vertex> vertices; std::vector<TextureCoord> textureCoords; std::vector<Normal> normals; std::vector<Face> faces; std::ifstream objFile("model.obj"); if (!objFile.is_open()) { std::cerr << "Failed to open file!\n"; return -1; } std::string line; while (std::getline(objFile, line)) { std::istringstream iss(line); std::string identifier; if (!(iss >> identifier)) { continue; } if (identifier == "v") { Vertex vertex{}; iss >> vertex.x >> vertex.y >> vertex.z; vertices.emplace_back(vertex); } else if (identifier == "vt") { TextureCoord textureCoord{}; iss >> textureCoord.u >> textureCoord.v; textureCoords.emplace_back(textureCoord); } else if (identifier == "vn") { Normal normal{}; iss >> normal.x >> normal.y >> normal.z; normals.emplace_back(normal); } else if (identifier == "f") { Face face{}; std::string faceLine; std::getline(iss, faceLine); std::istringstream iss2(faceLine); int index; char slash; while (iss2 >> index) { face.vertexIndices.emplace_back(index); iss2 >> slash; if (iss2.peek() != '/') { continue; } iss2.ignore(); if (iss2.peek() == '/') { iss2.ignore(); iss2 >> index; face.normalIndices.emplace_back(index); } else { iss2 >> index; face.textureIndices.emplace_back(index); if (iss2.peek() != '/') { continue; } iss2.ignore(); iss2 >> index; face.normalIndices.emplace_back(index); } } faces.emplace_back(face); } else { continue; } } objFile.close(); return 0; }
2. 渲染模型
读取.obj文件后,我们可以使用OpenGL等图形渲染库来渲染3D模型。
下面是一个使用OpenGL渲染一个.obj模型的C++示例代码:
#include <GL/glut.h> void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0f, 0.0f, -3.0f); glBegin(GL_TRIANGLES); for (const auto& face : faces) { for (int i = 0; i < face.vertexIndices.size(); i++) { int vertexIndex = face.vertexIndices[i]; int normalIndex = face.normalIndices[i]; int textureIndex = face.textureIndices[i]; glNormal3f(normals[normalIndex].x, normals[normalIndex].y, normals[normalIndex].z); glTexCoord2f(textureCoords[textureIndex - 1].u, textureCoords[textureIndex - 1].v); glVertex3f(vertices[vertexIndex - 1].x, vertices[vertexIndex - 1].y, vertices[vertexIndex - 1].z); } } glEnd(); glutSwapBuffers(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); glutInitWindowSize(800, 600); glutCreateWindow("Model Viewer"); glutDisplayFunc(display); glEnable(GL_DEPTH_TEST); glutMainLoop(); return 0; }
四、总结
本文介绍了.obj文件的基本格式和概念,以及如何读取和处理.obj文件,并使用OpenGL来渲染一个.obj模型。
读者可以通过本文了解.obj文件和处理方式,对3D模型处理有更深入的理解。