[lib3ds] 开源3ds文件解析库(一):基础

3ds 文件是 3D Max 的一种二进制存储格式,用来存储 3D 模型场景。关于这种格式官方的资料很少,从二进制角度解析文件很困难,幸好有个开源的项目lib3ds已经提供了解析的库。

  • 用 ANSI-C 编写
  • 支持的框架:
    • GNU build tools (autoconf, automake, libtool)
    • UNIX
    • Mac OS X
    • Microsoft Visual C++ 8.0
  • 支持小端和大端字节序的 cpu
  • 载入和保存:
    • Atmosphere settings
    • 背景设置 (Background settings)
    • 阴影贴图设置 (Shadow map settings)
    • 视口设置 (Viewport setting)
    • 材质 (Materials)
    • 摄像机 (Cameras)
    • 灯光 (Lights)
    • 网格 (Meshes)
    • 层次结构 (Hierarchy)
    • 关键祯 (Keyframes)
  • 计算动画(关键祯)数据
  • 简单容易操作的数据结构
    • 矢量数学模块
    • 四元数数学模块
  • 矩阵数学模块
  • 与 OpenGL 无缝集成

(1) 坐标系

在 3ds 文件中使用的坐标系是左手坐标系,从左到右,x 递增;从下到上,z 递增;从近到远,y 递增。

在 lib3ds 库中,经过解析,把 3ds 文件中的数据转换成了 OpenGL 采用的右手坐标系,从左到右,x 递增,从下到上 y 递增,从远到近,z 递增。

img

(2) 数学模块

// 矢量数学函数
extern LIB3DSAPI void lib3ds_vector_make(
    float c[3],
    float x,
    float y,
    float z);

/**
    Sets all components of a vector to zero.
    \param c
        The Pointer to the vector.
*/
extern LIB3DSAPI void lib3ds_vector_zero(
    float c[3]);

/**
    Copies all components of a vector to another vector.
    \param dst
        [out] The destination vector.
    \param src
        [in] The source vector.
*/
extern LIB3DSAPI void lib3ds_vector_copy(
    float dst[3],
    float src[3]);

/**
    Negates all components of a vector.
    \param c
        The Pointer to the vector.
*/
extern LIB3DSAPI void lib3ds_vector_neg(
    float c[3]);

extern LIB3DSAPI void lib3ds_vector_make(float c[3], float x, float y, float z);
extern LIB3DSAPI void lib3ds_vector_zero(float c[3]);
extern LIB3DSAPI void lib3ds_vector_add(float c[3], float a[3], float b[3]);
extern LIB3DSAPI void lib3ds_vector_sub(float c[3], float a[3], float b[3]);
extern LIB3DSAPI void lib3ds_vector_scalar_mul(float c[3], float a[3], float k);
extern LIB3DSAPI void lib3ds_vector_cross(float c[3], float a[3], float b[3]);
extern LIB3DSAPI float lib3ds_vector_dot(float a[3], float b[3]);
extern LIB3DSAPI float lib3ds_vector_length(float c[3]);
extern LIB3DSAPI void lib3ds_vector_normalize(float c[3]);
extern LIB3DSAPI void lib3ds_vector_normal(float n[3], float a[3], float b[3], float c[3]);
extern LIB3DSAPI void lib3ds_vector_min(float c[3], float a[3]);
extern LIB3DSAPI void lib3ds_vector_max(float c[3], float a[3]);
extern LIB3DSAPI void lib3ds_vector_transform(float c[3], float m[4][4], float a[3]);

