ことはじめ

VRなどで、3Dの空間(World Space)でCanvasを使いたくなることはよくあると思います。

文字のサイズやSpriteなどはピクセル単位での指定となるため、実際の位置とピクセル空間での位置を二重で考えなければならず、頭がこんがらがります。

f:id:notargs:20170511201447g:plain

「なんで3Dするのにピクセルのことを一々考えなければいけないんや!」と思ったので、楽するためのエディタ拡張を作ってみました。

使用例

f:id:notargs:20170511201958g:plain

  1. 楽したいCanvas(RenderModeをWorld Spaceに変更済み)にWorld Space Canvas Scalerを追加します。
  2. Pixel Per Unit(1メートルあたりのピクセル数)を好みの数に設定します。
  3. Sizeを好きなサイズに設定します。
  4. 完成

コード

WorldSpaceCanvasScaler.cs

/*
WorldSpaceCanvasScaler

Copyright (c) 2017 Yutaka Sato

This software is released under the MIT License.
http://opensource.org/licenses/mit-license.php
*/

using UnityEngine;

public interface IWorldSpaceCanvasScaler
{
    float PixelPerUnit { get; set; }
    Vector2 Size { get; set; }
}

IWorldSpaceCanvasScalerInspector.cs(Editor)

/*
WorldSpaceCanvasScaler

Copyright (c) 2017 Yutaka Sato

This software is released under the MIT License.
http://opensource.org/licenses/mit-license.php
*/

using UnityEditor;

[CustomEditor(typeof(WorldSpaceCanvasScaler))]
public class WorldSpaceCanvasScalerInspector : Editor
{
    WorldSpaceCanvasScaler canvasScaler;

    void OnEnable()
    {
        canvasScaler = (WorldSpaceCanvasScaler)target;
    }

    public override void OnInspectorGUI()
    {
        EditorGUI.BeginChangeCheck();

        var pixelPerUnit = EditorGUILayout.FloatField("Pixel Per Unit", canvasScaler.PixelPerUnit);
        var size = EditorGUILayout.Vector2Field("Size", canvasScaler.Size);

        if (!EditorGUI.EndChangeCheck()) return;

        Undo.RecordObject(canvasScaler, "Change world space canvas scaler");

        canvasScaler.PixelPerUnit = pixelPerUnit;
        canvasScaler.Size = size;
    }
}

WorldSpaceCanvasScaler.cs

/*
WorldSpaceCanvasScaler

Copyright (c) 2017 Yutaka Sato

This software is released under the MIT License.
http://opensource.org/licenses/mit-license.php
*/

using UnityEngine;

[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
public class WorldSpaceCanvasScaler : MonoBehaviour, IWorldSpaceCanvasScaler
{
    RectTransform rectTransform;

    void Awake()
    {
        rectTransform = GetComponent<RectTransform>();
    }

    public float PixelPerUnit
    {
        get { return 1 / rectTransform.localScale.x; }
        set { rectTransform.localScale = Vector3.one / Mathf.Max(value, float.Epsilon); }
    }

    public Vector2 Size
    {
        get { return rectTransform.sizeDelta / PixelPerUnit; }
        set { rectTransform.sizeDelta = value * PixelPerUnit; }
    }
}

ご活用ください。

© Unity Technologies Japan/UCL