Unityでキャラの表情コントロール2
Unity



Blenderで作ったシェイプキー付きのフィギュアをFBXでUnityにインポートするとメッシュごとにインスペクター上の「Skinned Mesh Renderer」の「BlendShapes」で操作できるようになっています。




カレンの顔には29個の表情シェイプキーが付けてあります。あと、眉毛に8個、目に5個、その他に汗や赤面等が12個ほど付けてあります。




モーフのブレンド値は3Dソフトでは一般的に0が最小値で1.0が最大値だと思いますが、Unityでは100が最大値となります。はじめ、1にしても変化したように見えなくて焦りました。

表情アニメーションをUnity上から付ける方法は2つあります。新規にアニメーションクリップを作って「Animation」でキーフレームを打ってさせる方法。もう一つは、スクリプトからBlendShapesを操作する方法です。

しかし、最初スクリプトから動かそうとしてもうまくいきませんでした。「Animation」でキーフレームを打ってさせる方法は重ねたいアニメーションにレイヤーで重ねればよいのですが、スクリプトからでは元のアニメーションのキーフレームの方が優先されるらしく反応してくれませんでした。(スクリプトからレイヤーのようなものを作ってブレンドさせる方法があるのかまでは分かりません)

手っ取り早い解決方法は、元のアニメーションの表情のキーフレームを削除してしまうことです。しかし、FBXでインポートしたアニメーションはデフォルトでは(Read-Only)となっていてキーフレームの削除どころか編集できないようになっています。




こういう時は、FBXのアニメーションクリップを複製(Ctrl + D)してそちらを使用すれば編集可能になります。




とりあえず、シェイプキーのキーフレームを全部削除しておきます。


public class FacialMorphing2 : MonoBehaviour {

    private SkinnedMeshRenderer SKMR_Kao;
    private SkinnedMeshRenderer SKMR_Mayu;  
    private SkinnedMeshRenderer SKMR_me;
    private SkinnedMeshRenderer SKMR_other1;  
    private SkinnedMeshRenderer SKMR_other2;

    private Transform kao;
    private Transform mayu;
    private Transform me;
    private Transform other1;
    private Transform other2;

    public Mesh kaoMesh;

    private int shape_me;
    private int shape_kuti;
    private int shape_mayu;

    void Awake() {
        kao = transform.FindChild("kao");
        mayu = transform.FindChild("mayu");
        me = transform.FindChild("me");
        other1 = transform.FindChild("other1");
        other2 = transform.FindChild("other2");
    }

    void Start() {
        SKMR_Kao = kao.GetComponent<SkinnedMeshRenderer>();
        SKMR_Mayu = mayu.GetComponent<SkinnedMeshRenderer>();
        SKMR_other1 = other1.GetComponent<SkinnedMeshRenderer>();
        SKMR_other2 = other2.GetComponent<SkinnedMeshRenderer>();
    }
...


あとは、各メッシュのSkinnedMeshRendererコンポーネントを取得し各BlendShapesの値を操作します。各メッシュそれぞれにスクリプトをアタッチするとモーフミキシングがバラバラになりやりにくくなるので親元から子のメッシュを取得するようにしました。

FindChildで取得する数が増えると処理が重くなることを想定して、明確にStart()の前に実行されるAwake()を使っています。(FindChildって公式リファレンスに載ってないのですがあんまり使うべきではないのでしょうかね。publicで直接取得でも良かったと思いつつ。)


        shape_mayu = 6;
        shape_me = kaoMesh.GetBlendShapeIndex("ジト目");
        shape_kuti = kaoMesh.GetBlendShapeIndex("たじろぎ_歯無し");

        SKMR_Mayu.SetBlendShapeWeight(shape_mayu, 100);
        SKMR_Kao.SetBlendShapeWeight(shape_me, 56);
        SKMR_Kao.SetBlendShapeWeight(shape_kuti, 100);

BlendShapesのブレンド値には
SkinnedMeshRenderer.SetBlendShapeWeightを使います。引数1はint型でブレンドシェープのインデックス番号で引数2がfloat値のブレンド具合です(リファンレスではウェイトは [0から100] の範囲に制限されないそうです)。

ブレンドシェープの数がひと目で分かるぐらいならインデックス番号でいいんですが、30、40ぐらいになってくるといちいち数えるのが大変になります。

こういう時、Mesh.GetBlendShapeIndexを使えばブレンドシェープに登録されてある名前の文字列からint型のインデックス値を返してくれます。日本語名でも使えるのでこちらの方が見分けやすいですね。ただし、対象のメッシュを予めMesh型で取得しておく必要があります。




スクリプトからBlendShapesを操作して表情を変えさせてみたものをbxSliderを使ってGIFアニメ風に再現してみました。(今回は動かす必要も無いと思い直立不動で表情のみ変化させています)

スクリプトのみで表情を動かすためには次の表情の前に表情を戻す処理や滑らかに遷移させるための処理を考える必要があったりと、やはりスクリプトだけでやるよりはAnimationを使った方が楽だと思いました。

あえて、スクリプトでBlendShapesを操作してアニメーションをさせるならリニアカーブ的に中割り無しで表情を切り替えるような演出をしたい時には使えるかなとかとも思いました。

Unity5.6にしてよく落ちるようになったという話ですが、Unity5.6で新規でプロジェクトを作ったものに関しては落ちることはまだありません。古いバージョンのプロジェクトを扱う時に注意しておけば安心のようです。


関連リンク:

Unityでキャラの表情コントロール

Unityでキャラの表情コントロール2

表情をスクリプトで滑らかに遷移

スポンサーサイト
テーマ: CG ジャンル: 日記
カテゴリ
ini-T MUSIC SKY
プロフィール