73828


Unity2020でスケートボードゲームの開発をしています。  
スケートボード用のオブジェクトの板モデルを、斜面などの床の法線に合わせて回転させる必要があるのですが、上手くいきません。  
ヒエラルキーの構造は以下です。  
移動や回転を親のPlayerで行い、その子としてModelとBoardオブジェクトがあります。  
床に合わせて回転させる必要があるのがBoardオブジェクトです。  
[![ヒエラルキーの構造](https://i.stack.imgur.com/nFhkR.png)](https://i.stack.imgur.com/nFhkR.png)

トリックや移動などを行う際、Playerを回転させることで全体の回転を行います。  
PlayerのRotationの値が全て0の時は上手く行くのですが、少しでも回転しているとBoardの回転がうまくいかなくなります。

以下は実際に使用しているスクリプトです。  
インスペクターで_ReferenceTargetにPlayerを、_RotateTargetにBoardを設定しています。

[code]

    public class RotateObjectFromHitObject : MonoBehaviour
    {
        [SerializeField] GameObject _ReferenceTarget;
        [SerializeField] GameObject _RotateTarget;
        void OnCollisionEnter(Collision collision)
        {
            if (collision.gameObject.tag != "Field") return;
            var lhs = _ReferenceTarget.transform.forward;
            var rhs = _ReferenceTarget.transform.right;
            var cross = Vector3.Cross(lhs, rhs);
            foreach (var contact in collision.contacts)
            {
                _RotateTarget.transform.localRotation = Quaternion.FromToRotation(cross, contact.normal);
            }
        }
    }
    
[/code]

このコードですと、以下の画像のようにPlayerのRotationが全て０の場合うまくいきます。  
[![PlayerのRotationが全て０](https://i.stack.imgur.com/Vii1S.png)](https://i.stack.imgur.com/Vii1S.png)

しかし以下画像のようにPlayerのYを90度動かすと、以下画像のように変な挙動になってしまいます。

[![PlayerのYを90度動かす](https://i.stack.imgur.com/Vp5IA.png)](https://i.stack.imgur.com/Vp5IA.png)

Playerの回転の状態がどのような状態でも、Boardを床の斜面に合わせるように回転させるには、どうすれば良いでしょうか。


CC BY-SA 4.0
2021-02-03T10:19:26.577
73775
2021-02-06T06:56:42.690
22827
question
unity3d
床の法線に合わせて板を回転させる方法


回転を適用する順番の問題です。この階層構造ですとローカルの回転で制御するのは難しいので、ワールドでの回転として管理したほうが良いと思います。

[code]

    /// <summary>
    /// 接地面での回転を設定する
    /// </summary>
    /// <param name="rotateTarget">このオブジェクト回転を設定する</param>
    /// <param name="referenceTarget">このオブジェクトのy軸回転を使用する</param>
    /// <param name="normal">接地面の法線</param>
    private void SetGroundRotate(GameObject rotateTarget, GameObject referenceTarget, Vector3 normal)
    {
        // リファレンスのY軸回転のみを取得
        var defaultRotation = Quaternion.Euler(0.0f, referenceTarget.transform.eulerAngles.y, 0.0f);
        // 接地の傾き回転を取得
        var groundRotation = Quaternion.FromToRotation(Vector3.up, normal); // 常に真上を基準
        // ワールドでの回転として設定
        rotateTarget.transform.rotation = groundRotation * defaultRotation;
    }
    
[/code]

実際に使用する際は、常にプレイヤーの回転の影響を受けるため、スケートボードの Update() 等で回転を管理することになると思います。


CC BY-SA 4.0
2021-02-06T06:42:20.827
73828
2021-02-06T06:56:42.690
2021-02-06T06:56:42.690
14817
14817
73775
answer