unity中的各种坐标转换(世界坐标,局部坐标,屏幕坐标,UI坐标,视口坐标)学习
今天学习unity的各种坐标,以及相互转换。
今天学习unity的各种坐标,以及相互转换。
一.认识坐标系
1.世界坐标
世界坐标:顾名思义,就是物体在全局世界空间内的坐标。
获取:transform.position
2.局部坐标
局部坐标:物体相对于父物体的坐标,以父物体为基准。unity的Inspector视图里的坐标就是相对于父物体的坐标,也就是局部坐标。

获取:transform.localPosition
3.屏幕坐标
屏幕坐标:ScreenPoint,以像素为单位的2D坐标,与屏幕分辨率有关,原点在屏幕左下角,即左下角坐标为Vector2(0,0),右上角为Vector2(Screen.width,Screen.height)。
以分辨率为1920*1080来说,屏幕左下角坐标为Vector2(0,0),右上角为Vector2(1920,1080)。
获取:对于3D物体来说,获取屏幕坐标需要将世界坐标转换为屏幕坐标,见坐标转换部分。对于2D的UI来说,Overlay模式下,它本身就不在空间内,它的屏幕坐标就是自己的世界坐标,即transform.position。但如果是带有相机的渲染模式,获取屏幕坐标同样需要将世界坐标转换为屏幕坐标。
4.视口坐标(又叫观察坐标)
视口坐标:ViewportPoint,是归一化坐标,与屏幕分辨率无关,将屏幕的长和宽视为整体1,原点依然是在左下角,坐标为Vector2(0,0),右上角为Vector2(1,1)。
获取:需要将世界坐标转换为视口坐标,见坐标转换部分。
5.UI坐标
UI坐标:原点位置由Canvas或指定UI或父UI的Rect Transform和锚点设置决定,不是固定的屏幕左下角。
获取:对于直系父物体来说,自身的UI坐标是anchoredPosition,可以直接通过RectTransform.anchoredPosition获取,也就是说,anchoredPosition获得的是自己相对直系父物体的UI位置;那对于其他UI,则需要将自己的屏幕坐标转换为相对其他UI的UI坐标,见坐标转换部分。
二.坐标转换
os:终于上代码了~
1.世界坐标与局部坐标
这里只写了位置互相转换,同样的,还有方向和缩放的相互转换,这里就不过多说了
/// <summary>
/// 局部坐标→世界坐标,获取物体的子物体在世界的位置,比如获取机器上某个零件的世界坐标
/// </summary>
///<param name="localPos">零件的相对位置</param>
private void LocalToWorld(Vector3 localPos)
{
Vector3 worldPos = transform.TransformPoint(localPos);
//为什么不直接用transform.position?
//直接用就只能获取到这个零件本身在哪(世界里),而TransformPoint(localPos)可以获取机器身上任何一个特定点在哪(世界里)
Debug.Log("打印零件的世界坐标" + worldPos);
}
/// <summary>
/// 世界坐标→局部坐标,获取世界的某个点在物体的什么位置,比如获取某个路牌在我家的什么位置
/// </summary>
/// <param name="worldPos">路牌的世界位置</param>
private void WorldToLocal(Vector3 worldPos)
{
Vector3 localPos = transform.InverseTransformPoint(worldPos);//是上面的逆运算
//为什么不直接用transform.LocalPosition?
//同理,InverseTransformPoint(worldPos);可以获取任何物体在自己的什么位置;而transform.LocalPosition只能获取自己在父物体的位置
Debug.Log("打印路牌相对于我的局部坐标" + localPos);
}
2.世界坐标与屏幕坐标
/// <summary>
/// 世界 → 屏幕坐标
/// </summary>
/// <param name="worldPos">世界坐标</param>
private void WorldToScreen(Vector3 worldPos)
{
Vector3 screenPos = Camera.main.WorldToScreenPoint(worldPos);
}
/// <summary>
/// 屏幕 → 世界坐标 ,需要深度,深度代表世界坐标的Z值位置,代表物体在3D空间的远近(近大远小)
/// 深度获取:通过射线获取碰撞点深度;通过指定距离;等等
/// </summary>
/// <param name="depth">深度</param>
private void ScreenToWorld(float depth)
{
Vector3 mousePos = Input.mousePosition;
Vector3 worldPos = Camera.main.ScreenToWorldPoint(new Vector3(mousePos.x, mousePos.y, depth));
}
3.世界坐标与视口坐标
/// <summary>
/// 世界 → 视口坐标
/// </summary>
/// <param name="worldPos">世界坐标</param>
private void WorldToView(Vector3 worldPos)
{
Vector3 viewportPos = Camera.main.WorldToViewportPoint(worldPos);
}
/// <summary>
/// 视口 → 世界坐标,需要深度值,深度代表世界坐标的Z值位置,代表物体在3D空间的远近(近大远小)
/// 比如depth=10,代表世界位置的Z方向位置为距离摄像机前10米处
/// </summary>
/// <param name="depth"></param>
private void ViewToWorld(float depth)
{
//例1:获取屏幕中心的世界坐标(摄像机前10米处)
Vector3 centerWorldPos = Camera.main.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, 10f));
//例2:获取屏幕右上角的世界坐标(摄像机前5米处)
Vector3 topRightWorld = Camera.main.ViewportToWorldPoint(new Vector3(1f, 1f, 5f));
}
4.屏幕坐标与视口坐标
/// <summary>
/// 屏幕 → 视口坐标
/// </summary>
/// <param name="worldPos"></param>
private void ScreenToView(Vector3 screenPos)
{
Vector3 viewportPos = Camera.main.ScreenToViewportPoint(screenPos);
}
/// <summary>
/// 视口 → 屏幕坐标
/// </summary>
/// <param name="viewportPos"></param>
private void ViewToScreen(Vector3 viewportPos)
{
Vector3 screenPos = Camera.main.ViewportToScreenPoint(viewportPos);
}
5.屏幕坐标与UI坐标
如果要从世界坐标转UI坐标,也需要先将其转为屏幕坐标,再转为UI坐标;从UI坐标转为世界坐标同理,都要经过屏幕坐标去转换。
/// <summary>
/// 将屏幕坐标转换为相对于谁的UI坐标
/// </summary>
//if里面返回的是bool值,表示是否转换成功,在UI平面内
void ScreenToUI(RectTransform canvasRect,Vector2 screenPos,Camera camera)
{
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(
canvasRect, // 目标RectTransform,相对于谁的UI
screenPos, // 屏幕坐标
camera, // Camera(摄像机渲染模式为Overlay模式时,此值为null)
out Vector2 uiPos //得到的UI坐标
))
{
Debug.Log(uiPos);
}
}
/// <summary>
/// 将UI坐标转为屏幕坐标,Overlay模式的话可以直接用transform.position获取屏幕坐标
/// </summary>
/// <param name="camera">ui相机,</param>
/// <param name="uiPos">UI坐标</param>
void UIToScreen(Camera camera, Vector2 uiPos)
{
transform.GetComponent<RectTransform>().anchoredPosition = uiPos;//这一步必须要有!!!
//1.计算了uiPos(理论坐标)
// 2. 必须把 targetUI 移动到这个位置(本例中目标UI就是自己)
// 3. 然后才能用 targetUI.position 获取实际位置
// 4. 再用 RectTransformUtility.WorldToScreenPoint 转换这个实际位置
Vector3 screenPos = RectTransformUtility.WorldToScreenPoint(camera, transform.position);
Debug.Log("UI坐标转换屏幕坐标:" + screenPos);
}
6.射线投影相关
// 屏幕坐标 → 射线,从屏幕上的一个点向3D世界发射一条射线,用于检测这个"屏幕像素"在3D世界中指向什么物体。
Ray ray = camera.ScreenPointToRay(screenPos);
// 视口坐标 → 射线,与上面不同的是,用归一化坐标发射射线
Ray ray = camera.ViewportPointToRay(viewportPos);
三.小知识
1.什么情况下用到的是屏幕坐标?
获取鼠标/输入位置时,从鼠标位置发出射线检测时(比如点击3D物体),截图等需要直接处理屏幕像素位置时。
2.什么情况用到的是UI坐标?
创建UI时,UI跟随物体时,UI交互检测时,UI拖拽时等。
以上就是全部内容,如果有不对或者改进的地方请速速告诉我,我改,我改/(ㄒoㄒ)/~~
这里是一个专注于游戏开发的社区,我们致力于为广大游戏爱好者提供一个良好的学习和交流平台。我们的专区包含了各大流行引擎的技术博文,涵盖了从入门到进阶的各个阶段,无论你是初学者还是资深开发者,都能在这里找到适合自己的内容。除此之外,我们还会不定期举办游戏开发相关的活动,让大家更好地交流互动。加入我们,一起探索游戏开发的奥秘吧!
更多推荐


所有评论(0)