extern LIB3DSAPI void lib3ds_quat_identity(float c[4]);
extern LIB3DSAPI void lib3ds_quat_copy(float dest[4], float src[4]);
extern LIB3DSAPI void lib3ds_quat_axis_angle(float c[4], float axis[3], float angle);
extern LIB3DSAPI void lib3ds_quat_neg(float c[4]);
extern LIB3DSAPI void lib3ds_quat_cnj(float c[4]);
extern LIB3DSAPI void lib3ds_quat_mul(float c[4], float a[4], float b[4]);
extern LIB3DSAPI void lib3ds_quat_scalar(float c[4], float k);
extern LIB3DSAPI void lib3ds_quat_normalize(float c[4]);
extern LIB3DSAPI void lib3ds_quat_inv(float c[4]);
extern LIB3DSAPI float lib3ds_quat_dot(float a[4], float b[4]);
extern LIB3DSAPI float lib3ds_quat_norm(float c[4]);
extern LIB3DSAPI void lib3ds_quat_ln(float c[4]);
extern LIB3DSAPI void lib3ds_quat_ln_dif(float c[4], float a[4], float b[4]);
extern LIB3DSAPI void lib3ds_quat_exp(float c[4]);
extern LIB3DSAPI void lib3ds_quat_slerp(float c[4], float a[4], float b[4], float t);
extern LIB3DSAPI void lib3ds_quat_squad(float c[4], float a[4], float p[4], float q[4], float b[4], float t);
extern LIB3DSAPI void lib3ds_quat_tangent(float c[4], float p[4], float q[4], float n[4]);
// 四元数数学函数
extern LIB3DSAPI void lib3ds_quat_identity(float c[4]);
extern LIB3DSAPI void lib3ds_quat_copy(float dest[4], float src[4]);
extern LIB3DSAPI void lib3ds_quat_axis_angle(float c[4], float axis[3], float angle);
extern LIB3DSAPI void lib3ds_quat_neg(float c[4]);
extern LIB3DSAPI void lib3ds_quat_cnj(float c[4]);
extern LIB3DSAPI void lib3ds_quat_mul(float c[4], float a[4], float b[4]);
extern LIB3DSAPI void lib3ds_quat_scalar(float c[4], float k);
extern LIB3DSAPI void lib3ds_quat_normalize(float c[4]);
extern LIB3DSAPI void lib3ds_quat_inv(float c[4]);
extern LIB3DSAPI float lib3ds_quat_dot(float a[4], float b[4]);
extern LIB3DSAPI float lib3ds_quat_norm(float c[4]);
extern LIB3DSAPI void lib3ds_quat_ln(float c[4]);
extern LIB3DSAPI void lib3ds_quat_ln_dif(float c[4], float a[4], float b[4]);
extern LIB3DSAPI void lib3ds_quat_exp(float c[4]);
extern LIB3DSAPI void lib3ds_quat_slerp(float c[4], float a[4], float b[4], float t);
extern LIB3DSAPI void lib3ds_quat_squad(float c[4], float a[4], float p[4], float q[4], float b[4], float t);
extern LIB3DSAPI void lib3ds_quat_tangent(float c[4], float p[4], float q[4], float n[4]);
// 矩阵数学函数
extern LIB3DSAPI void lib3ds_matrix_zero(float m[4][4]);
extern LIB3DSAPI void lib3ds_matrix_identity(float  m[4][4]);
extern LIB3DSAPI void lib3ds_matrix_copy(float dest[4][4], float src[4][4]);
extern LIB3DSAPI void lib3ds_matrix_neg(float m[4][4]);
extern LIB3DSAPI void lib3ds_matrix_transpose(float m[4][4]);
extern LIB3DSAPI void lib3ds_matrix_add(float m[4][4], float a[4][4], float b[4][4]);
extern LIB3DSAPI void lib3ds_matrix_sub(float m[4][4], float a[4][4], float b[4][4]);
extern LIB3DSAPI void lib3ds_matrix_mult(float m[4][4], float a[4][4], float b[4][4]);
extern LIB3DSAPI void lib3ds_matrix_scalar(float m[4][4], float k);
extern LIB3DSAPI float lib3ds_matrix_det(float m[4][4]);
extern LIB3DSAPI int lib3ds_matrix_inv(float m[4][4]);
extern LIB3DSAPI void lib3ds_matrix_translate(float m[4][4], float x, float y, float z);
extern LIB3DSAPI void lib3ds_matrix_scale(float m[4][4], float x, float y, float z);
extern LIB3DSAPI void lib3ds_matrix_rotate_quat(float m[4][4], float q[4]);
extern LIB3DSAPI void lib3ds_matrix_rotate(float m[4][4], float angle, float ax, float ay, float az);
extern LIB3DSAPI void lib3ds_matrix_camera(float m[4][4], float pos[3], float tgt[3], float roll);

关于 3D 数学基础知识,大家可以参考下这本书—《3D 数学基础:图形与游戏开发》。

(3) 3DS 文件数据结构

// Lib3dsFile
typedef struct Lib3dsFile {
    unsigned            user_id;
    void*               user_ptr;
    unsigned            mesh_version;
    unsigned            keyf_revision;
    char                name[12+1];
    float               master_scale;
    float               construction_plane[3];
    float               ambient[3];
    Lib3dsShadow        shadow;
    Lib3dsBackground    background;
    Lib3dsAtmosphere    atmosphere;
    Lib3dsViewport      viewport;
    Lib3dsViewport      viewport_keyf;
    int                 frames;
    int                 segment_from;
    int                 segment_to;
    int                 current_frame;
    int                 materials_size;
    int                 nmaterials;
    Lib3dsMaterial**    materials;
    int                 cameras_size;
    int                 ncameras;
    Lib3dsCamera**      cameras;
    int                 lights_size;
    int                 nlights;
    Lib3dsLight**       lights;
    int                 meshes_size;
    int                 nmeshes;
    Lib3dsMesh**        meshes;
    Lib3dsNode*         nodes;
} Lib3dsFile;

extern LIB3DSAPI Lib3dsFile* lib3ds_file_open(const char *filename);
extern LIB3DSAPI int lib3ds_file_save(Lib3dsFile *file, const char *filename);
extern LIB3DSAPI Lib3dsFile* lib3ds_file_new();
extern LIB3DSAPI void lib3ds_file_free(Lib3dsFile *file);

通过 lib3ds_file_open 函数打开 3ds 文件后,Lib3dsFile 结构包含了解析完成的所有 3d 数据。