youtubeじゃ見ずらいので、こっちのほうが良かったですね。 pic.twitter.com/qDTICPuzNl
— フラッグさん (@pixelflag) 2019年2月16日
こちらのパペットみたいなキャラクター制御の話です。シンプルなのでまとめとこうと思います。
ツールはUnity2017.3を使用しています。
ドット絵を使用していますが、普通の2Dイラストでも同じになります。
ドット絵に関する初期設定はこちらを参照してください。
https://qiita.com/pixelflag/items/ad817bdd64931e084a46
Unity上ではこういう構成になっています。
分解するとこんな感じです。
各Rootは空のgameObjectで、座標制御に使用します。その他はSpriteRendererだけが付いたシンプルなGameObjectです。
顔パーツは3パーツで構成されてますが、扱いにあまり差が無いので説明は省きます。
ポイントになるのが腕パーツの動きの制御。これだけです。
手のルートが固定位置に配置され、そのから半径(HandDistance)の範囲だけHandが動くようになっています。
入力は何でもいいのですが、今回はPS4のコントローラを使用しました。アナログ入力のほうが面白い動きになりますしね。
コントローラのアナログスティックがx,yそれぞれ、-1.0~1.0の数値を返してくれるので、それをスケールしてHandの座標に反映するだけです。そのときHandをRootの子階層にいれることで、0位置を定義するというわけです。
片手だけならマウスの座標でなんとかしてもいいと思います。
コントローラーの使用はProject Settings > inputの初期設定が必要なので別途お手持ちのデバイスに合わせて設定してください。
コードはこんな感じ。
文字がやたら多いですがやってることはシンプルです。(全部gameobject.transform.positionのせいです。)
// 右手
Vector3 right = new Vector3(Input.GetAxis("PsRStickX"), -Input.GetAxis("PsRStickY"), 0);
RHand.transform.localPosition = right * handDistance;
Vector3 rsp = RShoulder.transform.position;
Vector3 rhp = RHand.transform.position;
RWrist.transform.position = ((rhp - rsp) * wristPositionRate) + rsp;
// 左手
Vector3 left = new Vector3(Input.GetAxis("PsLStickX"), -Input.GetAxis("PsLStickY"), 0);
LHand.transform.localPosition = left * handDistance;
Vector3 lsp = LShoulder.transform.position;
Vector3 lhp = LHand.transform.position;
LWrist.transform.position = ((lhp - lsp) * wristPositionRate) + lsp;
// 顔
face.transform.localPosition = (right + left) * headPositionRate;
headPhone.transform.localPosition = (right + left) * headPositionRate;
head.transform.localPosition = (right + left) * headPositionRate;
// 体
body.transform.localPosition = (right + left) * bodyPositionRate;
コントローラの入力は右手と左手それぞれにアナログスティックの入力が割り当てられます。
その他のパーツは右手と左手の位置を見て計算されます。
手首(wrist)は、肩(Shoulder)の座標と、手(Hand)の座標の中間に配置されるようにしています。
その時、中間のどの辺の位置に配置するか、wristPositionRateで定義します。今回は90%くらいHandに近い位置に配置しました。
顔は3パーツありますが座標は全部同じ。[order in layer] で、体の前に表示されるものと、後ろに表示されるもの設定だけ差がついています。
右手と左手の動きの差分を、HeadPositionRateでスケールした分の影響を受けるようにしました。今回は1.0fです。(調整して影響無しになりました)
胴も顔と同様に手の動きの影響を受けてbodyPositionRateのスケールで影響を受けます。今回は0.5。半分です。顔より動きが小さくなります。
これで手を動かすと全身が微妙に動くことになり、パペット的な動きなりました。
顔の表情と、手の形の切り替えはシンプルにSpriteRendererのSprite差し替えのみです。
// □
if (Input.GetButtonDown("PsSquare"))
{
face.GetComponent<SpriteRenderer>().sprite = defaultFace;
}
// ×
if (Input.GetButtonDown("PsCross"))
{
face.GetComponent<SpriteRenderer>().sprite = smileFace;
}
// 〇
if (Input.GetButtonDown("PsCircle"))
{
face.GetComponent<SpriteRenderer>().sprite = downFace;
}
// △
if (Input.GetButtonDown("PsTriangle"))
{
if(isGrip)
{
RHand.GetComponent<SpriteRenderer>().sprite = parHand;
isGrip = false;
}
else
{
RHand.GetComponent<SpriteRenderer>().sprite = gripHand;
isGrip = true;
}
}
コントローラーの入力をうけて、差し替えるだけですね。
これであとは、UnityをBuildして実行したものを、コントローラーを握って演技して撮影します。
そして動画編集ソフトで合成して終わりです。
高い機材やソフトが無くてもシンプルな実装でVtuber的な表現ができました。
みなさんもぜひ拡張したりして遊んでみてください。