はじめに
Unityでは、スタンドアロンモードのみマルチディスプレイに対応しています。(対応OS:Windows、Mac、Linux)
Windowsでマルチディスプレイ対応のアプリを作成していたところ、
座標の扱いで何度か混乱してしまったため、書き留めておきたいと思います。
環境
- Windows 10
- Unity 2019.2.19f1
- Visual Studio 2019
スクリーン座標とワールド座標
Unityをさわったことがある方ならご存知だと思いますが、Unityの座標にはスクリーン座標系とワールド座標系が存在します。
スクリーン座標系は画面上の座標で、左下隅が (0, 0)となります。
ワールド座標系はUnityのゲーム空間上の座標で、Scene直下にあるオブジェクトであればInspectorのTransform > Position の値となります。
マウス位置(Input.mousePosition)は画面上のどこかを表すものなので、当然スクリーン座標系となります。
マルチディスプレイの場合のマウス位置は?
マルチディスプレイの場合、Input.mousePositionで取得できる座標は、メインディスプレイ基準の座標となります。
例えば、1920 x 1080のディスプレイ2台を以下のように配置していた場合
座標は以下のようになります。
ワールド座標に変換したい
取得したマウス位置の座標をワールド座標に変換するには、
① 画面ごとのスクリーン座標に変換
② 該当する画面のカメラでワールド座標に変換
の2段階の変換を行う必要があります。
// cameras という変数に、ディスプレイ番号順のカメラが保持されている想定です
private Vector2? ConvertScreenPointToWorld(Vector2 position)
{
// 1. 画面ごとのスクリーン座標に変換
// ※ 各画面の左下隅を(0, 0)とする座標に変換されます
var relativePosition = Display.RelativeMouseAt(position);
// ※ 気持ち悪いですが、z座標にディスプレイ番号がセットされます...
var displayIndex = (int)relativePosition.z;
if (displayIndex >= cameras.Count) return null;
// 2. 該当する画面のカメラでワールド座標に変換
var camera = cameras[displayIndex];
return camera.ScreenToWorldPoint(relativePosition);
}
ちなみに、Unityエディター上では Display.RelativeMouseAt()
は動作しないのでご注意ください。