Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9366

AnimationCurveを使わずにVRMをC#で走らせてみる【Unity】

$
0
0

これは Unity Advent Calendar 2019の25日目の記事です。
昨日は @youri_sskさんによる 2.5Dキャラクターアニメーション - Mirror Animation Playableでした。

Animation Curveを使わずにC#だけでVRMを走らせてみる

Animation Curveを使えば、便利なGUIで3Dアニメーションを作ることができます!

そう!普通の人ならAnimation Curveを使いましょう!!(もちろん、BlenderとかUnity外のツールでもいいです)

しかし!Qiita読者の皆さんは プログラマーなんです!

プログラマーだったらプログラミングで3Dアニメーションを作りたいですよね!

というわけで、VRMアバターをC#で動かしてみます!

最終的にはこんな感じのアニメーションが作れました。

201912241856a.gif

動作環境

以下の環境でやりました。

  • Windows 10 64bit
  • Unity 2019.2.11f1
  • UniVRM 0.54.0

初期状態

とりあえずVRMファイルをシーンに読み込んでみます。

今回は 今里尚吾くんにご協力いただきます!(VRoid Studioで作りました!)

image.png

Hierarchyを見てみたらこんな感じでした!

image.png

股関節を30度に曲げてみる

まずは、股関節を曲げてみましょう。

以下のスクリプトを作成します。

