前面我们分析了静态模型OBJ格式,桢动画模型MD2,这篇主要分析骨骼动画MD5的一些概念并且实现。

  混合桢动画有计算简单,容易实现等优点,但是在需要比较细致的效果时,则需要更多的关键桢,每桢都添加相同的顶点,如果模型再细分一些,则比较恐怖了。在这基础上,则发展出了骨骼动画模型,原理说起来很简单,比如我们人类,做的各种动作具体都是由几个关节点来控制,比如你抬腿,你只把你大腿的骨骼调动起来,而大腿的肌肉跟着骨骼向上。由些我们只需要保存每桢的骨骼变动,然后再上面蒙上表皮。因此大量简单了顶点存储,并且,我们能方便的对骨骼实时改动就能添加不同的动画,但是因为骨骼的改变都是针对父骨骼来的,而蒙皮操作又是针对骷髅节点来做的,这些操作需要大量的运算。

  下面我们来解析MD5骨骼模型中,一些基本的概念与实现,在MD5,除去纹理图片,有二个比较主要的文件,一个是后缀为md5mesh的文件,一个是后缀为md5anim的文件,二个文件如他们的后缀名所表达的意思一样,前者和OBJ模型里的描述比较类似,主要包含每部分的顶点,面,纹理组成,不同于OBJ模型的的,这些元素是变化的,因此在OBJ模型有一些新的元素,如顶点不是单独的顶点,而是由一个或多个权重点构成,每个权重点关联着对应着骨骼节点,这样骨骼节点的改变能引起权重点的改变,而权重点的改变又引起了顶点的改变,至于为什么要用到权重点来连接骨骼和顶点,而不是直接用骷髅和顶点关联,首先拿我们来说,我们身上有些位置并不是只和一个骨骼节点有关,更多是和多个节点有关,这样能让动画更真实,也避免在关节点产生重合和断裂的现象。

  首先我们来解析md5mesh文件里的信息,在这个文件里,主要有二大元素,一个是骨骼节点信息,一个是多个部位蒙皮信息,下面我简化了一个md5mesh,实际肯定不可能这样,主要是用来说明各节点用的。

  

  在文件中我都加了注释,简单来说,第一行是版本信息,下面写的解析也是针对这个10的版本,然后是命令行,骨骼节点数,蒙皮组件数,然后是骨骼节点的具体信息,在这里包含每个骨骼的父索引,顶点位置,四元数(包含旋转信息).在这里特别说下,这个骨骼节点的顺序暗含他们自己的索引,还有特别一点,在md5mesh文件中,骨骼的顶点位置与旋转信息是针对模型空间的,后面我们会看到在md5anim也有骨骼节点下的顶点位置与旋转信息,但是那是针对父骨骼节点坐标来的。然后就是蒙皮各个部分的详细信息,包含纹理坐标位置,顶点数,面的信息,权重信息,如前面所说,一个面包含3个顶点,每个顶点包含多个权重,每个权重关联一个或多个骨骼信息。下面根据上面各个部位来定义我们代码里各个类:

  1.  蒙皮节点描述类

  这里的类与文件里各个描述部分差不多都是一一对应,很好理解,因元组在F#编译器级别的默认支持,使我们不用想尽办法组织结构,让结构和原始文件保持一致就行,然后要用到的时候因函数式操作相关便利性,很少的代码就能拿到需要组合的数据。

  在下面,我们具体处理如何加载md5mesh文件。

  1.  读取蒙皮文件信息

  在这里,差不多就把蒙皮文件里的所有信息处理完毕。其实如果只是md5mesh,他就相当于一个复杂了些,包含了权重的OBJ模型,组织方式都大同小异,不信请看下面。我们记的在md5mesh前面骨骼也包含了顶点位置与四元数信息,根据这个,可以求得默认的权重点具体位置,然后就能得到顶点的具体位置,然后得到面,然后绘制,下面这段代码可以在没有md5anim文件里,绘制一个静态的,相当于OBJ模型一样功能的模型。  

  1.  根据蒙皮文件绘制模型

  这段代码比较简单,就是上面所说,求面中的顶点,顶点根据权重求,权重根据骨骼当前状态来得到,还是和上面一样说明下,md5mesh里的骨骼节点是模型坐标系下的,所以骨骼节点不需要做转化。

  这里说下四元数,在3D中,我们表示旋转一般有矩阵,欧拉角,四元数,平常我们所用都是矩阵与欧拉角,四元数用到复数,理解起来比较麻烦,我现在也只是记着一些四元数的特性,能实现平滑插值,点p用四元数旋转后得到点p1=ap(a的逆).四元数和矩阵一样,满足结合律,但是不满足交换律。四元数的有向量部分v(x,y,z)和一个分量w,几何意义可以描述为对于一个向量n,旋转@角,四元数就是[w=cos(@/2),sin(@/2)*n]=[w=cos(@/2),sin(@/2)*nx,sin(@/2)*ny,sin(@/2)*nz],根据这个定义,可以推导出一些四元数的特性,如四元数的共轭和四元数代表相反的角位移,上面的p1=ap(a的逆).

  如果没有md5anim文件,MD5文件也就和OBJ文件一样,只是一个静态的模型,下面让我们来分析md5anim的相关格式。下面一样给出一个简化了的样式。

  各信息我给出了基本标注,比较重要的每秒多少桢,桢的具体信息,这个顺序与前面md5mesh是对应的,父索引也是一样的,不同的是,后面二个整数,一个表示应该读frame的那些数据,一个表示读的位置的起点。给出对应的代码格式。

  1.  MD5动画格式

  分别定义了,Md5JointInfo,Md5BaseFrame,Md5Frame,大家可以看出多了Md5SkeletonJoin与Md5FrameSkeleton,没有与文件里的信息对应,这里就是要大家前面老注意的一个地方,在md5mesh文件,给的骨骼节点坐标已经是模型坐标系下的,而md5anim给出的骨骼节点坐标只是针对父骨骼节点里的,Md5SkeletonJoin与Md5FrameSkeleton就是Md5Frame根据父骨骼节点求出的在模型坐标系下的坐标。

  下面首先是加载md5anim信息的代码:

  1.  加载MD5动画模型

  这部分代码也是一些IO操作,把读到的信息都放入Md5Animation里去,这个类主要做二件事,一是得到正确的Md5SkeletonJoin与Md5FrameSkeleton,就是得到Md5Frame根据父骨骼节点求出的在模型坐标系下的坐标。然后一些,就是根据当前时间,当前桢率得到正确的插值,这部分和MD2插值差不多。请看主要代码:

  1.  MD5动画计算模型坐标下骨骼节点与线性插值

  关键部分我都写了注释,应该容易看明白,如上面所说,二件事,一是CreateFrameSkeleton,这个首先根据flag与startIndex读取文件,然后把在父骨骼坐标系中的点转化成模型坐标系下的点。二是GetCurrentFrameSkeleton,分别得到所在时间的当前桢与下一桢,然后根据在这桢之间的位置插值得到各骨骼节点正确的坐标。渲染部分在这里,考虑到因为一个MD5模型本来包含几部分Mesh,然后每部分Mesh又包含各桢的情况,再想用MD2中关键桢顶点信息做VBO不现实,故直接用VA来输出渲染。  

  1.  输出MD5动画

  到此,整个过程就差不多了,下面给出效果图:

  

  代码:源码与执行文件 http://files.cnblogs.com/zhouxin/MD5Load.zip 其中\bin\Release\CgTest.exe为可执行文件

  其中EDSF前后左右移动,鼠标右键加移动鼠标控制方向,空格上升,空格在SHIFT下降。再发现,整个工程中,去掉OBJ,MD2模型后,加上DLL一共27M,压缩下才5M,能上传上来,前面每次都分开上传给大家造成不便了其中为了突出MD5的重点,相应的法线没有自动生成,相关方法可以看前面OBJ,MD2里的,计算过程一样。

  CPU和GPU各应该执行的操作让我的理解应该是,一次计算很久变一次应该交给CPU,而在渲染过程快速,大量执行的代码应该交给GPU来算,下一步目标,改进里面关于骨骼位置的计算,以及相应蒙皮的操作应该交给GPU,也就是放到着色器中去处理。

