目前fbx 2015.1中支持三种变形器:skinDeformer,blendShapeDeformer,vertexCacheDeformer。定义在fbxdeformer.h中:

enum EDeformerType {

  eUnknown, //!< Unknown deformer type

  eSkin, //!< Type FbxSkin

  eBlendShape, //!< Type FbxBlendShape

  eVertexCache //!< Type FbxVertexCacheDeformer

};

前两种变形器分别对应:骨骼蒙皮动画 和 变形动画,(第三种还没研究)。

相应的播放代码都可以在ViewScene示例中找到。

其中 骨骼蒙皮动画 游戏里用得最多,所以研究得较早。这几天又看了一下 变形动画(BlendShape/Morph animation),散乱记录一下若干注意事项。

一,变形(blendShape/morph)基本原理。

大体上讲就是在拓扑结构相同的mesh之间插值。细节在下文中会提到。

典型应用是做表情动画。

二,在3dmax中制作带有 变形动画 的模型。

我用的是3dmax 2012(中文版)。

1,先建一个模型X,然后复制出一份X1。

2,对X1在保持拓扑结构不变的条件下进行变形。

3,为X添加“变形器”修改器,将X1添加到“变形器”修改器的一个通道中,则X1成为X的一个变形目标。

4,调整通道值,便可看到X受X1影响发生变形。

5,打开自动关键点,记录变形动画。

可以重复上面方法为X添加多个变形目标。

“变形器”修改器的一个通道可以添加多个变形目标,通道名称将显示为此通道中所添加的第一个变形目标的名称,此通道所添加的所有变形目标可以在”渐进变形“栏的”目标列表“中看到。

当一个通道中添加多个变形目标时,称为progressive morph,X将按目标列表中目标的顺序依次变形。

另外注意,并非对X1的任何保持拓扑的修改都能对X产生影响,只有局部空间的修改(例如使用对象空间修改器进行的修改、直接编辑顶点的修改等)才起作用,而对X1整体进行的修改(例如对X1整体进行旋转、平移、缩放等)则不会起作用。

三,fbx变形动画原理。

fbx sdk的ViewScene示例中的ComputeShapeDeformation()函数实现变形动画的数据提取和播放,通过阅读这部分代码,可以了解fbx中变形动画数据的逻辑结构:

一个mesh包含多个blendShape,

一个blendShape包含多个blendShapeChannel,

一个blendShapeChannel包含多个targetShape和一个weight动画曲线weightCurve。

targetShape中包含controlPoints和一个fullWeight值。

这些结构与3dmax中的对应关系如下:

mesh对应的就是3dmax中的模型,

blendShape对应“变形器”修改器,一个模型可以添加多个“变形器”修改器,

blendShapeChannel对应“变形器”修改器的通道,blendShapeChannel->GetName()得到通道名称.

targetShape对应变形目标,一个通道可以添加多个变形目标。targetShape->GetName()得到变形目标名称。

通道的weightCurve给出各时间点此通道变形进度weight。

targetShape的fullWeight值表示的是本通道变形进度weight值达到多少时恰好完全变形为本targetShape。对于只有一个targetShape的通道,targetShape的fullWeight必定是100;而对于含有多个targetShape的通道,各targetShape的fullWeight值按顺序依次增大,并且最后一个targetShape的fullWeight必定是100。

可见,非常符合直观,至此变形插值算法几乎不用再看ComputeShapeDeformation()的代码便可以直接想象出来了:

1,对于只有一个变形目标的通道(非渐近变形),只要根据通道变形进度weight在变形物体和变形目标间插值。

2,对于含有多个变形目标的通道(渐近变形),看变形进度weight落在哪两个变形目标的fullWeight之间,然后计算weight将此区间分成的比例得到此区间上的变形进度weightOfSpan,再根据此区间变形进度在上述两个变形目标间插值。

下面是ComputeShapeDeformation()中的注释,用具体例子说明在progressive morph和progressive morph情况下的插值算法,与我们的直观想象完全一致:

If there is only one targetShape on this channel, the influence is easy to calculate:

influence = (targetShape - baseGeometry) * weight * 0.01

dstGeometry = baseGeometry + influence

But if there are more than one targetShapes on this channel, this is an in-between

blendshape, also called progressive morph. The calculation of influence is different.

For example, given two in-between targets, the full weight percentage of first target

is 50, and the full weight percentage of the second target is 100.

When the weight percentage reach 50, the base geometry is already be fully morphed

to the first target shape. When the weight go over 50, it begin to morph from the