usingSystem;usingUnityEngine;publicclassPendulumRunning:MonoBehaviour{// transformを保管する変数privateTransformcHips;privateTransformlUpperLeg;privateTransformrUpperLeg;voidStart(){// 腰のtransformを取得cHips=transform.Find("Root").Find("J_Bip_C_Hips");// 股関節のtransformを取得lUpperLeg=cHips.Find("J_Bip_L_UpperLeg");rUpperLeg=cHips.Find("J_Bip_R_UpperLeg");}voidFixedUpdate(){// 脚を30°傾けるlUpperLeg.rotation=Quaternion.AngleAxis(-30.0f,Vector3.right);rUpperLeg.rotation=Quaternion.AngleAxis(30.0f,Vector3.right);}}

作成できたら、シーン内のVRMにアタッチします。

image.png

脚が前後に開きました!

image.png

image.png

振り子のように足を揺らしてみる

せっかくなので、アニメーションさせたいですよね。

ということで、振り子のように揺らしてみます!

voidFixedUpdate(){// 1秒周期の振り子を用意するfloatpendulum=(float)Math.Sin(Time.time*Math.PI);// 股関節を右軸(x軸)を中心に±60°幅で揺らすlUpperLeg.localRotation=Quaternion.AngleAxis(-60.0f*pendulum,Vector3.right);rUpperLeg.localRotation=Quaternion.AngleAxis(60.0f*pendulum,Vector3.right);}

201912241743a.gif

いいかんじ!

膝を曲げてみる

膝も曲げてみたくなったので、 LowerLegを追加してみました。あと係数とかを微調整したのがこちらです。

publicclassPendulumRunning:MonoBehaviour{privateTransformcHips;privateTransformlUpperLeg;privateTransformrUpperLeg;privateTransformlLowerLeg;privateTransformrLowerLeg;voidStart(){cHips=transform.Find("Root").Find("J_Bip_C_Hips");lUpperLeg=cHips.Find("J_Bip_L_UpperLeg");rUpperLeg=cHips.Find("J_Bip_R_UpperLeg");// 膝のtransformを取得lLowerLeg=lUpperLeg.Find("J_Bip_L_LowerLeg");rLowerLeg=rUpperLeg.Find("J_Bip_R_LowerLeg");}voidFixedUpdate(){floatpendulum=(float)Math.Sin(Time.time*Math.PI);// 股関節の動きを少し変更lUpperLeg.localRotation=Quaternion.AngleAxis(-60.0f*pendulum-20.0f,Vector3.right);rUpperLeg.localRotation=Quaternion.AngleAxis(60.0f*pendulum-20.0f,Vector3.right);// 膝を揺らすlLowerLeg.localRotation=Quaternion.AngleAxis(-60.0f*pendulum+60.0f,Vector3.right);rLowerLeg.localRotation=Quaternion.AngleAxis(60.0f*pendulum+60.0f,Vector3.right);}}

201912241818a.gif

膝も曲がりました。

全身動かしてみる

同じ要領で、全身の関節の動かしてみます。色々調整したら、以下のようなコードになりました。

publicclassPendulumRunning:MonoBehaviour{privateTransformcHips;privateTransformlUpperLeg;privateTransformlLowerLeg;privateTransformrUpperLeg;privateTransformrLowerLeg;privateTransformcSpine;privateTransformcChest;privateTransformcUpperChest;privateTransformlShoulder;privateTransformlUpperArm;privateTransformlLowerArm;privateTransformrShoulder;privateTransformrUpperArm;privateTransformrLowerArm;voidStart(){// 全身の関節のtransformを取得cHips=transform.Find("Root").Find("J_Bip_C_Hips");lUpperLeg=cHips.Find("J_Bip_L_UpperLeg");lLowerLeg=lUpperLeg.Find("J_Bip_L_LowerLeg");rUpperLeg=cHips.Find("J_Bip_R_UpperLeg");rLowerLeg=rUpperLeg.Find("J_Bip_R_LowerLeg");cSpine=cHips.Find("J_Bip_C_Spine");cChest=cSpine.Find("J_Bip_C_Chest");cUpperChest=cChest.Find("J_Bip_C_UpperChest");lShoulder=cUpperChest.Find("J_Bip_L_Shoulder");lUpperArm=lShoulder.Find("J_Bip_L_UpperArm");lLowerArm=lUpperArm.Find("J_Bip_L_LowerArm");rShoulder=cUpperChest.Find("J_Bip_R_Shoulder");rUpperArm=rShoulder.Find("J_Bip_R_UpperArm");rLowerArm=rUpperArm.Find("J_Bip_R_LowerArm");}voidFixedUpdate(){// 速度を3倍に変更floatpendulum=(float)Math.Sin(Time.time*Math.PI*3.0f);// 脚を揺らす        lUpperLeg.localRotation=Quaternion.AngleAxis(-60.0f*pendulum-20.0f,Vector3.right);rUpperLeg.localRotation=Quaternion.AngleAxis(60.0f*pendulum-20.0f,Vector3.right);lLowerLeg.localRotation=Quaternion.AngleAxis(-30.0f*pendulum+60.0f,Vector3.right);rLowerLeg.localRotation=Quaternion.AngleAxis(30.0f*pendulum+60.0f,Vector3.right);// 腰にひねりを加えるcHips.localRotation=Quaternion.AngleAxis(10.0f*pendulum,Vector3.up)*Quaternion.AngleAxis(10.0f,Vector3.right);// 胸は腰と反対にひねるcChest.localRotation=Quaternion.AngleAxis(-10.0f*pendulum,Vector3.up);cUpperChest.localRotation=Quaternion.AngleAxis(-20.0f*pendulum,Vector3.up);// 腕を揺らすlUpperArm.localRotation=Quaternion.AngleAxis(60.0f*pendulum+30.0f,Vector3.right)*Quaternion.AngleAxis(70.0f,Vector3.forward);rUpperArm.localRotation=Quaternion.AngleAxis(-60.0f*pendulum+30.0f,Vector3.right)*Quaternion.AngleAxis(-70.0f,Vector3.forward);lLowerArm.localRotation=Quaternion.AngleAxis(-60.0f*pendulum+60.0f,Vector3.up);rLowerArm.localRotation=Quaternion.AngleAxis(-60.0f*pendulum-60.0f,Vector3.up);}}

201912241847a.gif

だんだんそれっぽくなってきました。

ただ、重心が上下しないのはちょっと違和感がありますね。

重心を上下させてみた

重心も上下させてみます。

publicclassPendulumRunning:MonoBehaviour{privateTransformcHips;privateTransformlUpperLeg;privateTransformlLowerLeg;privateTransformrUpperLeg;privateTransformrLowerLeg;privateTransformcSpine;privateTransformcChest;privateTransformcUpperChest;privateTransformlShoulder;privateTransformlUpperArm;privateTransformlLowerArm;privateTransformrShoulder;privateTransformrUpperArm;privateTransformrLowerArm;// 腰の初期位置を保管する変数privateVector3firstHipsPosition;voidStart(){cHips=transform.Find("Root").Find("J_Bip_C_Hips");lUpperLeg=cHips.Find("J_Bip_L_UpperLeg");lLowerLeg=lUpperLeg.Find("J_Bip_L_LowerLeg");rUpperLeg=cHips.Find("J_Bip_R_UpperLeg");rLowerLeg=rUpperLeg.Find("J_Bip_R_LowerLeg");cSpine=cHips.Find("J_Bip_C_Spine");cChest=cSpine.Find("J_Bip_C_Chest");cUpperChest=cChest.Find("J_Bip_C_UpperChest");lShoulder=cUpperChest.Find("J_Bip_L_Shoulder");lUpperArm=lShoulder.Find("J_Bip_L_UpperArm");lLowerArm=lUpperArm.Find("J_Bip_L_LowerArm");rShoulder=cUpperChest.Find("J_Bip_R_Shoulder");rUpperArm=rShoulder.Find("J_Bip_R_UpperArm");rLowerArm=rUpperArm.Find("J_Bip_R_LowerArm");// 腰の初期値を取得するfirstHipsPosition=cHips.localPosition;}voidFixedUpdate(){floatpendulum=(float)Math.Sin(Time.time*Math.PI*3.0f);lUpperLeg.localRotation=Quaternion.AngleAxis(-60.0f*pendulum-20.0f,Vector3.right);rUpperLeg.localRotation=Quaternion.AngleAxis(60.0f*pendulum-20.0f,Vector3.right);lLowerLeg.localRotation=Quaternion.AngleAxis(-30.0f*pendulum+60.0f,Vector3.right);rLowerLeg.localRotation=Quaternion.AngleAxis(30.0f*pendulum+60.0f,Vector3.right);cHips.localRotation=Quaternion.AngleAxis(10.0f*pendulum,Vector3.up)*Quaternion.AngleAxis(10.0f,Vector3.right);cChest.localRotation=Quaternion.AngleAxis(-10.0f*pendulum,Vector3.up);cUpperChest.localRotation=Quaternion.AngleAxis(-20.0f*pendulum,Vector3.up);lUpperArm.localRotation=Quaternion.AngleAxis(60.0f*pendulum+30.0f,Vector3.right)*Quaternion.AngleAxis(70.0f,Vector3.forward);rUpperArm.localRotation=Quaternion.AngleAxis(-60.0f*pendulum+30.0f,Vector3.right)*Quaternion.AngleAxis(-70.0f,Vector3.forward);lLowerArm.localRotation=Quaternion.AngleAxis(-60.0f*pendulum+60.0f,Vector3.up);rLowerArm.localRotation=Quaternion.AngleAxis(-60.0f*pendulum-60.0f,Vector3.up);// 周期が半分の振り子を用意するfloathalfPendulum=(float)Math.Sin(Time.time*Math.PI*3.0f*2.0f);// 腰の位置を上下させるcHips.localPosition=firstHipsPosition+newVector3(0.0f,0.04f*halfPendulum,0.0f);}}

201912241856a.gif

ちょ、ちょっとだけ、マシになったかな?

ゲシュタルト崩壊してきたので、このあたりで止めておきます。

一応、AnimationCurveは使わずにC#だけでアニメーションを作成することができました!

AnimationClipに保存してみる

せっかくだからAnimationClipに保存してみます。

Unityの GameObjectRecorderというAPIを使えば、シーン実行中のアニメーションをAnimationClipに保存できます。

以下のスクリプトを作成し、シーン内のVRMにアタッチしてください。

usingUnityEngine;usingUnityEditor.Animations;publicclassRecordTransformHierarchy:MonoBehaviour{publicAnimationClipclip;privateGameObjectRecorderm_Recorder;voidStart(){m_Recorder=newGameObjectRecorder(gameObject);m_Recorder.BindComponentsOfType<Transform>(gameObject,true);}voidLateUpdate(){if(clip==null){return;}m_Recorder.TakeSnapshot(Time.deltaTime);}voidOnDisable(){if(clip==null){return;}if(m_Recorder.isRecording){m_Recorder.SaveToClip(clip);}}}

適当なフォルダーに空のAnimationClipファイルを作成します。

image.png

ここでは仮に pendulum-runningというファイル名にします。

image.png

これを RecordTransformHierarchyClipに割り当てます。

image.png

これでシーンを実行すれば、AnimationClipに動きが保管されます!

FBX Exporter等を使えば、FBXに変換することもできますね!

さいごに

C#でもAnimationClipを作成することができました!

そのことに、果たして意味があるかはわかりませんが、個人的には Quaternionの勉強をできたのが収穫です。

本記事作成にあたり、以下の記事を参考にさせていただきました。ありがとうございました。


Viewing all articles
Browse latest Browse all 9366

Latest Images

Trending Articles