111 lines
3.2 KiB
C++
111 lines
3.2 KiB
C++
#pragma once
|
||
#include <string>
|
||
#include <vector>
|
||
#include "vde/foundation/math_types.h"
|
||
|
||
namespace vde::foundation {
|
||
|
||
/**
|
||
* @brief OBJ 文件解析结果数据结构
|
||
*
|
||
* 存储从 Wavefront OBJ 文件读取的完整几何数据,
|
||
* 包括顶点位置、纹理坐标、法线、面信息和材质分组。
|
||
*
|
||
* 内部索引均为 0-based,与文件中的 1-based 索引不同。
|
||
*
|
||
* @ingroup foundation
|
||
*/
|
||
struct ObjMeshData {
|
||
/// 顶点位置数组
|
||
std::vector<Point3D> vertices;
|
||
/// 纹理坐标数组(可能为空)
|
||
std::vector<Point2D> texcoords;
|
||
/// 顶点法线数组(可能为空)
|
||
std::vector<Vector3D> normals;
|
||
|
||
/**
|
||
* @brief 每个面的顶点索引列表(0-based)
|
||
*
|
||
* 无论文件中面的格式如何(纯顶点、"v/vt"、"v/vt/vn"),
|
||
* 此字段始终被填充。faces[i] 存储第 i 个面的所有顶点索引。
|
||
*/
|
||
std::vector<std::vector<int>> faces;
|
||
|
||
/**
|
||
* @brief 每个面的纹理坐标索引列表(0-based)
|
||
*
|
||
* 与 faces 数组长度相同;若无纹理数据则为空。
|
||
*/
|
||
std::vector<std::vector<int>> face_texcoords;
|
||
|
||
/**
|
||
* @brief 每个面的法线索引列表(0-based)
|
||
*
|
||
* 与 faces 数组长度相同;若无法线数据则为空。
|
||
*/
|
||
std::vector<std::vector<int>> face_normals;
|
||
|
||
/**
|
||
* @brief 每个面对应的材质名称
|
||
*
|
||
* face_materials[i] 给出第 i 个面使用的材质名。
|
||
* 材质名来源于 usemtl 指令,在定义后所有后续面使用该材质。
|
||
*/
|
||
std::vector<std::string> face_materials;
|
||
|
||
/// 是否有纹理坐标数据
|
||
[[nodiscard]] bool has_texcoords() const { return !texcoords.empty(); }
|
||
};
|
||
|
||
/**
|
||
* @brief 读取 Wavefront OBJ 文件
|
||
*
|
||
* 解析 ASCII OBJ 文件,支持以下 OBJ 特性:
|
||
* - v(顶点)、vt(纹理坐标)、vn(法线)
|
||
* - f(面):支持三角面和任意多边形面
|
||
* - usemtl(材质名称)、g(组名)、o(对象名)
|
||
* - # 注释行
|
||
*
|
||
* @param filepath OBJ 文件路径
|
||
* @return 解析后的 ObjMeshData
|
||
*
|
||
* @throws std::runtime_error 若文件无法打开或格式错误
|
||
*
|
||
* @note 不解析 MTL 材质文件,仅记录 usemtl 指令中的材质名称
|
||
* @note 面索引在内部转换为 0-based;若文件中使用相对索引(负值),自动转换为正向
|
||
*
|
||
* @code{.cpp}
|
||
* auto data = read_obj("model.obj");
|
||
* std::cout << "Vertices: " << data.vertices.size() << "\n";
|
||
* std::cout << "Faces: " << data.faces.size() << "\n";
|
||
* @endcode
|
||
*
|
||
* @see write_obj, ObjMeshData
|
||
* @ingroup foundation
|
||
*/
|
||
ObjMeshData read_obj(const std::string& filepath);
|
||
|
||
/**
|
||
* @brief 写入 Wavefront OBJ 文件
|
||
*
|
||
* 将 ObjMeshData 以 ASCII OBJ 格式写出,包含顶点、纹理坐标、
|
||
* 法线和面信息。材质名称通过注释嵌入。
|
||
*
|
||
* @param filepath 输出文件路径
|
||
* @param data 要写出的网格数据
|
||
*
|
||
* @note 输出的面索引为 1-based(OBJ 标准)
|
||
*
|
||
* @code{.cpp}
|
||
* ObjMeshData data;
|
||
* // ... 填充 data ...
|
||
* write_obj("output.obj", data);
|
||
* @endcode
|
||
*
|
||
* @see read_obj
|
||
* @ingroup foundation
|
||
*/
|
||
void write_obj(const std::string& filepath, const ObjMeshData& data);
|
||
|
||
} // namespace vde::foundation
|