Unity中屏幕空间、窗口空间、显示器空间的区别及坐标转换方案咨询
Unity 屏幕空间转显示器空间实现方案
Unity默认的屏幕空间以应用窗口左下角为(0,0),要转换为全局显示器坐标,只需要叠加应用窗口在显示器上的全局位置偏移,同时适配系统DPI缩放即可。多显示器场景下只需额外获取窗口所属显示器的坐标基准即可适配。
Windows 平台可靠实现
该方案直接调用Win32原生API,兼容性覆盖Win10/Win11全版本,支持多显示器场景:
using System; using System.Runtime.InteropServices; using UnityEngine; public static class ScreenToMonitorConverter { // Win32 API 定义 [StructLayout(LayoutKind.Sequential)] private struct RECT { public int left; public int top; public int right; public int bottom; } [DllImport("user32.dll")] private static extern IntPtr GetActiveWindow(); [DllImport("user32.dll")] private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); [DllImport("user32.dll")] private static extern uint GetDpiForWindow(IntPtr hWnd); /// <summary> /// 输入Unity屏幕空间坐标,返回全局显示器空间坐标(左上角为(0,0)) /// </summary> /// <param name="unityScreenPos">Unity屏幕空间坐标,Y轴向上</param> /// <returns>全局显示器坐标,Y轴向下</returns> public static Vector2 ConvertToMonitorSpace(Vector2 unityScreenPos) { IntPtr windowHandle = GetActiveWindow(); GetWindowRect(windowHandle, out RECT windowRect); uint dpi = GetDpiForWindow(windowHandle); // 计算DPI缩放系数,默认96DPI为100%缩放 float dpiScale = dpi / 96f; // Win32窗口bottom为左下角Y坐标 int windowBottomY = windowRect.bottom; int windowLeftX = windowRect.left; // 叠加偏移,适配DPI float monitorX = windowLeftX + unityScreenPos.x * dpiScale; // Unity屏幕坐标Y向上,Win32显示器坐标Y向下,做翻转计算 float monitorY = windowBottomY - unityScreenPos.y * dpiScale; return new Vector2(monitorX, monitorY); } }
- 如果需要显示器坐标以左下角为基准,只需将返回值的Y坐标替换为
当前显示器总高度 - monitorY即可。 - 多显示器场景下,返回的坐标是跨所有显示器的全局坐标,比如副显示器在主显示器右侧,那么副显示器的X坐标起始值等于主显示器的宽度。
跨平台适配思路
如果需要兼容macOS、Linux系统,逻辑和Windows完全一致,只需替换为对应平台的原生API调用即可:
- macOS:调用Cocoa框架的
NSWindow相关接口,获取当前应用窗口的全局frame、系统缩放系数,做坐标偏移计算。 - Linux:调用X11或Wayland协议的对应接口,获取窗口位置和DPI参数后完成转换。
注意事项
- 全屏模式下应用窗口会铺满对应显示器,可直接用
Display.activeDisplay.bounds参数简化计算,无需调用原生API。 - 若输入坐标是3D世界空间的UI坐标,需先调用对应相机的
Camera.WorldToScreenPoint()方法转换为Unity屏幕空间坐标,再传入转换函数。 - 缩放系数适配要以窗口所属显示器的DPI为准,不要用系统全局DPI,避免多显示器不同缩放比例时计算错误。
内容的提问来源于stack exchange,提问作者FunnerSoft
相关产品推荐
相关产品推荐

