一、.obj文件简介
OBJ文件是一种包含三维几何体信息的文件格式,它包括物体的位置、法线、纹理坐标和面信息。该格式最初是由AutoCAD创建的,现在被广泛用于3D图形应用程序中
OBJ文件是一种包含模型和材质数据的文本文件,其结构非常简单:文件头信息、顶点和法线、纹理坐标、面等。在OBJ文件中,每行都表示一个参数,用空格或者制表符分隔。这使得它成为一种简单、通用的格式,因为几乎任何3D图形软件都能读取和写入OBJ格式。因此,OBJ文件成为了3D图形软件间通用的桥梁。
二、.obj文件的结构
OBJ文件的结构由一系列的组成部分组成:
1.文件头
OBJ文件格式的第一行通常是格式说明。在这一行中,#代表注释(注释应该位于该行的开头),后面可以跟着一些数字或字母代表该文件的格式版本、作者等信息。
# This is a Wavefront OBJ file # File created by Blender
2.顶点和法线
OBJ文件保存的每个物体顶点都以”v”开头的一行开始,后面跟着xyz三个浮点数表示三维位置坐标。此外,以”vn”开头的行代表了每个顶点的法向量。
# Vertex coordinates v 0.0 0.0 0.0 v 1.0 0.0 0.0 v 0.0 1.0 0.0 vn 0.0 0.0 1.0 vn 0.0 0.0 1.0 vn 0.0 0.0 1.0
3.纹理坐标
使用”vt”开头的行表示每个顶点的纹理坐标。纹理坐标通常是二维的,以u,v两个浮点数表示。
# Texture coordinates vt 0.0 0.0 vt 1.0 0.0 vt 0.0 1.0
4.面
面的定义以”f”开头的一行开始,后跟一系列整数表示该面顶点的索引号。索引号指向前面定义的顶点列表和纹理坐标列表。面的定义可以使用两种不同的格式表示:单个面和多重面。单个面只包含三个顶点,多重面可以包含任意数量的顶点。
# Face definitions f 1/1/1 2/2/2 3/3/3 f 1/1/1 3/3/3 4/4/4
5.材质和组
OBJ文件格式还支持材质和组。使用”mtllib”定义材质库,使用”usemtl”定义使用材质,使用”g”定义物体组。
# Material definitions mtllib example.mtl usemtl red usemtl green # Object groups g object1 g object2
三、示例代码
下面是一个读取并打印OBJ文件的C++函数示例:
#include
#include
#include
#include
#include
struct Vec3 {
float x, y, z;
};
struct Vec2 {
float u, v;
};
struct TriangleIndex {
int vertexIdx[3];
int normalIdx[3];
int texIdx[3];
};
std::vector vertices;
std::vector normals;
std::vector texCoords;
std::vector indices;
void loadObj(const std::string& filename) {
std::ifstream file(filename);
std::string line;
while (std::getline(file, line)) {
std::istringstream iss(line);
char c;
if (!(iss >> c))
continue;
switch (c) {
case 'v':
if (iss.peek() == 'n') {
Vec3 normal;
iss >> c;
iss >> normal.x;
iss >> normal.y;
iss >> normal.z;
normals.push_back(normal);
} else if (iss.peek() == 't') {
Vec2 texCoord;
iss >> c;
iss >> texCoord.u;
iss >> texCoord.v;
texCoords.push_back(texCoord);
} else {
Vec3 vertex;
iss >> vertex.x;
iss >> vertex.y;
iss >> vertex.z;
vertices.push_back(vertex);
}
break;
case 'f': {
TriangleIndex index;
for (int i = 0; i > index.vertexIdx[i];
if (iss.peek() == '/') {
iss.ignore();
if (iss.peek() != '/') {
iss >> index.texIdx[i];
}
if (iss.peek() == '/') {
iss.ignore();
iss >> index.normalIdx[i];
}
}
}
indices.push_back(index);
break;
}
}
}
}
int main() {
std::string filename = "example.obj";
loadObj(filename);
printf("Vertices:\n");
for (const auto& v : vertices) {
printf("%f %f %f\n", v.x, v.y, v.z);
}
printf("Normals:\n");
for (const auto& n : normals) {
printf("%f %f %f\n", n.x, n.y, n.z);
}
printf("Texture coordinates:\n");
for (const auto& t : texCoords) {
printf("%f %f\n", t.u, t.v);
}
printf("Faces:\n");
for (const auto& i : indices) {
printf("%d/%d/%d %d/%d/%d %d/%d/%d\n", i.vertexIdx[0], i.texIdx[0], i.normalIdx[0],
i.vertexIdx[1], i.texIdx[1], i.normalIdx[1],
i.vertexIdx[2], i.texIdx[2], i.normalIdx[2]);
}
return 0;
}
原创文章,作者:EAVKW,如若转载,请注明出处:https://www.506064.com/n/371105.html
微信扫一扫
支付宝扫一扫