MRが楽しい

MRやVRについて学習したことを書き残す

漫画によくある吹き出しを現実空間に表示する

おいかけっこアプリの追加機能枠です。
以前紹介したキャラクタの吹き出しについて新たに動画を撮ったので紹介します。
f:id:bluebirdofoz:20170705005635g:plain
少し長めのGIFファイルなので、重かったらすいません。

一見、特に難しい動きをしていないように見えますが、吹き出しは以下の条件を満たすように動いています。
・キャラクタの右脇に位置付けされること。
・カメラに対して正面を向き続けること。
・キャラクタと重ならないこと。
・カメラに一定以上の距離より近づかないこと。
・カメラとキャラクタが空間座標を自由に動き回っても上記の条件を満たし続けること。

漫画的表現を現実空間で表現すると言う事の難しさを思い知ったUI実装でした。
今回は「それっぽい」UIを作りたいという理由でこういったものを作ってみましたが、MRに漫画的表現を取り込むというのは面白い取り組みかもしれません。

以下にコードを記載します。試行錯誤の末に作ったので、まだまだ詰める余地はあると思います。
・CanvasManager.cs

        /// <summary>
        /// キャンバスの方向補正
        /// (カメラ方向に正面を向ける)
        /// </summary>
        private void CanvasRotationToCamera()
        {
            // カメラに対して正面を向ける.
            p_TargetCharactorCanvas.transform.parent.rotation = CatchAndRun.Util.UtilCamera.RotationToMainCameraAxisY(p_TargetCharactorCanvas.transform.position, p_CanvasDefaultRotation);
        }

        /// <summary>
        /// キャンバスの位置補正
        /// (カメラ方向に正面を向ける)
        /// </summary>
        /// <param name="nowPos">現在座標</param>
        /// <param name="prevPos">前回座標</param>
        private void CanvasPositionToCharactor(Vector3 nowPos, Vector3 prevPos)
        {
            // キャンバスの移動はディレイをかける
            Vector3 delay = nowPos - prevPos;
            Vector3 delayPos = delay;
            p_TargetCharactorCanvas.transform.parent.localPosition = delayPos;

            // カメラが一定以上の距離に近づいた場合は距離を取る
            Vector3 targetPosition = Camera.main.transform.position;
            targetPosition.y = p_TargetCharactorCanvas.transform.parent.position.y;
            float cameraDistance = Vector3.Distance(p_TargetCharactorCanvas.transform.parent.position, targetPosition);
            if (cameraDistance < p_MinCameraDistance)
            {
                float needDistance = p_MinCameraDistance - cameraDistance;
                Vector3 coefficient = new Vector3(1.0f, 0.0f, 1.0f);
                Vector3 point = CatchAndRun.Util.UtilCamera.PositionAwayMainCamera(this.transform.position, coefficient, needDistance);
                p_TargetCharactorCanvas.transform.parent.position = this.transform.position + point;
            }
        }

・UtilCamera.cs

        /// <summary>
        /// カメラ逆方向のポイント算出
        /// </summary>
        /// <param name="objectPosition">相対オブジェクト位置</param>
        /// <param name="vectorCoefficient">ベクトル係数</param>
        /// <param name="distance">距離</param>
        /// <returns>ポジション</returns>
        static public Vector3 PositionAwayMainCamera(Vector3 objectPosition, Vector3 vectorCoefficient, float distance)
        {
            // オブジェクトとカメラ位置の取得
            Vector3 cameraPosition = new Vector3(
                Camera.main.transform.position.x * vectorCoefficient.x,
                Camera.main.transform.position.y * vectorCoefficient.y,
                Camera.main.transform.position.z * vectorCoefficient.z
            );
            Vector3 targetPosition = new Vector3(
                objectPosition.x * vectorCoefficient.x,
                objectPosition.y * vectorCoefficient.y,
                objectPosition.z * vectorCoefficient.z
            );

            // オブジェクトとカメラの点差と距離を取得(カメラ逆方向)
            Vector3 pointDifference = targetPosition - cameraPosition;
            float pointDistance = Vector3.Distance(targetPosition, cameraPosition);

            // 距離1m辺りの点差を取得
            Vector3 pointCoefficient = pointDifference / pointDistance;

            // 要求位置のポイントを算出
            Vector3 postion = pointCoefficient * distance;
            return postion;
        }

        /// <summary>
        /// カメラ方向のルーチン算出(Y軸回転)
        /// </summary>
        /// <param name="objectPosition">相対オブジェクト位置</param>
        /// <param name="objectPosition">デフォルト回転方向</param>
        static public Quaternion RotationToMainCameraAxisY(Vector3 objectPosition, Quaternion defaultQuaternion)
        {
            // カメラに対して正面を向ける
            Vector3 directionToTarget = Camera.main.transform.position - objectPosition;
            directionToTarget.y = -1 * objectPosition.y;
            Quaternion rotation = Quaternion.LookRotation(-directionToTarget) * defaultQuaternion;
            return rotation;
        }

キャンバスとキャラクタを同じゲームオブジェクトに含ませて、ローカル座標と回転、ルート座標と回転の操作を駆使しているため、このコードだけ移植すれば動くというものではないのでご注意ください。