动态骨骼DynamicBone整理

关于布料模拟的方案早前就已经确定,DynamicBone作为插件果哥在离职前已经实现下C++版本,正好最近由于部门架构调整可以安心回来做技术想对它进行下优化,于是耐心抽时间看了下目前的实现。在对比楚留香的效果时顺带问了大弥撒亚的实现,几个项目也都基本采用弹簧质点模型用韦尔莱积分去迭代计算。只是测试下来目前实现性能存在问题,下面是简要的整理与说明,希望在下周能把它优化到满意程度

1. 简介

DynamicBone是一个简单的基于模拟弹簧振子的算法实现树状柔体的物理模拟插件。虽然基于模拟弹簧振子运动的算法实现,但是DynamicBone各节点之间的距离实际上不会发生变化, 比起弹簧,父子节点之间的相对运动更接近简谐运动中的单摆。

2. 使用说明

DynamicBone的使用非常简单,一句话说明,首先在Unity场景中选择要应用DynamicBone组件的GameObject添加组件,然后确定自己要应用DynamicBone的子节点,把最上层的子节点 的GameObject设置为DynamicBone组件的Root即可。然后设置各项参数,DynamicBone就会在物体发生运动的时候自动生效。要注意的问题有三个:

  • 因为DynamicBone组件会在启动时记录所有节点的局部座标并且在每次Update时还原局部座标,同时会根据所在的GameObject的移动计算节点位置,所以添加DynamicBone组件的 GameObject不能位于应用DynamicBone的模型节点树中,根节点也不行;
  • DynamicBone更新座标是在LateUpdate时进行的,这会导致DynamicBone的计算结果会覆盖动画输出的位置;
  • DynamicBone所有节点变换更新时,如果某个子节点是父节点唯一的子节点,会把这一帧内子节点发生的相对旋转同步到父节点上;

2.1. 关于碰撞

DynamicBone提供了简单的碰撞算法,允许使用者禁止进入或者离开某些特定的区域,组件提供了球型和胶囊体两种区域形状。碰撞功能的使用非常简单,只需要在希望与DynamicBone 节点发生碰撞交互的GameObject添加DynamicBoneCollider组件,并且设置以下属性:

  • Center:指定区域中心与GameObject位置的偏移量;
  • Radius:区域内球形部分的半径;
  • Height:区域高度,这个值在小于2倍Radius时无效,会使区域变成球型,高于2倍Radius时生效,区域会变成胶囊体(可视化模型是两个球体);
  • Direction:胶囊体在当前GameObject局部座标的方向,区域是球体的时候无效;
  • Bound:区域模式,Outside表示区域会作为碰撞盒与DynamicBone节点发生碰撞,阻止节点进入区域内,而Inside则会约束节点在区域内,阻止节点离开区域; 然后需要将DynamicBoneCollider对象添加至与其发生碰撞交互的DynamicBone组件的Colliders属性中。

3. 重要属性

DynamicBone有四个基本属性,决定了其运动效果,四个属性的取值范围都是[0, 1]:

  1. Damping 阻尼:阻止简谐运动的惯性运动,相当于弹簧的摩擦力。为0时简谐运动过程不会主动停止,为1时简谐运动过程不会发生;
  2. Elasticity 弹性:决定回振移动强度,在简谐运动过程中作为额外的作用力将节点拉到还原位置,相当于弹簧的弹力。为0时系统形变不会主动还原,为1时形变不会发生;
  3. Stiffness 刚性:限制最大振动幅度与方向,保证碰撞处理前节点不会跑到指定范围外,相当于弹簧的硬度。为0时不发挥作用,0到1时限制范围从2倍原始距离到0线性衰减;
  4. Inert 惯性:限制形变幅度,在每一帧的简谐运动迭代发生前,无条件随物体整体运动拉动节点,拉动距离为Inert * 整体运动距离;

