2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

STYLYAdvent Calendar 2024

Day 5

【Unity】モバイル端末の横持検知をジャイロで行う

Posted at

背景

SceneSemanticAPIというARCoreの機能を利用する際に、端末の横持ちを検知する必要があり、調査しました。

関連リンク:【Unity】SceneSemanticAPIを使ってオクルージョン処理を実現する

結論

横持ちを厳密に検知することはUnityのAPIでは不可能なのではないか?という仮説を立てて調査したところ、予想通り不可能でした。(もし良い方法ご存知であればコメントで教えてください)

そこでジャイロによる横持ち検知を用いるという結論に至りました。

調査した内容

調べると色々と横持ちに関する情報が出てきます。主に以下の3つの手法が候補に挙がりました。

  • Input.deviceOrientation
  • Screen.orientaion
  • Screen.width / heght による検知

Input.deviceOrientation

最初にたどり着いたAPIで、端末の向きを検知するために存在しているものです。

参考リンク:Input.deviceOrientation

ただ、 Android、iOS共に端末の回転設定をOSレベルで設定することができるので、この機能とコンフリクトします。具体的には、端末の回転をOSでロックしているとInput.deviceOrientationは反応しません。


Screen.orientaion

次にPlayerSettingsに存在する設定値でもある、Screen.orientaionを調べました。
この値は端末の向きに応じて変化するものではなく、端末の回転を制限するための値を持っているだけで判定には使えませんでした。

参考リンク:Screen.orientaion


Screen.width / heght

画面の縦幅と横幅が画面の向きに応じて変わることを利用する手法です。
この方法もダメで、以下条件の時にしか値が変化しませんでした。

  • ネイティブの画面の回転設定がAutoかつ、Screen.orientaionがAutoRotationである

サンプルコード

以上の理由からジャイロによる物理的な検知を独自実装しました。以下がサンプルです。

using UnityEngine;

public class CheckOrientation : MonoBehaviour
{
    [SerializeField] private GameObject _warningMessage;

    private void Awake()
    {
        Input.gyro.enabled = true;
    }

    private void Update()
    {
        _warningMessage.SetActive(IsLandscape());
    }

    private bool IsLandscape()
    {
        bool isLandscape;

        if (Application.isEditor)
        {
            isLandscape = Screen.width > Screen.height;
        }
        else
        {
            // Z軸方向だけの判定だと、縦持ちの状態でカメラを上下に傾けた場合に横持ちと判定されるため、X軸方向も判定に含める。
            var gyro = GetCameraGyroEuler(Input.gyro.attitude);
            var landScapeThresholdL = (gyro.z > 45 && gyro.z < 135) && (gyro.x < 45 || gyro.x > 315);
            var landScapeThresholdR = (gyro.z > 225 && gyro.z < 315) && (gyro.x < 45 || gyro.x > 315);
            isLandscape = landScapeThresholdL || landScapeThresholdR;
        }

        return isLandscape;
    }

    /// <summary>
    /// カメラのジャイロを取得する。
    /// カメラの正面方向をZ軸とし、Unityの座標系に合わせた変換を行なった上でオイラー角を返す。
    /// </summary>
    private Vector3 GetCameraGyroEuler(Quaternion gyro)
    {
        var gyroAsUnity = new Quaternion(gyro.x, gyro.y, -gyro.z, -gyro.w);
        var calculatedRotation = Quaternion.Euler(90f, 0f, 0f) * gyroAsUnity;
        return calculatedRotation.eulerAngles;
    }
}

デモ

横持ちを検知して警告が出るようになりました。
SceneSemanticBugFix.gif

参考リンク

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?