LoginSignup
5
6

More than 5 years have passed since last update.

[Unity] 画面を回転したときに見た目の大きさが変わらないように fov を調整する

Posted at

これはなに

Unity の FieldOfView は垂直方向の視野です。
よって、 ScreenOrientation.AutoRotation などに対応する場合、 Landscape にしたとき対象物が小さく見えます。

no-fix.png

iPhone 4 Tall (640x940) / Wide (940x640)

これが、同じ大きさに見えるように、 FieldOfView を調整するスクリプトを書きました。

fixed.png

スクリプト

Camera と同じ GameObject に挿してください。

毎フレーム更新しちゃう版

FixFieldOfViewOrientation.cs
using UnityEngine;

[RequireComponent(typeof(Camera)), ExecuteInEditMode]
public class FixFieldOfViewOrientation : MonoBehaviour
{
    [SerializeField, HideInInspector] private Camera _camera;
    [Range(1, 179)] public float fieldOfView;

    private bool IsLandscape => _camera.aspect > 1;

    void Update()
    {
        _camera.fieldOfView = FixedFieldOfView(fieldOfView, _camera.aspect, IsLandscape);
    }

    private static float FixedFieldOfView(float fieldOfView, float aspect, bool isLandscape)
    {
        if (isLandscape) return fieldOfView / aspect;
        return fieldOfView;
    }

    void OnValidate()
    {
        _camera = GetComponent<Camera>();
    }
}

  • EditMode で動く
  • Camera.fieldOfView set でなにをやってるかわからないので、毎フレーム呼んで大丈夫かがほんの少しだけ不安

Camera.fieldOfView を無駄に更新しない版

FixFieldOfViewOrientation.cs
using UniRx;
using UnityEngine;

[RequireComponent(typeof(Camera))]
public class FixFieldOfViewOrientation : MonoBehaviour
{
    [SerializeField, HideInInspector] private Camera _camera;
    [Range(1, 179)] public float fieldOfView;

    private bool IsLandscape => _camera.aspect > 1;

    void Start()
    {
        Observable.EveryUpdate()
            .Select(_ => FixedFieldOfView(fieldOfView, _camera.aspect, IsLandscape))
            .DistinctUntilChanged()
            .Subscribe(x => _camera.fieldOfView = x)
            .AddTo(this);
    }

    private static float FixedFieldOfView(float fieldOfView, float aspect, bool isLandscape)
    {
        if (isLandscape) return fieldOfView / aspect;
        return fieldOfView;
    }

    void OnValidate()
    {
        _camera = GetComponent<Camera>();
        _camera.fieldOfView = FixedFieldOfView(fieldOfView, _camera.aspect, IsLandscape);
    }
}
  • EditMode で画面サイズ変えても反映されない
    • ほしければ、 Rx 使わないで普通に Update で前フレームとの比較書けばいいと思う
  • Camera.fieldOfView set を無駄に叩かない

補足など

Camera は sealed class なので継承で解決できません。
今回のケースに限っては継承したほうがエレガントに解決できそうな気もしましたが、いずれにせよ、です。
外部のスクリプトから変更する場合など、こちらのコンポネントを経由するように注意する必要があります。
Camera.fieldOfView を自分が更新したのか、外部から更新されたのかをがんばって判別してゴニョゴニョするほどではないかなと思ってやっていません。

そもそも Camera.fieldOfView set に関しては、一応気にしてみましたが、恐らく問題ないと思うので、基本的には上を使うで良いと思います。たぶん。

ちなみに uGUI は、 Canvas Scaler を用いて類似の問題を解決できます。
Unity - マニュアル: 複数の解像度のための UI 設計

それでは、レッツ複数解像度対応!!

5
6
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
5
6