實現世界坐標的原理是: 世界坐標和UGUI的坐標分屬兩個坐標系,他們之間是無法進行轉換的,需要通過屏幕坐標系來進行轉換(因為屏幕坐標是固定的),即先將游戲場景中的世界坐標通過游戲場景Camera轉化為屏幕坐標(Camera.main.WorldToScreenPoint(point)),再通過UICamera將該屏幕坐標轉換為UI本地坐標(RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas, screenPoint, uiCamera, out localPoint))
疑問?
那么初學的小白們(博主也是小白)可能會疑惑UGUI為什么會有UICamera,因為UGUI的Canvas的RenderMode有三種模式,一般默認為Overlay(全覆蓋),另一種為Camera。
當RenderMode為Overlay時,UI坐標系和屏幕坐標系是一樣的,則不需要通過UICamera來轉換,直接將第一步得到的屏幕坐標賦值給Hud的localPosition就可以了。
一般游戲中要實現3D物體在在UI之上時,就不能用畫布全覆蓋模式,而是要再創建一個Camera來單獨渲染UI,Clear Flags為Depth Only。當RenderMode為Camera時,則需要以上兩步來得到本地坐標。
注意:最后賦值給Hud的本地坐標是localPosition而不是position
拓展:世界坐標、本地坐標、視口坐標,各種坐標系要理解清楚,在學習shader時也是有用的
以下是實現hud跟隨3D物體的腳本,只是測試用,不是開發中的代碼,腳本掛在任意游戲物體上 demo下載
using UnityEngine;
public class SceneFollowUI : MonoBehaviour
{
public RectTransform hud; //Hud
public RectTransform canvas;//UI的父節點
public Transform parent; //跟隨的3D物體
public Camera uiCamera; //UICamera
Vector3 offset; //hud偏移量
Vector3 cachePoint;
float originalDistance;
float factor = 1;
bool visiable = true;
void Start()
{
offset = hud.localPosition - WorldPointToUILocalPoint(parent.position);
cachePoint = parent.position;
originalDistance = GetCameraHudRootDistance();
UpdateVisible();
}
void LateUpdate()
{
if (cachePoint != parent.position)
{
float curDistance = GetCameraHudRootDistance();
factor = originalDistance / curDistance;
UpdatePosition(); //更新Hud位置
UpdateScale(); //更新Hud的大小
UpdateVisible(); //更新Hud是否可見,根據需求設置:factor或者根據和相機距離設置,一定范圍內可見,相機視野范圍內可見 等等
}
}
private void UpdateVisible()
{
}
private void UpdatePosition()
{
hud.localPosition = WorldPointToUILocalPoint(parent.position) + offset * factor;
cachePoint = parent.position;
}
private void UpdateScale()
{
hud.localScale = Vector3.one * factor;
}
private float GetCameraHudRootDistance(http://www.my516.com)
{
return Vector3.Distance(Camera.main.transform.position, parent.position);
}
private Vector3 WorldPointToUILocalPoint(Vector3 point)
{
Vector3 screenPoint = Camera.main.WorldToScreenPoint(point);
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas, screenPoint, uiCamera, out localPoint);
return localPoint;
}
}
---------------------