MD5骨骼动画模型加载的更多相关文章

  1. MD5骨骼动画模型加载(一)

    前面我们分析了静态模型OBJ格式,桢动画模型MD2,这篇主要分析骨骼动画MD5的一些概念并且实现. 混合桢动画有计算简单,容易实现等优点,但是在需要比较细致的效果时,则需要更多的关键桢,每桢都添加相同 ...

  2. DirectX11 With Windows SDK--19 模型加载:obj格式的读取及使用二进制文件提升读取效率

    前言 一个模型通常是由三个部分组成:网格.纹理.材质.在一开始的时候,我们是通过Geometry类来生成简单几何体的网格.但现在我们需要寻找合适的方式去表述一个复杂的网格,而且包含网格的文件类型多种多 ...

  3. OpenGL OBJ模型加载.

    在我们前面绘制一个屋,我们可以看到,需要每个立方体一个一个的自己来推并且还要处理位置信息.代码量大并且要时间.现在我们通过加载模型文件的方法来生成模型文件,比较流行的3D模型文件有OBJ,FBX,da ...

  4. 6_1 持久化模型与再次加载_探讨(1)_三种持久化模型加载方式以及import_meta_graph方式加载持久化模型会存在的变量管理命名混淆的问题

    笔者提交到gitHub上的问题描述地址是:https://github.com/tensorflow/tensorflow/issues/20140 三种持久化模型加载方式的一个小结论 加载持久化模型 ...

  5. cesium模型加载-加载fbx格式模型

    整体思路: fbx格式→dae格式→gltf格式→cesium加载gltf格式模型 具体方法: 1. fbx格式→dae格式 工具:3dsMax, 3dsMax插件:OpenCOLLADA, 下载地址 ...

  6. Wish3D用户必看!模型加载失败原因汇总

    上传到Wish3D的模型加载不出来,作品显示页面漆黑一片,是什么原因? 很有可能是操作过程中的小失误,不妨从以下几点检查.还是不行的请加QQ群(Wish3D交流群3):635725654,@Wish3 ...

  7. 从零开始openGL——三、模型加载及鼠标交互实现

    前言 在上篇文章中,介绍了基本图形的绘制.这篇博客中将介绍模型的加载.绘制以及鼠标交互的实现. 模型加载 模型存储 要实现模型的读取.绘制,我们首先需要知道模型是如何存储在文件中的. 通常模型是由网格 ...

  8. PyTorch模型加载与保存的最佳实践

    一般来说PyTorch有两种保存和读取模型参数的方法.但这篇文章我记录了一种最佳实践,可以在加载模型时避免掉一些问题. 第一种方案是保存整个模型: 1 torch.save(model_object, ...

  9. CC模型加载太慢?一招破解!

    伴随无人机性能的提升,单个项目涉及到的倾斜摄影数据范围不断扩大,模型的数据量越来越大,在同配置机器上的显示速度也相应的越来越慢,那么如何在不升级配置的情况下提升模型的加载速度呢? 01 百GB倾斜摄影 ...

随机推荐

  1. IT路上的应该注意自我规划 学习规划与自我修炼

    http://www.nowamagic.net/librarys/veda/detail/607 IT路漫漫,你需要明确自己所处的位置,并作出相应的规划,这条路才能够走得更加顺畅.下面是参考: 初学 ...

  2. 执行 maven 命令 报错Unable to add module to the current project as it is not of packaging type 'pom'[转]

    今天学习在本地搭建Maven工程时,执行了mvn archetype:generate 命令,报错. Unable to create project from archetype [org.apac ...

  3. CMD查看进程ID并查杀进程

    开始-运行,输入CMD打开命令行界面,输入命令netstat -ano 结束该进程C:\>taskkill /f /t /im Wiz.exe 根据进程ID杀 >taskkill /F / ...

  4. mysql string types ---- mysql 字符类型详解

    一.mysql 中包涵的字符类型: [national] char [(m)] [character set charset_name] [collate collation_name] [natio ...

  5. ajax提交数据处理总结

    一:Ajax中Get请求与Post请求的区别  http://www.cnblogs.com/oneword/archive/2011/06/06/2073533.html 二:ajax分页: 360 ...

  6. Atitit. 解释器模式框架选型 and应用场景attilax总结 oao

    Atitit. 解释器模式框架选型 and应用场景attilax总结 oao 1. 解释器模式结构描述 1 2. 如何实现(简单的解释器模式,仅仅通过词法分析即可实现,而无需token流进行处理. 2 ...

  7. Altera Quartus II下载中途失败

    1.Altera 的quartus II 下载程序时中途失败,有可能是程序写的不对(缺少初始状态,else补全等等) 2.下载程序pof最好也用英文命名,再下载.

  8. 再谈API GateWay服务网关

    前面在谈微服务架构的时候,我博客上转过Chris Richardson 微服务系列中对微服务网关的描述: 通常来说,使用 API 网关是更好的解决方式.API 网关是一个服务器,也可以说是进入系统的唯 ...

  9. 执行git命令出现 xcrun: error:

    xcrun: error: active developer path ("/Applications/Xcode.app/Contents/Developer") does no ...

  10. phoenix系统创建语句

    CREATE TABLE SYSTEM."CATALOG"( TENANT_ID VARCHAR NULL, TABLE_SCHEM VARCHAR NULL, TABLE_NAM ...