前回までの記事で、せっかく自分の動きでアバターを動かせるようにしたけど、
大きさがあっていないので、若干の違和感が発生してしまっていました。
ということで、この記事では自己流でサイズを合わせてみました。
いつもの通り、前提環境は以下の通りです。
- Unity Personal 2019.2.16f1
- Windows 10
- Index Controller
- SteamVR が設定済みのシーン
使用するアセットは以下の通りです。
使用した 3D モデルは、以下の 2 種類です。
- 【CC0】オリジナルアバター「シャペル」【VRChat 想定】
- 同梱されている UnityPackage を取り込んで使います。
- オリジナル 3D モデル『キッシュ』
- README 通りに VRChat 用に設定したものを使います。
アバターのサイズを人間に合わせるには、いくつかの手段があります。
私が知っている限りは、アバターのサイズを変えるのが一般的でした。
しかし、私は世界観的に VR 空間内のオブジェクトの大きさ比は維持されて欲しいので、
VR 空間そのものの大きさを変えることにしてみました。
まず初めに、 World
という空の GameObject を設置します。
次に、 SteamVRObjects
という空の GameObject を設置します。
画像のように配置する
設置したら、その中にそれぞれ対応する GameObject を入れていきます。
World
には世界に関連するもの (鏡やアバターなどなど) を、
SteamVRObjects
には SteamVR 関連のものを入れていきます。
今回の場合、最終的には下のような構成になりました。
これで前準備は完了です。
次は、大きさをどのように変えるかを C# Script で組みます。
いくつかの VR ゲームをプレイすると分かるのですが、
ユーザーに身長を選択もしくは入力させることがあります。
これをヒントに、以下の流れで拡大率を決定しました。
- ユーザーの身長を元に、腕の長さを計算する
- VRIK に設定されているアバターの腕を元に、アバターの腕の長さを計算する
- ユーザーの腕の長さをアバターの腕の長さで割る
- その値で
World.transform.localScale
を設定する
個体差はあるものの、人間の形は大体にたようなものなので、
身長さえ分かれば、あとは大体計算で求めることが可能です。
今回、両腕の長さ (実際には手首まで) を 身長 * .78
として算出しました。
これは、標準的な人間の身長に対して、以下の法則がある (らしい) からです。
- 腕を横に伸ばした場合、その長さはほぼ身長と等しい
- 身長の長さに対して、手のひらの長さは大体 11% 程度
- よって、 100 - (11 * 2) = 78%
今回の場合、私の身長は 157cm なので、両腕の長さはだいたい 122cm で計算します。
次に、1 つめのアバターのシャペルちゃんは、両腕の長さが 90cm 程度だったので、
世界の大きさをだいたい 1.38 倍にしてあげると、ちょうど良い感じになります。
それを行っているのが、以下のスクリプトです。
using RootMotion.FinalIK; using UnityEngine; #pragma warning disable 649 namespace SteamVR_Sandbox.Scripts { public class AvatarCalibrator : MonoBehaviour { private const float PlayerHandDistanceByHeight = .78f; // Start is called before the first frame update private void Start() { if (World == null) return; var avatarHandDistance = Vector3.Distance(IK.references.leftHand.position, IK.references.rightHand.position); var playerHandDistance = PlayerHeight * PlayerHandDistanceByHeight; var worldScale = playerHandDistance / avatarHandDistance; World.transform.localScale = Vector3.one * worldScale; } [SerializeField] private GameObject World; [SerializeField] private VRIK IK; [SerializeField] [Tooltip("Player Real Height (m)")] private float PlayerHeight; } }
これを適当な GameObject にくっつけて、 World に先ほど作成した World
を、
IK にはアバターにくっつけている VRIK
を、 PlayerHeight には身長を入れます。
私の場合の設定例
最後に、デバッグモードで起動してあげれば、身長、コントローラーの位置ともに、
ちょうど良い感じになります (若干まだ調整はいりそうですが)。
ということで、ではでは~(╹⌓╹ )