4. 其他属性说明

  1. Update 更新频率:DynamicBone计算频率,当游戏实际帧率高于这个更新频率时,DynamicBone会在每一帧进行消极计算,会尽量保持节点形状,但不会进行简谐运动模拟;当DynamicBone更新 频率远远高于游戏帧率的时候,DynamicBone会在脚本执行时尝试追帧,但每次最多执行4次,也就是更新频率实际最高只是当前游戏帧数的4倍;
  2. Radius 半径:指定每个节点与DynamicBoneCollider发生碰撞的半径,注意节点互相之间不存在碰撞关系,注意这个半径是0碰撞依然会生效;
  3. Damping\Elasticity\Stiffness\Inert\Radius各属性的Distrib:指定属性随着节点深度递增发生的变化;
  4. End Length\End Offset 末尾节点偏移量:指定特殊的末尾节点End Bone局部位置,详见下方的4.1. 关于EndLength和EndOffset
  5. Gravity 重力:在DynamicBone节点上施加的重力,方向是在全局座标系中的,注意DynamicBone的重力比较特殊,只在节点运动发生时起效,会在节点运动时把节点向重力方向拉动;
  6. Force 常驻力:在DynamicBone节点上施加的额外力,方向是在全局座标系中的,注意Force与Gravity不同,是无条件生效的,会一直把节点向指定方向拉动;
  7. Colliders 碰撞体列表:会与DynamicBone各节点发生碰撞的碰撞体对象,详见2.1. 关于碰撞
  8. Exclusions 排除节点列表:在设置Root节点后,DynamicBone会根据节点的GameObject的父子关系沿着子GameObject方向自动生成节点树,Exclusions中所有节点及其子孙节点都不会 生成DynamicBone节点;
  9. Freeze Axis 固定轴:非None的情况下,所有节点在局部座标系的对应的轴上在值不会发生变化;
  10. DistanceDisable 距离控制开关:开启或者关闭距离控制机制,开启后如果DynamicBone所在的物体超出了参考物体的参考距离范围,DynamicBone的所有行为都会停止;
  11. Reference Object 参考物体:距离控制机制的参考物体,如果为空则DynamicBone会选择场景内的主摄影机作为参考对象;
  12. Distance To Object 参考距离:距离控制机制的参考距离;

4.1. 关于EndLength和EndOffset

DynamicBone有一个虚拟的End Bone机制,通过设置EndLength和EndOffset开启,当两个属性都是0时End Bone不会出现。DynamicBone每个骨骼节点与真实的GameObject是一一对应,但是 EndLength和EndOffset非0的时候,DynamicBone会创造一个虚拟的End Bone,作为末尾节点的子节点。这个虚拟节点没有对应的GameObject,所以其唯一的作用的就是将自己的相对旋转更新到 自己的父节点,也就是原本的末尾节点(子节点旋转同步到父节点的操作见2. 使用说明)。

EndLength和EndOffset的逻辑是,当EndLength为0,DynamicBone会直接使用EndOffset,在EndOffset指示的局部偏移位置安排一个End Bone节点;如果EndLength不为0,那么EndOffset 会根据EndLength计算得到(设置的EndOffset值会被舍弃),计算方法是末尾节点的父节点沿末尾节点方向延伸EndLength长度,如果末尾节点就是根节点,则沿着末尾节点的局部座标的X轴延伸 EndLength。

5. 使用限制和缺陷

  1. 由于DynamicBone完全不发生拉伸和压缩的特性,DynamicBone并不适合模拟凝胶、橡胶等各方向形变明显的物体,而更适合模拟头发、绳子等不容易拉伸但容易形变的物体, 衣物则要看衣物材质是否容易拉伸,如果容易拉伸依然不适合用DynamicBone模拟;
  2. 虽然有简单的碰撞机制,DynamicBone的各节点之间是不存在碰撞的(当然可以通过在各节点都设置DynamicBoneCollider组件来实现,但因为开销会很高所以不建议),这意味着DynamicBone 模拟的物体在刚性为0的时候可能会发生自我穿插;
  3. DynamicBone的位置更新发生在LateUpdate节点,这意味着DynamicBone会完全控制节点的位置,其计算结果会覆盖物理和动画系统输出的位置,而不能与其融合;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章