使用AdvancedSkeleton给Unity制作动画的一些经验技巧

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用AdvancedSkeleton给Unity制作动画的一些经验技巧相关的知识,希望对你有一定的参考价值。

参考技术A AdvancedSkeleton(俗称ADV)是大家在Maya中使用得非常多的一个绑定+动画插件,功能强大,简单易学。我们可以使用ADV来绑定角色,key出动画,然后输出成FBX供游戏引擎(比如Unity)来使用。

不过,由于ADV的开发初衷并非针对游戏,所以默认的骨骼设计比较繁琐,与Unity的Humanoid角色设定并不能完美通用。

比如,我们选择DeformationSystem节点(这是ADV放蒙皮骨骼的地方)和Geometry节点(通常将模型放在这里)然后导出的FBX,如果在Unity中以 Rig: Animation Type = Humanoid 的设定导入的话,骨骼的识别匹配是有问题的,通常会表现为明明Maya中脚步没有滑动,但导入Unity以后脚步就出现明显的滑动现象。

这是因为ADV的Deformation Rig的骨骼数量远远超过Humanoild的骨骼数量,转换后必然会丢掉很多骨骼的动画,这样累积起来就会造成动画的明显偏差。

解决的办法有两个:

一个办法是不使用Unity的Humanoid系统,将 Rig: Animation Type 设为 Generic ,这样能够完美保留动画的全部细节,但缺陷也很明显,设为 Generic 之后基本上就只能用自己调的动画了,不能直接套用海量的Unity动作资源库。对于我这种用习惯了资源库的懒人来说简直是不可忍受的。

另一个办法是利用ADV的“游戏骨骼(Game Skeleton)”功能,这个功能可以自动建立一套符合Unreal规范的标准骨骼系统,甚至还可以将原本DeformationSystem的蒙皮转移到这套新骨骼上去。Unreal标准骨骼系统和Unity的Humanoid是完美匹配的,这样我们就可以很愉快的在Unity中利用Humanoid系统同时使用自己制作的动画以及海量动作资源库的素材了。

具体操作步骤如下:

导出带骨骼蒙皮的模型:

首先在Rig文件中点击 Game Skeleton -> Create ,场景中会创建一套以 root 节点开头的骨骼,这套骨骼是完美匹配我们的Rig的,大家在配图中看到多出来的骨骼是原本Rig中就没有的手指结构(是的,原本的Rig中就没有做5根手指,所以这个Game Skeleton就匹配不了),这些多余的结构是可以直接删除的。

然后,点击 Transfer Skinning ,ADV会将蒙皮权重转移给新的游戏骨骼系统。大家要注意Maya底端的提示,如果看到 // Skinning transferred to Unreal Skeleton 字样就说明转换成功了。如果再次点击 Transfer Skinning ,ADV会将蒙皮权重转回给原来的DeformationSystem。

转移权重成功后,就可以选择这个新的 root 节点和原来的 Geometry 节点,导出成FBX,这就是我们的可以在Unity中使用的带骨骼蒙皮的角色资产了。通常我会在Unity的FBX导入设置中设置无动画、无材质、Humanoid类型Rig。

导出动画:

动画的导出更为简单。首先还是点击 Game Skeleton -> Create 来创建Game Skeleton。我个人建议先将模型复原成绑定姿态再创建Game Skeleton,可以到实际动画曲线之外的帧,点击ADV最底下的 Go To Build Pose 按钮。

然后直接选择 root 节点,导出成FBX,这就是纯骨骼动画资产。要注意: root 以及其下的骨骼都是受驱动控制的,并没有关键帧和动画曲线,在导出FBX的设置中不仅需要勾选 动画 ,还需要勾选 烘焙动画 并设置烘焙范围。

动画FBX在Unity中的设置也是无材质+Humanoid Type,不过Rig中的Avatar我会拷贝前面Rig模型所创建的Avatar,不喜欢工程中多出一堆无用的Avatar来。

Animation那里需要修改下动画片段名称,并设置动画片段范围。希望动画片段循环播放的可以勾选 Loop Time 选项。

默认的Animation导入设置会将动画曲线做一些优化,通常情况下就都让它优化吧,但如果发现优化后的动画出现了明显的问题,可以将 Anim. Compression 设置为 Off 。

最后不要忘记了点击 Apply 按钮确认修改。

白模是转成Game Skeleton后导出的Humanoid Type,有贴图的是原始动画导出的Generic Type,两者基本看不出差异来。

Unity3D日常开发Unity循环里面给按钮添加绑定事件

一、前言

今天介绍的是在开发中遇到的一个坑。
问题是:有三个按钮,分别点击之后显示对应的界面,我一听,这不就可以使用循环解决吗?
比如代码:

using UnityEngine;
using UnityEngine.UI;

public class TestBtn : MonoBehaviour
{
    public Button[] AllBtn;
    public GameObject[] ALLPanel;

    void Start()
    {
        for (int i = 0; i < AllBtn.Length; i++)
        {
            AllBtn[i].onClick.AddListener(() => BtnEvent(i));
        }
    }

    private void BtnEvent(int index)
    {
        Debug.Log(index);
        for (int i = 0; i < ALLPanel.Length; i++)
        {
            ALLPanel[i].SetActive(false);
        }
        ALLPanel[index].SetActive(true);
    }
}

对吧,代码很简单,但是一运行就报错:
在这里插入图片描述
索引超出了数组的边界。

这个报错也很明了,然后Debug显示传来的索引是3

这就是问题,那么进行分析一下

二、分析

分析内容参考文章:
Unity之在循环里面给多个按钮绑定点击事件

现在是无论点击哪一个按钮,传入的索引都是3,也就是最后一次循环的下标,也就是i的值

那么这个过程就是,虽然看似是一对一绑定,其实是i=3循环结束,然后再点击按钮的时候,去i这个临时变量的内存中去取值,i=3,所以点击任意按钮,都是以3的下标传递。

为了更清楚这个过程,请看图:

你以为的绑定过程:

在这里插入图片描述

实际的绑定过程:

在这里插入图片描述

三、解决思路

解决思路也很简单,这不是三个按钮都指向了循环中的临时变量i的内存地址吗

那我们就每次循环就新建一个内存地址

然后让按钮分别指向不同的内存地址就行了

如下所示:

using UnityEngine;
using UnityEngine.UI;

public class TestBtn : MonoBehaviour
{
    public Button[] AllBtn;
    public GameObject[] ALLPanel;

    void Start()
    {
        for (int i = 0; i < AllBtn.Length; i++)
        {
            int temp = i;
            AllBtn[i].onClick.AddListener(() => BtnEvent(temp));
        }
    }

    private void BtnEvent(int index)
    {
        Debug.Log(index);
        for (int i = 0; i < ALLPanel.Length; i++)
        {
            ALLPanel[i].SetActive(false);
        }
        ALLPanel[index].SetActive(true);
    }
}

每次都新建一个int temp去接收临时变量i的值,并且自己再开辟一块空间

然后按钮点击的时候,就去自己指定的内存空间取值即可。

就OK了
在这里插入图片描述

以上是关于使用AdvancedSkeleton给Unity制作动画的一些经验技巧的主要内容,如果未能解决你的问题,请参考以下文章

从 Google Play 服务、Unity 插件获取所有回合制比赛信息

如何使用 Unity 中的 Photon 和骰子在棋盘游戏中创建回合制经理?

Unity 中 Google Games Services 回合制多人游戏的自定义 UI

Unity 中的回合制网络

Unity3D 怎样获得摄像机角度(rotation)

Unity 掷骰子后让玩家的棋子轮流移动