基于lib3ds和OpenGL的3ds文件的读取与显示

来源:互联网 发布:手腕腱鞘炎 知乎 编辑:程序博客网 时间:2024/06/04 19:37

3ds文件是3ds Max建模软件的标准输入输出格式,它的应用十分的广泛。各种虚拟现实项目都可使用它作为模型格式,甚至可以在游戏中使用,但是它的文件格式比较复杂而且 没有相关的官方文档,所以对它的读取显示一直是一个问题。笔者通过多年的项目经验总结了一套操作3ds文件的方法,简单的说就是使用lib3ds库对 3ds文件进行解析读取,然后利用OpenGL来显示。

一、 模型的读取

要绘制模型必须首先将其读入内存。 在我们读取3ds文件以前我们有必要了解一下3ds文件都包含那些组成部分。

1. 物体(Object)

这 可能是我们最关心的一部分了,一个3ds文件可以包含多个物体,一个物体可以是一座房屋、一头狮子、一个简单的长方体等等。物体又包含顶点数据、三角形索 引数据、纹理坐标数据、材质列表数据等。每种数据由一个特定的ID标识,ID说明了跟在其后的是什么数据。

2. 材质

材 质包含颜色、透明度、贴图文件名等数据。3ds文件里可以有多个材质,也可以没有。

3. 相机

相机数据中主 要包含相机的位置、朝向等信息。

4. 灯光

灯光数据中主要包含灯光的位置、类型等信息。灯光可以是泛光灯、 聚光灯等。

5. 关键帧

关键帧是用来描述动画的,其中包含了每个物体在每一关键帧处的变换矩阵。这样只要在 绘制每一帧动画前给物体乘上相应的变换矩阵即可实现动画。需要注意一下3ds文件只能描述刚体动画,不能描述柔体动画。

读取的工作 由lib3ds中的lib3ds_file_load(char *filename)函数来实现,lib3ds库将不同类型数据组织成以file为根节点的树状结构,而同类数据以链表的形式存放,可以像这样遍历一种数据:

Lib3dsMesh *p;

for(p=file->meshes;p!=0;p=p->next)
{
//在这里您可以用p做一些事情
}

以下为模型加载的关键代码:

// 加载模型

file=lib3ds_file_load(投篮.3DS);

// 加载出错或找不到文件时显示错误信息并退出

if (!file) {
puts(没有找到文件\n);
exit(1);
}

以下代码获取模型文件的包围盒

lib3ds_file_bounding_box_of_nodes(file, LIB3DS_TRUE, LIB3DS_FALSE, LIB3DS_FALSE, bmin, bmax);sx = bmax[0] - bmin[0];sy = bmax[1] - bmin[1];sz = bmax[2] - bmin[2];size = MAX(sx, sy); size = MAX(size, sz);cx = (bmin[0] + bmax[0])/2;cy = (bmin[1] + bmax[1])/2;cz = (bmin[2] + bmax[2])/2;

因为3ds Max制作的场景中可能没有灯光、相机所以人为的在模型的左右上下各加入一个,代码如下:

if( !file->cameras ) {Lib3dsCamera *camera = lib3ds_camera_new(Camera_X);camera->target[0] = cx;camera->target[1] = cy;camera->target[2] = cz;memcpy(camera->position, camera->target, sizeof(camera->position));camera->position[0] = bmax[0] + 1.5 * MAX(sy,sz);camera->near_range = ( camera->position[0] - bmax[0] ) * .5;camera->far_range = ( camera->position[0] - bmin[0] ) * 2;lib3ds_file_insert_camera(file, camera);camera = lib3ds_camera_new(Camera_Y);camera->target[0] = cx;camera->target[1] = cy;camera->target[2] = cz;memcpy(camera->position, camera->target, sizeof(camera->position));camera->position[1] = bmin[1] - 1.5 * MAX(sx,sz);camera->near_range = ( bmin[1] - camera->position[1] ) * .5;camera->far_range = ( bmax[1] - camera->position[1] ) * 2;lib3ds_file_insert_camera(file, camera);camera = lib3ds_camera_new(Camera_Z);camera->target[0] = cx;camera->target[1] = cy;camera->target[2] = cz;memcpy(camera->position, camera->target, sizeof(camera->position));camera->position[2] = bmax[2] + 1.5 * MAX(sx,sy);camera->near_range = ( camera->position[2] - bmax[2] ) * .5;camera->far_range = ( camera->position[2] - bmin[2] ) * 2;lib3ds_file_insert_camera(file, camera);camera = lib3ds_camera_new(Camera_ISO);camera->target[0] = cx;camera->target[1] = cy;camera->target[2] = cz;memcpy(camera->position, camera->target, sizeof(camera->position));camera->position[0] = bmax[0] + .75 * size;camera->position[1] = bmin[1] - .75 * size;camera->position[2] = bmax[2] + .75 * size;camera->near_range = ( camera->position[0] - bmax[0] ) * .5;camera->far_range = ( camera->position[0] - bmin[0] ) * 3;lib3ds_file_insert_camera(file, camera);}
原创粉丝点击