コントローラーから渡されるQuaternionの回転を初期化してからオブジェクトに渡すために頑張った話

Quaternionの回転がわからなすぎて1週間近くが経とうとしていた頃自分で調べるかとなった僕の話です。

Quaternion自体の説明は省略します。
各自で調べてください。

#回転
Quaternionを`gameobject.transform.rotation`に代入することによりオブジェクトの回転ができます。

```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SetQuaternion : MonoBehaviour
{
    [SerializeField]
    private Quaternion p = Quaternion.identity;

    [SerializeField]
    private GameObject _gameObject;

    //ボタン用
    public void RandomQuaternion()
    {
        //ランダムなQuaternionを生成しpに代入
        p = Random.rotation;
    }
    
    void Update()
    {
        _gameObject.transform.rotation = p;
    }
}
```

まずこれで回転ができます。
![Quaternion_1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/fb04b459-ecc3-2a57-4d88-dd0aca9063fb.gif)

#ここから本題
ゲームのコントローラーで6軸の情報を取得しゲーム本編に反映させたい状況があるかと思います。
そのような際コントローラーの情報をそのまま渡すと当然予期しない動きをするのでスクリプト側で一度リセットをかけて上げる必要があります。


#軸の補正(コントローラーのQuaternionの初期位置の設定)
Quaternionに逆数のQuaternionを掛けてあげると初期位置に設定できます。

```C#
    private Quaternion q = Quaternion.identity;

    public void InitializeQuaternion()
    {
        q = Quaternion.Inverse(p);
    }
    void Update()
    {
        _gameObject.transform.rotation = p * q;
    }
```
![Quaternion_2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/a236388a-568d-65ad-ffa6-22c894520534.gif)

#オブジェクトの向きの調整
補正した値に向かせたい向きのQuaternionをかけてあげることで初期化をした状態で向きを変更できます。

```C#
    [SerializeField]
    private Quaternion b = Quaternion.Euler(0,90,0);
    void Update()
    {
        _gameObject.transform.rotation = p * q * b;
    }
```
![Quaternion_3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/eab6e4c3-2be4-cb2e-cbb1-a22f3b8b79d7.gif)

##問題点
このままだとx軸にコントローラーを回転させたがオブジェクトはy軸に回転するというようなことが起きます。
その際は

```C#
        _quaternion = _inputController.RightConQuaternion;
        _rightRot.Set(-_quaternion.x, _quaternion.y, -_quaternion.z, _quaternion.w);
```
のようにQuaternionの成分を反転させてあげることで対応可能です。

#2つのQuaternionの合成
元の状態 x コントローラーの入力 = コントローラーの入力を反映したQuaternion
が作れます。
ここでは例で左からアウトプット、元の状態、コントローラー(を想定したオブジェクト)を作り再現してみます。
このとき動的に動く値はアウトプットとコントローラーのQuaternionのみです。
※リセットがちゃんと動くことを確認するために元の状態のRotationの値を変えています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/190b13d5-a903-aaa1-d94b-c3df222a14c9.png)

```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SetQuaternion : MonoBehaviour
{
    [SerializeField]
    private Quaternion p = Quaternion.identity;
    [SerializeField]
    private Quaternion q = Quaternion.identity;
    [SerializeField]
    private Quaternion b = Quaternion.identity;
    [SerializeField]
    private Quaternion d = Quaternion.identity;
    
    [SerializeField]
    private GameObject _gameObject;
    
    [SerializeField]
    private GameObject _blendGameobjectRotation_a;
    [SerializeField]
    private GameObject _blendGameobjectRotation_b;

    public void RandomQuaternion()
    {
        p = Random.rotation;
    }

    
    public void InitializeQuaternion()
    {
        q = Quaternion.Inverse(p);
        d = Quaternion.Inverse(b);
    }
    void Update()
    {
        p = _blendGameobjectRotation_a.transform.rotation;
        b = _blendGameobjectRotation_b.transform.rotation;

        _gameObject.transform.rotation = p * q;
        _gameObject.transform.rotation *= b * d;
    }
}
```
![Quaternion_4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374827/d4865bd8-8f62-6d6f-9611-d31153d84008.gif)
##だが
ここまで色々書いたが実際は↓のコードでうまく動いてしまいQuaternionなにもわからい状態に陥った。

```C#
        //_inputController.LeftConQuaternionは初期化処理をしてから渡している
        _quaternion = _inputController.LeftConQuaternion;
        //-_quaternion.x,-_quaternion.zはコントローラーからの入力がほしい値ではないため反転している
        _leftRot.Set(-_quaternion.x, _quaternion.y, -_quaternion.z, _quaternion.w);
        leftHand.localRotation = _leftQuaternionCorrectionValue * _leftRot;
```