zoukankan      html  css  js  c++  java
  • CSharpGL(50)使用Assimp加载骨骼动画

    CSharpGL(50)使用Assimp加载骨骼动画

    在(http://ogldev.atspace.co.uk/www/tutorial38/tutorial38.html)介绍了C++用Asismp库加载骨骼动画的原理和流程。

    在(http://wiki.jikexueyuan.com/project/modern-opengl-tutorial/tutorial45.html)是其中文版译文。

    本文用CSharpGL借助Assimp库实现加载和渲染骨骼动画的功能。

    下载

    CSharpGL已在GitHub开源,欢迎对OpenGL有兴趣的同学加入(https://github.com/bitzhuwei/CSharpGL

    在.NET下使用Assimp

    三维模型解析库Assimp本身是用C++编写的,所幸有一个C#的封装(https://github.com/assimp/assimp-net)。使用此封装即可直接在CSharpGL中调用Assimp了。

    将Assimp32.dll、Assimp64.dll和AssimpNet.dll都放到项目所在目录下,在Reference中添加对AssimpNet.dll的引用即可。

     

     

    渲染骨骼动画

    Assimp加载模型后得到的数据结构如下:

    1 public sealed class Scene
    2 {
    3     public Animation[] Animations { get; }
    4     public Material[] Materials { get; }
    5     public Mesh[] Meshes { get; }
    6     public Node RootNode { get; }
    7 }

    按我的理解,其中的RootNode就是骨骼的根结点。整个骨骼构成一个树结构。每个结点都包含一个mat4 Transform矩阵,用于描述自己相对于父结点的方位变化。子结点代表的骨骼,其绝对方位由根结点的Transform逐步地乘到自己的Transform来得到。“绝对方位”指的就是在Model Space中的方位。

     

    如图所示,红色的小方块描述了骨骼所在的绝对位置(这里的骨骼对应人体的关节)。从红到白渐变的线条描述了骨骼之间的父子关系,红色一端为父结点,白色一端为子结点。两脚之间的那个红色小方块,就是根结点RootNode。用半透明方式渲染的两臂水平摆放的,就是模型的默认位置。

    上图这个模型,只有一个“拿起灯左右查看”的动作(Animation)。其他模型可能有多个动作,它们构成一个数组(Assimp.Animation[])。每个Animation都指定了这个模型的所有骨骼在所有关键帧上的Transform值。这样,通过按时间顺序依次经历各个关键帧(更准确地说,是在2个相邻的关键帧之间插值),就可以得到骨骼在各个时刻的Transform。再让模型的顶点依附于骨骼而动,就实现了骨骼动画。

    模型上的一个顶点,要记录自己都依附于哪几个骨骼,自己对这几个骨骼依附的权重分别是多少(权重之和为1)。然后,就可以从默认的初始位置(用半透明方式渲染的两臂水平摆放的那个位置)变换到骨骼要求的位置。

    顶点的这一变换过程我还没弄明白。这里需要的Offset Matrix到底是什么。据我查资料,外加计算,Offset Matrix就是那个让骨骼结点变换到绝对方位的矩阵的逆矩阵。但是总觉得有点想不通的地方,确不知道是哪里。

    经高人goodpgr提醒,Offset Matrix就是那个让骨骼结点变换到model space的矩阵的逆。非常感谢!

    将其推导过程陈列如下:

    「Offset Matrix就是那个让骨骼结点变换到绝对方位的矩阵的逆矩阵」:
    可以改寫成
    「Offset Matrix就是那个让骨骼结点变换到model space的矩阵的逆」:
    因為skin mesh的頂點資料是在model space定義的
    假設在右小腿附近有1個頂點P,用model space的三把尺和原點來測量
    它在model space可能是 p'=(10,20,0)
    (y向上是天空)
    但對右小腿Bone來說,用它的三把尺和原點測量頂點P
    得到的值可能是 p=(10,0,0) => local bone space
    假設右小腿Bone的階層長這樣
    RootBone // 右骨盆Bone // 右大腿Bone // 右小腿Bone
    它們對映到的矩陣分別是
    Mroot // Mc // Mb // Ma
    那 p和p'會有下面的關系
    p'=(Mroot Mc Mb Ma) p
    (Mroot Mc Mb Ma)^-1 p'=p
    MatrixModelSpaceToBoneLocal * p' = p
    MatrixModelSpaceToBoneLocal = Offset_Matrix
    mesh綁定到bone上,實際上是綁定到bone的local space
    但一開始mesh的資料是在model space建模的

    总结

    骨骼动画的原理网上有很多介绍了。我还没有透彻理解,所以不对本文的原理部分负责。

  • 相关阅读:
    k8s系列---service
    算法
    golang-练习ATM --面向对象实现
    golang-练习ATM
    k8s系列---pod介绍
    12.20 一组v-if/v-else-if/v-else 的元素类型相同,应该使用 key
    12.20 await 操作符的学习(await后跟非promsie、promsie(成功/失败)的几种情况测试)
    12.20 async关键字的学习
    12.20 falsy变量
    12.19 js中递归优化(递归爆栈)
  • 原文地址:https://www.cnblogs.com/bitzhuwei/p/csharpgl-50-bones-animation.html
Copyright © 2011-2022 走看看