first target shape to the second target shape.

To calculate influence when the weight percentage is 25:

1. 25 falls in the scope of 0 and 50, the morphing is from base geometry to the first target.

2. And since 25 is already half way between 0 and 50, so the real weight percentage change to

the first target is 50.

influence = (firstTargetShape - baseGeometry) * (25-0)/(50-0) * 100

dstGeometry = baseGeometry + influence

To calculate influence when the weight percentage is 75:

1. 75 falls in the scope of 50 and 100, the morphing is from the first target to the second.

2. And since 75 is already half way between 50 and 100, so the real weight percentage change

to the second target is 50.

influence = (secondTargetShape - firstTargetShape) * (75-50)/(100-50) * 100

dstGeometry = firstTargetShape + influence

四,多通道同时影响时的叠加方式。

假设变形物体X受channel1和channel2两个通道影响,channel1中只有一个变形目标shape1,通道变形进度为w1;channel2中只有一个变形目标shape2,通道变形进度为w2。设v是X上一点,原始坐标为p;v1是shape1上等位点,坐标为p1;v2是shape2上等位点,坐标为p2。

则v在两个通道影响下变形后的坐标p_deformed应计算如下:

p_deformedByChannel1=p+(p1-p)*w1

p_deformedByChannel1andChannel2=p_deformedByChannel1+(p2-p_deformedByChannel1)*w2

p_deformed=p_deformedByChannel1andChannel2

五,法线问题。

对变形物体进行变形,如果只是顶点位置发生变化,而法线不变的话,那么在有光照的情况下显示效果是不对的,所以法线也需要在变形物体和变形目标之间进行插值。

前面分析fbx变形动画数据逻辑结构时提到“targetShape中包含controlPoints和一个fullWeight值”,是因为在viewScene示例中,只使用targetShape的controlPoints对变形物体的顶点位置进行了变形,而根本没有处理法线的变形。我没有找到由targetShape获得有效normals的方法。而且当我把动画导出为ascii的fbx,查看targetShape的normals数据时发现全是0。

我目前的解决办法是通过targetShape获得targetShapeName,然后再按名称在场景中搜索到与targetShape相对应的模型(mesh),然后从mesh中取得法线数据。这样就要求变形目标模型不能删,且要随变形物体一同导出到fbx文件中。另外一个需要注意的问题是,由于我的引擎中只支持三角网,于是要求或者在3dmax建模时物体就建成三角网,或者在导出为fbx文件时勾选“三角化”选项,或者在引擎载入fbx文件之后调用fbx sdk提供的api转换为三角网。但是后两者都不能保证变形物体mesh和变形目标mesh在三角化后仍具有完全相同的拓扑结构。而如果变形物体mesh和变形目标mesh的拓扑结构不同,法线插值就无法进行。

注意:顶点位置插值是不要求变形物体mesh和变形目标mesh拓扑结构相同的,只要顶点能一一对应,顶点位置插值就可以进行,所以如果像ViewScene示例那样只处理顶点变形而不考虑法线变形的话,不必要求模型在3dmax中就建成三角网。(不需要考虑法线变形的情况确实是存在的,例如的像《地铁跑酷》那种无光照的Q版3d游戏,根本不需要法线,因此做变形时也不用考虑法线变形)。

法线插值是向量间插值,与顶点位置插值(点之间插值)是不同的。点之间的插值直接线性插值即可,而向量间插值严格来讲应该使用球面插值(slerp)。不过经过试验,发现在此处两种方法的视觉差异并不很大,且线性插值速度要快得多,所以最后我仍然选择了线性插值。

六,ViewScene示例中变形动画代码有错误。

ViewScene示例中播放变形动画的代码是有错误的,将动画由3dmax中导出为fbx再用viewScene示例播放,会发现viewScene示例播放结果与3dmax中不一样,而且动画会出现跳变等明显错误。

我现在已经记不清具体是什么原因造成的了,但我在自己的播放程序中解决了这些问题。

