[{"data":1,"prerenderedAt":468},["ShallowReactive",2],{"\u002F2020-09-17-note-cedec2020-final-fantasy-vii-remake-animation":3},{"id":4,"title":5,"body":6,"date":445,"description":12,"extension":446,"meta":447,"navigation":450,"path":462,"seo":463,"stem":464,"tags":465,"__hash__":467},"blogs\u002F_legacy\u002F2020\u002F2020-09-17-note-cedec2020-final-fantasy-vii-remake-animation.md","FF7重置版动画技术笔记",{"type":7,"value":8,"toc":404},"minimark",[9,13,22,25,29,32,39,42,45,48,52,55,59,62,68,73,76,80,83,87,95,98,107,116,120,123,126,129,133,136,139,142,145,149,152,155,159,162,165,169,172,175,179,182,185,191,194,197,200,213,216,222,225,229,232,236,239,242,245,248,251,254,257,261,269,273,281,285,288,292,295,309,313,316,319,322,325,328,332,335,338,341,344,348,351,354,357,361,364,367,370,373,376,379,385,392,395,398,401],[10,11,12],"p",{},"CEDEC2020上的FF7的技术分享的笔记，不过我没赶上直播，事后看的PPT。",[10,14,15,16],{},"CEDEC页面：",[17,18,19],"a",{"href":19,"rel":20},"https:\u002F\u002Fcedec.cesa.or.jp\u002F2020\u002Fsession\u002Fdetail\u002Fs5e58c8811bc98",[21],"nofollow",[10,23,24],{},"FF7是UE4做的，所以可以参考的部分就会多一些。",[26,27,28],"h2",{"id":28},"动画结构",[10,30,31],{},"首先是整个角色动画的结构的概览，如果只是想要粗略的了解的话，看这张图就够了：",[10,33,34],{},[35,36],"img",{"alt":37,"src":38},"animation-struct","\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage-300x121.png",[10,40,41],{},"左边上边两个，首先是游戏场景动画，然后到过场动画的动画。这两个是串行的，由于没有玩过FF7R，猜测可能过场动画是以游戏场景为基础直接播放的，而不是作出固定的Sequence动画。",[10,43,44],{},"左边下边的两个，是LipSync到过场动画的Facial动画，也就是嘴唇的动作叠加到过场动画的表情动画上。",[10,46,47],{},"其他的都和中文的表意差不多，下面会有列出，就不赘述了。",[26,49,51],{"id":50},"primary-animation","Primary Animation",[10,53,54],{},"主动画部分根据当前角色的状态完成主要的动作更新，例如当前的行走、攻击等动作的播放应该都在这边。",[56,57,58],"h3",{"id":58},"游戏场景动画",[10,60,61],{},"上面那张图左上角的Filed Body(フィールドボディ)，就只是简单的列出了下结构",[10,63,64],{},[35,65],{"alt":66,"src":67},"field-animation","\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage-1-300x140.png",[69,70,72],"h4",{"id":71},"locomotion","Locomotion",[10,74,75],{},"Locomotion上是针对所有角色的基础移动动画逻辑，这个应该和大多数游戏的实现是一样的，根据StateMachine以及其他State的差分来应用不同的动画叠加。通过切换动作的配置可以实现动态的切换，这里的MotionPack不是很确定具体指的是什么。从实现上看，动画蓝图中引入的motion是可以在C++层面动态指定的。但FF7R具体在什么时间切换这些并没有具体说明，不过这个根据游戏逻辑不同会有不同，写出来其实也没什么太大的参考意义。",[69,77,79],{"id":78},"action","Action",[10,81,82],{},"角色固有的动作动画。根据运行时游戏逻辑中玩家的输入进行动态的切换，通常的攻击动画应该都是在这里进入动画逻辑的。动作根据类型定义，可以根据不同的角色进行任意的状态管理。对于同一层的Action，如果有新的玩家输入进来的话，会进行中断和替换处理。",[69,84,86],{"id":85},"resident","Resident",[10,88,89,90,94],{},"一些装饰性物品的动画，比如尾巴这些与Locomotion的状态管理无关的东西的动画处理。由于用的是",[91,92,93],"em",{},"常驻","这样的描述，不是很确定头发和衣服是否在其中。尾巴应当算是装饰物，可能我对词语的理解有偏差，话说有角色有尾巴的吗？没玩过原作不是很确定。总之实际上就是那些与主动画循环关系不大的部分放在主动画更新完成后进行一次更新。",[56,96,97],{"id":97},"惯性补间",[10,99,100,101,106],{},"在混合的时候不考虑源动画，只朝着目标动画进行计算的方式。在减少运算量的同时提高动画的流畅感，但是会增加一些内存消耗。PPT里面列了很多计算的公式和内部的设计的原理，由于在UE4.24已经作为引擎功能提供了，直接在动画蓝图中使用",[17,102,105],{"href":103,"rel":104},"https:\u002F\u002Fdocs.unrealengine.com\u002Fzh-CN\u002FEngine\u002FAnimation\u002FNodeReference\u002FBlend\u002Findex.html",[21],"Inertialization","动画混合方式就可以了。",[10,108,109,110,115],{},"想要详细的了解技术方面可以参考之前的GDC分享：",[17,111,114],{"href":112,"rel":113},"https:\u002F\u002Fwww.gdcvault.com\u002Fplay\u002F1025331\u002FInertialization-High-Performance-Animation-Transitions",[21],"Inertialization-High Performance Animation Transitions","，当然也可以去看UE4的源码实现方式。",[56,117,119],{"id":118},"pose-matching","Pose Matching",[10,121,122],{},"在目标动画有好几个候补的时候，通过对这几个动画进行比较来决定使用哪一个动画。例如，从行走到停止的状态，会事先设定一些候补的动画，然后根据当时状态选择一个最合适的。",[10,124,125],{},"候补的动画列表可以按照角色进行不同的配置，同时也可以使用动画通知对候补列表进行追加和限制。",[10,127,128],{},"进行动画比较时并不是使用全体的骨骼进行评估，而是使用事先设定的骨骼进行比较。例如，二足行走的时候使用下半身的基础骨骼进行比较。",[26,130,132],{"id":131},"secondary-animation","Secondary Animation",[10,134,135],{},"次要动画在主要动作确立之后对动作进行微调，通常的足IK、手部IK都在这里。",[56,137,138],{"id":138},"输入补正",[10,140,141],{},"根据来自玩家或者AI的输入对骨骼进行动态的旋转补正，通过IK Control Rig进行配置所以可以在角色间公用，同时可以在编辑器中进行动态的预览。这个记得之前ALS里面也有类似的实现，可以给用户输入一个细节上的反馈，例如在向前加速的过程中有一个向前倾的动作。",[10,143,144],{},"输入补正的配置资源保存在IK Control Rig中，运行时直接进行叠加。",[56,146,148],{"id":147},"look-at","Look At",[10,150,151],{},"LookAt的处理只使用惯性补间和线性补间，可以针对每个骨骼进行其重量和角速度的设定。使用惯性补间时，对其到达时间进行一个随机的基础数值叠加。在角度的限制上区分了Pitch和Yaw。在进行姿态维持时，可以将骨骼的目标按照Mesh的空间进行指定。",[10,153,154],{},"LookAt在操作上可以在具体的动作中通过动画通知暂时的关掉。",[56,156,158],{"id":157},"aim","Aim",[10,160,161],{},"Aim的处理只使用EaseOut和线性补间，不使用惯性补间的原因是目标在不断的进行移动时惯性补间的效果很差。通过AimGroup来针对每个骨骼进行重量和角度设定，并在动画蓝图通知中对不同的AimGroup进行选择。",[10,163,164],{},"Aim的设定主要在AimGroup中，动画只能指定不使用Aim，运行时也不会调整这些参数。",[56,166,168],{"id":167},"hand-ik","Hand IK",[10,170,171],{},"使用FABRIK算法，IK的目标分为两种：指定世界坐标的固定目标和使用特效等的相对位置的锁定目标。使用锁定目标的IK时，由于使用的是补间之前的位置，可以充当LookAt和FootIK的反动作。",[10,173,174],{},"与Aim相同，运行时只能使用设定好的HandGroup，具体的配置是在资源中固化的。",[56,176,178],{"id":177},"footik-hip-control","FootIK & Hip Control",[10,180,181],{},"与其他游戏一样检出地面的凹凸来调整脚的位置，同时根据脚的目标位置(FootLock)对腰的骨骼施加一个动态的偏移。战斗中防御动作时，对腰部施加了一个额外的向下10cm的偏移来表现重心的下落。",[10,183,184],{},"为了避免滑步移动的现象，会对当前脚的最低点到地面的距离Base Height进行维护。",[10,186,187],{},[35,188],{"alt":189,"src":190},"foot-ik-base-hegith","\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage-2-150x150.png",[10,192,193],{},"在站立或行走时，会根据脚接触地面的最低的位置来调整腰部的下落。同时根据地面的倾斜度来调整root骨骼的旋转以反应腰部的骨骼位置补正。",[56,195,196],{"id":196},"平衡控制",[10,198,199],{},"由于Foot Ik与Hip Control导致角色的中心出现偏移时，通过倾斜角度对骨骼的旋转进行调整。调整的内容包括：",[201,202,203,207,210],"ul",{},[204,205,206],"li",{},"根据Pitch计算补正值",[204,208,209],{},"根据Pitch的绝对值进行补正",[204,211,212],{},"根据Roll进行补正",[10,214,215],{},"这个中心偏移，原文描述的是类似人物的中轴线的感觉。当人站在斜坡上时，为了保持平衡，其站立方向应该还是向上的。如下图：",[10,217,218],{},[35,219],{"alt":220,"src":221},"ballance-control","\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002Fimage-3-150x150.png",[10,223,224],{},"模拟的是人在斜坡上的一种后倾的维持平衡的动作。",[56,226,228],{"id":227},"control-rig的必要性","Control Rig的必要性",[10,230,231],{},"Control Rig可以方便对动画蓝图中的补正进行运行时效果进行观察和调整，有时这种运行时的效果调试比设定专门的预览环境更加能够有效的达到目的。尤其是根据背景物体和周围角色而表现不同的地方，在游戏环境中直接测试能够更好的对效果进行控制和调整。",[56,233,235],{"id":234},"bodydriver","BodyDriver",[10,237,238],{},"是内部研发的一种物理动画特效。用于击倒动画中，与通常的RagDoll不同，会有角色按住受击部位的同时后退的演出。",[10,240,241],{},"目测，应该就是在击倒动画时有一部分骨骼是开启了物理的，然后另一部分叠加了按住受击部分等的动画控制。通过这样可以为击倒动画添加不同的表现，提升演出效果。",[10,243,244],{},"一般的RagDoll直接打开的话总是会有很大的概率出现非常鬼畜的效果，所以FF7R的对应方式值得参考一下。",[56,246,247],{"id":247},"物理拘束补正",[10,249,250],{},"通过Position base dynamice添加基于物理拘束的补正处理。通过将约束条件进行Preset化并保存到Mesh的用户数据中。",[10,252,253],{},"通过物理拘束补正，可以表现鱼在沿着Spline移动时身体的扭动。对于与部分的角色，会将物理拘束补正与受击反馈结合起来，表现出更好的受击效果。由于是工作在Mesh空间的，成本较低，对于一些简单的背景物体也可以使用。",[10,255,256],{},"PBD本身使用物体的速度计算出位置，然后将所有的约束叠加到物体上得到新的位置，根据这个位置重新推断出速度来。可以在运行时调整物理的开关以及速度和重力等属性。",[56,258,260],{"id":259},"kinedriver","KineDriver",[10,262,263,264,268],{},"辅助骨骼：",[17,265,266],{"href":266,"rel":267},"https:\u002F\u002Fcedil.cesa.or.jp\u002Fcedil_sessions\u002Fview\u002F2007",[21],"，这个还没仔细看过，大体上是由实际的运动骨骼去驱动一个虚拟的骨骼，然后这个虚拟的骨骼可以决定Mesh的显示、特效等其他的参数。看演示效果，应该主要是用于实现一些无法单纯用骨架来实现的模型形变。",[56,270,272],{"id":271},"bonamik","Bonamik",[10,274,275,276,280],{},"参考资料：",[17,277,278],{"href":278,"rel":279},"https:\u002F\u002Fcedil.cesa.or.jp\u002Fcedil_sessions\u002Fview\u002F1583",[21],"。这个挺复杂的，简单的看了下，似乎是基于Position Based Dynamic的原理来基于骨骼进行一些物理模拟的辅助，主要用于防止衣服等物体穿模。",[26,282,284],{"id":283},"facial-animation","Facial Animation",[10,286,287],{},"表情动画能够让角色的表现更加自然，FF7R制定了一套程序化生成的表情动画流程。",[56,289,291],{"id":290},"saccade","Saccade",[10,293,294],{},"眼球運動，人的眼球在稳定凝视点和转移凝视点的时候的一种非自主反射运动……总之在FF7中专注于两种眼球运动的模拟，一种是在视角移动时的眼球运动，频率在12.5～17.5Hz，单次移动的角度是有限制的。另一种是注视的时候的微小眼动，频率和幅度更小的线性运动。",[10,296,297,298,302,303,308],{},"想要详细了解的可以参考维基百科的描述，由于是专业外，很多术语并不是很明确的了解，就不去强行解释了。参考链接：",[17,299,291],{"href":300,"rel":301},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSaccade",[21],"以及",[17,304,307],{"href":305,"rel":306},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMicrosaccade",[21],"Microsaccade","。",[69,310,312],{"id":311},"saccade眼睑联动","Saccade眼睑联动",[10,314,315],{},"眼球运动的话会带动眼睑的运动，实际过程应该是相反的？我不是很了解生物学也就不去纠结了。",[10,317,318],{},"添加这个联动主要是为了让Saccade的运动变得更加明显，将Yaw和Pitch作为输入对眼皮的上下左右运动进行Blend。",[69,320,321],{"id":321},"自动生成",[10,323,324],{},"Saccade可以使用身体和脸的朝向自动生成的，使用jenkins对所有的角色动画进行曲线的烘培。",[10,326,327],{},"自动生成的流程只在动画不被LookAt控制的时候使用，通常用于攻击动画等时机。原理上面有提到，在视角目标变动的时候会有额外的眼动逻辑。",[56,329,331],{"id":330},"gaze-diversion","Gaze diversion",[10,333,334],{},"人在注视的时候会无意识的移开视线的现象，尤其在对话中的非语言交流更加能体现，因为凝视会被视为敌对表现。由于详细的对条件进行设定在实现上会有很多麻烦，实际上只是添加了在表现过程中随机的移开视线。",[56,336,337],{"id":337},"眨眼",[10,339,340],{},"眨眼以2～10秒的间隔周期性的随机发生，当视角大规模移动时的反射性眨眼则在LookAt的对象移动位置很大的时候发生。",[10,342,343],{},"眨眼没有很多动画，在闭眼动作的基础上进行blend来实现。单次眨眼并不一定完全闭上眼睛，而是在0.5～1.0之间进行随机。",[56,345,347],{"id":346},"happysadface","HappySadFace",[10,349,350],{},"是一套LipSync系统，通过语音和文本生成统一的格式，可以在Maya和UE4中进行嘴唇动画的控制。可以处理日语、英语、法语和德语。",[10,352,353],{},"从语音中抽出音素，使用音素对形变动画生成时间轴变化。针对每种语言的音素到形变采用的是不同的映射方式。同时，针对语音的情感状态，也会采用不同的形变预设。也就是说，根据下面的情感推定的结果，会针对不同的情感状态采用不同的嘴唇动画。",[10,355,356],{},"这个系统的一个问题是在流程上容易出错，如果文本有误或者声优进行了即兴演出的话，会导致生成的精读下降。同时，虽然在没有语音时产生嘴唇动画很容易排查，但是如果出现嘴形对不上的问题很难逐一进行目视确认。",[56,358,360],{"id":359},"voiceattack","VoiceAttack",[10,362,363],{},"通过对话的音量对眉毛进行控制，动画上只是通过音量值传入然后对眉毛向上的动画进行blend。",[10,365,366],{},"同时也会通过音量来让上体和头部有一个额外的摇动动作，这个动作是配在Ik control rig中的，在运行时会随机的决定一个预设来使用。",[56,368,369],{"id":369},"表情生成",[10,371,372],{},"使用ST Emotion通过语音来推定情感，通过情感的指数对各个表情动画进行混合。推定的情感指数是一种时间线数据，并不是针对单句语音，而是会在一个语音中有表情的变化。",[10,374,375],{},"情感推定的精读在70%左右，但是单单只是给表情添加了变化就能带来很大的表现提升。",[10,377,378],{},"情绪指数参考Russel的情感圆环模型针对所有的角色进行设置。根据情绪指数的不同其在情感圆环中的采样位置就会不同，为了避免线性插值导致的生硬变化，使用自定义的曲线进行插值。",[10,380,381],{},[35,382],{"alt":383,"src":384},"emotion-circle","\u002Fwp-content\u002Fuploads\u002F2020\u002F09\u002FFF7-circle-150x150.png",[10,386,387,388,308],{},"Russel情感圆环应该是这篇：",[17,389,390],{"href":390,"rel":391},"https:\u002F\u002Fpsycnet.apa.org\u002Frecord\u002F1981-25062-001",[21],[10,393,394],{},"ST Emotion可以实时的对情感进行检出，对五种情感每一种检出到10个精度上。对应的情感为：喜悦、愤怒、悲伤、平常和兴奋。",[26,396,397],{"id":397},"总结",[10,399,400],{},"FF7R的整体角色动画流程的处理有非常多的值得参考的部分，虽然一些技术细节并没有公布，但是并没有什么影响。因为根据项目需求的不同其实很多地方也会不一样，即便拿到源代码后面能用的部分也不多。",[10,402,403],{},"ST Emotion是商业项目，由于官方网站没有标价所以不是很确定使用成本，不过情感推定作为人工智能领域的一个广泛研究的主题，应该也能找到好的替代品，如果对开发周期特别敏感的话也可以尝试购买使用。",{"title":405,"searchDepth":406,"depth":407,"links":408},"",2,3,[409,410,420,433,444],{"id":28,"depth":406,"text":28},{"id":50,"depth":406,"text":51,"children":411},[412,418,419],{"id":58,"depth":407,"text":58,"children":413},[414,416,417],{"id":71,"depth":415,"text":72},4,{"id":78,"depth":415,"text":79},{"id":85,"depth":415,"text":86},{"id":97,"depth":407,"text":97},{"id":118,"depth":407,"text":119},{"id":131,"depth":406,"text":132,"children":421},[422,423,424,425,426,427,428,429,430,431,432],{"id":138,"depth":407,"text":138},{"id":147,"depth":407,"text":148},{"id":157,"depth":407,"text":158},{"id":167,"depth":407,"text":168},{"id":177,"depth":407,"text":178},{"id":196,"depth":407,"text":196},{"id":227,"depth":407,"text":228},{"id":234,"depth":407,"text":235},{"id":247,"depth":407,"text":247},{"id":259,"depth":407,"text":260},{"id":271,"depth":407,"text":272},{"id":283,"depth":406,"text":284,"children":434},[435,439,440,441,442,443],{"id":290,"depth":407,"text":291,"children":436},[437,438],{"id":311,"depth":415,"text":312},{"id":321,"depth":415,"text":321},{"id":330,"depth":407,"text":331},{"id":337,"depth":407,"text":337},{"id":346,"depth":407,"text":347},{"id":359,"depth":407,"text":360},{"id":369,"depth":407,"text":369},{"id":397,"depth":406,"text":397},"2020-09-17","md",{"layout":448,"status":449,"published":450,"author":451,"author_login":452,"author_email":453,"author_url":454,"wordpress_id":455,"wordpress_url":456,"date_gmt":457,"excerpt":458},"post","publish",true,{"display_name":452,"login":452,"email":453,"url":454},"chaoshikari","chaoshikari@gmail.com","\u002F",2939,"\u002F?p=2939","2020-09-17 15:05:58 +0000",{"type":7,"value":459},[460],[10,461,12],{},"\u002F2020-09-17-note-cedec2020-final-fantasy-vii-remake-animation",{"title":5,"description":12},"_legacy\u002F2020\u002F2020-09-17-note-cedec2020-final-fantasy-vii-remake-animation",[466],"Animation","Q3LKOb2a2Rno6CG5WMb56TEjju4Tp3M8biDAcy2nBEo",1788763181228]