MD2/MD3无通用解析库支持,需手动解析或启用Assimp的MD2插件;MD2头68字节含固定字段,顶点为压缩字节需映射,UV需归一化;MD3更复杂,含surface分组、delta动画、定点数坐标,且依赖外部skin与shader文件。

MD2/MD3不是标准格式,没有通用解析库
直接用 tinyobjloader 或 assimp 加载 MD2/MD3 会失败——它们默认不支持。Assimp 虽然在较新版本(5.0+)中通过编译选项启用了 MD2 支持,但默认关闭;MD3 更是完全未被官方支持。你得自己读二进制结构,或启用并验证 Assimp 的 MD2 插件。
MD2 文件头结构固定,必须按字节偏移解析
MD2 是 Quake II 使用的旧格式,头部共 68 字节,含魔法数 "IDP2"、顶点数 num_vertices、帧数 num_frames、纹理坐标数 num_skins 等。常见错误包括:
- 误把
skinwidth/skinheight当作贴图尺寸(实际是 UV 坐标归一化分母,需除以它才能得到[0,1]范围) - 跳过帧数据时没按
framesize = 40 + num_vertices * 6计算(每个顶点占 6 字节:3 字节位置 + 1 字节法向量索引 + 2 字节对齐填充) - 读取顶点坐标时忽略“压缩顶点”:X/Y/Z 各为无符号字节,需映射到
[min_bounds, max_bounds](从帧头中读出)
示例关键字段读取:
struct md2_header_t {
char magic[4]; // 必须是 "IDP2"
int version; // 应为 8
int skin_width;
int skin_height;
int frame_size; // 单帧字节数,用于定位下一帧
int num_skins;
int num_vertices;
int num_st; // UV 数(通常等于顶点数)
int num_tris;
int num_frames;
int offset_skins; // 皮肤名起始偏移
int offset_st; // UV 坐标起始偏移
int offset_tris; // 三角面片起始偏移
int offset_frames; // 帧数据起始偏移
int offset_glcmds; // OpenGL command list(可忽略)
int offset_end; // 文件末尾偏移
};
MD3 更复杂:含多层命名、动画分段与 Q3A 引擎依赖
MD3(Quake III Arena)不是单文件模型,而是由 .md3 + .skin + 贴图路径共同构成。它支持“tag”(骨骼参考点)、“surfaces”(子模型分组)、“shaders”(着色器引用),且动画帧是差分编码(delta-compressed)。关键难点:
-
magic是"IDP3",但版本号为 15,不是 3 —— 错判版本会导致后续解析错位 - 每个
surface有独立的顶点/UV/面片,且num_frames是整个文件的总帧数,不是该 surface 的帧数 - 顶点坐标是 float[3],但存储为 16 位定点数(
short),需缩放:除以1.0f / 64.0f(即乘以 64)还原精度 - 动画插值必须基于 base frame + delta frame,不能直接线性插值 raw vertex data
典型 surface header 中重要字段:name(最多 64 字节,含
典型 surface header 中重要字段:name(最多 64 字节,含 \0)、num_shaders(实际常为 1)、num_verts、num_triangles、ofs_triangles、ofs_shaders、ofs_uv、ofs_vertices。
num_shaders(实际常为 1)、num_verts、num_triangles、ofs_triangles、ofs_shaders、ofs_uv、ofs_vertices。
立即学习“C++免费学习笔记(深入)”;
用 Assimp 加载 MD2 要手动开启并验证插件
Assimp 5.2+ 编译时需定义 ASSIMP_BUILD_MD2_IMPORTER,否则 aiImportFile(..., aiProcess_Triangulate) 对 MD2 返回空场景。运行时还需确认:
- 文件扩展名必须是
".md2"(大小写敏感,".MD2"可能失败) - 返回的
aiScene*中mNumMeshes> 0,且每个aiMesh::mNumVertices不为 0 - UV 坐标在
aiMesh::mTextureCoords[0],但 MD2 的 UV 是整数,需手动归一化:u = st.u / header.skin_width - 顶点法向量需查表:MD2 只存 1 字节索引(0–255),对应预定义的
anorms法向量表
如果你看到 aiScene::mRootNode == nullptr 或所有 mesh 的 mNumFaces == 0,大概率是插件没启用,或文件魔数校验失败(比如被截断或误用 MD3 文件当 MD2 传入)。
MD2/MD3 解析真正麻烦的不是结构本身,而是引擎上下文缺失:没有材质路径约定、没有动画状态机定义、没有 tag hierarchy 语义。你读出来的顶点和 UV,离能渲染还差 shader 绑定、骨骼权重、动画时间轴同步这三步——而这三步,原始格式里一个都没规定。



















