うにてぃブログ

主にUnityとC#に関する記事を書いていきます

【Unity】カメラの Rect を RectTransform に合わせる

UI 上に 3D モデルを出したい際には RenderTexture を利用したりするが、
メモリを食ってしまったり、汚かったりする

その場合、UI 上に映るように 3D モデル を別カメラで写してやることがある

この際に UI の位置が変わるたびに、カメラの Rect を調整するのは面倒になる

それ用に RectTransform の Rect に合わせて カメラ の Rect を調整できるような仕組みを作りました

一部コードは以前書いた記事からそのまま持ってきています

コード

using UnityEngine;
 
public static class RectTransformExtension
{
    private static readonly Vector3[] _corners = new Vector3[4];
 
    /// <summary>
    /// Rect にカメラをあわせる
    /// </summary>
    public static void FitCamera(this RectTransform self, Camera targetCamera)
    {
        var screenRect = self.GetScreenRect();
        var x = Mathf.InverseLerp(0, Screen.width, screenRect.x);
        var x2 = Mathf.InverseLerp(0, Screen.width, screenRect.x + screenRect.width);
 
        var y = Mathf.InverseLerp(0, Screen.height, screenRect.y);
        var y2 = Mathf.InverseLerp(0, Screen.height, screenRect.y + screenRect.height);
 
        targetCamera.rect = new Rect(x, y, x2 - x, y2 - y);
    }
 
    public static Rect GetScreenRect(this RectTransform self)
    {
        var canvas = self.GetComponentInParent<Canvas>();
        return self.GetScreenRect(canvas.worldCamera);
    }
 
    public static Rect GetScreenRect(this RectTransform self, Camera camera)
    {
        self.GetWorldCorners(_corners);
        if (camera != null)
        {
            _corners[0] = RectTransformUtility.WorldToScreenPoint(camera, _corners[0]);
            _corners[2] = RectTransformUtility.WorldToScreenPoint(camera, _corners[2]);
        }
 
        var rect = new Rect
        {
            x = _corners[0].x,
            y = _corners[0].y
        };
        rect.width = _corners[2].x - rect.x;
        rect.height = _corners[2].y - rect.y;
        return rect;
    }
}

サンプル

画面上部の Rect にカメラを合わせると

f:id:hacchi_man:20201205031145p:plain:h300

このようになる

f:id:hacchi_man:20201205031208p:plain:h300

using UnityEngine;
 
public class SampleMonoBehaviour : MonoBehaviour
{
    [SerializeField]
    private RectTransform _rect;
    [SerializeField]
    private Camera _camera;
 
    private void Start()
    {
        _rect.FitCamera(_camera);
    }
}