Unityでカメラが平行投影の場合にScreenToWorldPointがズレる

初めに

タイトルの通りの話。もっと良い方法があるはずだけど、とりあえず残します。

内容

誤差の理由は、スクリーン座標はピクセルなのでピクセルの隙間がある為との事。 じゃあどうするかだが補正する事にした。

補正値の計算

  1. カメラを原点上空に移動
  2. Camera.ScreenToWorldPoint をスクリーン中心(new Vector2(Screen.width * 0.5f, Screen.height * 0.5f)) で実行
  3. 結果を補正値として保存
  4. カメラ位置を戻す

※ カメラは回転Xを90度にして真下を見ているとする。

※ スクリーンサイズや Camera.orthographicSize が変わる度に計算し直す。

後は Camera.ScreenToWorldPoint を実行する度に補正値を引く。 それでも誤差は残るので確認はする事。許容出来ないなら透視投影にする。

ところで透視投影だと誤差が少ない理由は、カメラからレイを飛ばして計算する関係かららしいが理解出来ていない。

サンプルコード


using UnityEngine;
using System;

public class MyCameraController : MonoBehaviour
{
    Camera cameraP;
    Vector3 worldDelta;
    float prevOrthographicSize = 0f;
    float prevScreenWidth = 0f;
    float prevScreenHeight = 0f;

    void Start()
    {
        cameraP = GetComponent<Camera>();
        UpdateWorldDelta();
    }

    public Vector3 ScreenToWorld(Vector2 screenPos)
    {
        UpdateWorldDelta();
        return cameraP.ScreenToWorldPoint(screenPos) - worldDelta;
    }

    public Vector2 WorldToScreen(Vector3 worldPos)
    {
        UpdateWorldDelta();
        return cameraP.WorldToScreenPoint(worldPos + worldDelta);
    }

    void UpdateWorldDelta()
    {
        if (Mathf.Approximately(prevOrthographicSize, cameraP.orthographicSize) &&
            Mathf.Approximately(prevScreenWidth, Screen.width) &&
            Mathf.Approximately(prevScreenHeight, Screen.height)) return;
        
        prevOrthographicSize = cameraP.orthographicSize;
        prevScreenWidth = Screen.width;
        prevScreenHeight = Screen.height;

        var prevPosition = transform.position;
        try
        {
            transform.position = new Vector3(0f, transform.position.y, 0f);
            worldDelta = cameraP.ScreenToWorldPoint(new Vector2(Screen.width * 0.5f, Screen.height * 0.5f));
        }
        finally
        {
            transform.position = prevPosition;
        }
    }
}

top

その他の投稿
20250712-01 Unity既存プロジェクトにURP追加
20250320-01 Unity のナビゲーションシステム 追記
20241013-01 Google Play で開発者情報が公開される件
20240824-01 Unity UI Toolkit カスタムコントロールサンプル
20240720-01 Unity NavMesh サンプル
20240529-02 Unity ECS の Android ビルドでエラー
20240529-01 Unity ECS で、Prefab を使用した場合に Android ビルドでエラー
20240505-01 Unity ECS で動的に親子関係を作る
20240211-01 Unity Android カスタムアクティビティの作り方
20231216-01 Unity のナビゲーションシステム