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

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

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

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

  

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

 蒙皮节点描述类

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

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

 读取蒙皮文件信息

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

 根据蒙皮文件绘制模型

  这段代码比较简单,就是上面所说,求面中的顶点,顶点根据权重求,权重根据骨骼当前状态来得到,还是和上面一样说明下,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的那些数据,一个表示读的位置的起点。给出对应的代码格式。

 MD5动画格式

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

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

 加载MD5动画模型

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

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

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

 输出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. D3D11 MD5骨骼动画模型的加载

    MD5模型由两个文件组成:md5mesh和md5anim文件,正如名字所示,一个用于加载md5模型,一个用于动画.本章节介绍的是如何从md5mesh文件加载md5骨骼动画模型以及如何基于骨骼布局来设置 ...

  2. 第八章 DirectX 3D模型加载和骨骼动画(下)

    接下来,我们介绍一些骨骼动画.我们之前大致讲过骨骼动画,存储骨骼动画的网格文件要比普通的文件复杂一下.主要是增加了骨骼信息,蒙皮信息以及动画帧信息.骨骼动画的实现原理是仿照人体运动学,将3D模型由一种 ...

  3. Three.js 模型加载及加载简单动画

    时间过的好快啊~再一次感叹,忙忙碌碌一年又过去了,新年第一帖,新的一年也要加油呀! 简单介绍下Three.js吧,Three.js是基于原生WebGL封装运行的三维引擎,在所有WebGL引擎中,Thr ...

  4. OpenGL Assimp模型加载库

    OpenGL Assimp库 前言 模型加载库 构建Assimp 前言 到目前为止的所有场景中,我们一直都在滥用我们的箱子朋友,但时间久了甚至是我们最好的朋友也会感到无聊.在日常的图形程序中,通常都会 ...

  5. 【虚幻引擎UE】UE5 AR初体验之静态动态模型加载

    UE5的AR初体验之静态动态两种模型加载 基于配置好AR环境(参考另一篇文章) 先## 标题简单了解一下它的项目结构 这里的brush就是我们的操作空间范围 官方模板可以实现平面识别,控制对象的旋转和 ...

  6. Python时间序列模型推理预测实战:时序推理数据预处理(特征生成、lstm输入结构组织)、模型加载、模型预测结果保存、条件判断模型循环运行

    Python时间序列模型推理预测实战:时序推理数据预处理(特征生成.lstm输入结构组织).模型加载.模型预测结果保存.条件判断模型循环运行 目录

  7. OpenGL OBJ模型加载.

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

  8. OpenGL模型加载和渲染

    OpenGL模型加载和渲染 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <stdio.h> #include "GL/g ...

  9. pytorch无法将模型加载到gpu上

    通常是model = model.to(cuda)就好了 但由于搭建模型的时候,forward函数的代码直接调用这个类外部的函数,如图所示: 在这里直接调用了外部的函数, 这个函数里面有torch.n ...

最新文章

  1. 曾因出演《西游记》爆红,现在转行写代码身价过亿!不一样的CTO!
  2. 移动端自动化测试 Appium 框架之数据驱动
  3. English in 999
  4. ADSL宽带为什么下载和上传速度差别如此之大?
  5. luogu_1002 过河卒
  6. 11.context_suggester
  7. iOS 7 如何关闭已打开的应用(App)
  8. 【技术解决方案】优化FFmpeg探测网络流时间过长的问题
  9. 47.QT-QChart之曲线图,饼状图,条形图使用
  10. 选择 Veeam ONE v10 的其他三大原因!
  11. linux系统中db2创建表空间,为DB2数据库创建表空间
  12. cocos2d-x 中创建 CCSprite 精灵动画
  13. CentOS 6.2配置NIS主/从服务器
  14. file_get_contents打开中文名文件时出错
  15. qt中使用mysql模糊查询_mysql数据库模糊查询简介
  16. linux 制作分区镜像img文件
  17. 一次网易游戏测试(外包)面试
  18. 目前可用的通用DNS
  19. joycon手柄拆解_任天堂switch手柄怎么拆解图文教程 教你如何拆joycon
  20. 2010年翡翠岛露营

热门文章

  1. 【计算机·科技】互联网的黑科技来啦
  2. Codeforces 1089D Eels (看题解)
  3. 《程序员的数学1》读书笔记整理
  4. 数论--欧几里得和扩展的欧几里得定理
  5. STL容器基础 - 0
  6. Ubuntu18.04安装搜狗拼音输入法皮肤透明解决方法
  7. [ROC-RK3568-PC] 手把手教你把出厂的Android系统烧写为Ubuntu系统
  8. PHP:安装fileinfo扩展
  9. php简单的功能模块,php中mysql模块部分功能的简单封装
  10. job全异常 mapreduce_eclipse 运行MapReduce程序错误异常汇总(解决Map not fount)