我在c3dEngine2(https://github.com/wantnon2/c3dEngine2)中添加了一个app_fbxLoader_shapeDeformTest demo,效果视频:

FBX BlendShape/Morph动画解析的更多相关文章

  1. Skeleton with Assimp 骨骼动画解析

    Skeleton with Assimp 骨骼动画解析 骨骼动画是图形学中十分常见应用很广泛的一个技术,也是比较基础的内容,作为图形学的工程师需要将这一部分内容梳理清晰,主要关键在于几点:第一,分清楚 ...

  2. Android动画解析--XML

    动画类型 Android的animation由四种类型组成 XML中 alpha 渐变透明度动画效果 scale 渐变尺寸伸缩动画效果 translate 画面转换位置移动动画效果 rotate 画面 ...

  3. 【转】Unity3d:读取FBX中的动画

    从模型中获得切割好的动画clip,并且对其中设置好的动画事件进行修改方法: 1.动画模型后缀为.FBX.在Unity3d中,能够显示FBX中的动画.要加载模型中的AnimationClip,只要Ass ...

  4. Unity3d修改FBX文件的动画名方法

    问题描述:FBX文件导入Unity3d后的动画名字一般都是 “Take 001”并且无法修改!如何修改它呢? 解决方法:解决方法其实很简单,只要你按照Unity3d的FBX文件命名规则,压根就不会存在 ...

  5. Unity导入FBX自动进行动画切分

    手动处理动画分割 在导入FBX模型过程中,若带有动画呢,需要对它进行切分. 当然这个工作可以在Unity中完成. 比如: 这样手动来分割进行. 自动动画切分   这就需要代码了. 把代码保存成cs文件 ...

  6. 3DMAX导出FBX的烘焙动画选项

    勾选了 [烘焙动画]选项时,表示由骨骼动画塌陷为逐帧动画,这样的结果就是:导出的动画确保是正确的,但体积增大,这是骨骼动画与逐帧去画的区别所在. 如果不勾选此选项,则导出的是骨骼动画,可能出现一些问题 ...

  7. android动画解析(初级)

    效果图: ObjectAnimator继承自ValueAnimator的,底层的动画实现机制也是基于ValueAnimator来完成的,因此ValueAnimator仍然是整个属性动画当中最核心的一个 ...

  8. CATransition 转场动画解析

    http://blog.csdn.net/mad2man/article/details/17260901

  9. Unity3D之多个fbx导入场景, 合并多个动画

    1:先导入到合适的文件夹, Unity自动刷新, 生成相应的文件. 2:在Project视图中选中单个fbx, 在Inspector中选择"Rig", 更改"Animat ...

随机推荐

  1. 关于json与protobuf的材料

    1. https://solicomo.com/network-dev/protobuf-proto3-vs-proto2.html 2.

  2. Cognos值提示设置小技巧

    针对值提示问题做一个小的总结: 1:显示类问题 如上图,如何让”英文参数名"和"分割线----"不显示,或者说指定中文显示值呢 (1):让”英文参数名"和&qu ...

  3. Android基础新手教程——1.6 .9(九妹)图片怎么玩

    Android基础新手教程--1.6 .9(九妹)图片怎么玩 标签(空格分隔): Android基础新手教程 1.本节引言: 可能有的一些疑问: 1.什么是.9图片? 答:图片后缀名前有.9的图片,如 ...

  4. textarea光标移到末尾兼容ie,ffchrome

    function moveEnd(obj){         obj.focus();         var len = obj.value.length;         if (document ...

  5. (字符串)最长公共字串(Longest-Common-SubString,LCS)

    题目: 给定两个字符串X,Y,求二者最长的公共子串,例如X=[aaaba],Y=[abaa].二者的最长公共子串为[aba],长度为3. 子序列是不要求连续的,字串必须是连续的. 思路与代码: 1.简 ...

  6. linux可视化桌面安装

    [root@VM_193_201_centos ~]# yum grouplist Loaded plugins: fastestmirror, langpacks There is no insta ...

  7. ZH奶酪:【数据结构与算法】搜索之BFS

    1.目标 通过本文,希望可以达到以下目标,当遇到任意问题时,可以: 1.很快建立状态空间: 2.提出一个合理算法: 3.简单估计时空性能: 2.搜索分类 2.1.盲目搜索 按照预定的控制策略进行搜索, ...

  8. 算法笔记_108:第四届蓝桥杯软件类省赛真题(JAVA软件开发本科A组)试题解答

     目录 1 世纪末的星期 2 振兴中华 3 梅森素数 4 颠倒的价牌 5 三部排序 6 逆波兰表达式 7 错误票据 8 带分数 9 剪格子 10 大臣的旅费 前言:以下试题解答代码部分仅供参考,若有不 ...

  9. How to set up OpenERP for various timezone kindly follow the following steps to select timezone in OpenERP

        How to set up OpenERP for different Time Zones Click on the "Edit Preferences" wheel a ...

  10. [C#]记录程序耗时的方法【转发】

    System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); // H ...