实现世界坐标的原理是: 世界坐标和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;
}
}

---------------------

最新文章

  1. 设置NotePad++设置"不打开上次关闭的文件"
  2. Android学习五:Content Provider 使用
  3. 关于viewport的研究
  4. C Primer Plus(第五版)11
  5. 用cudamat做矩阵运算的GPU加速
  6. windows服务控制类
  7. 强大DevExpress,Winform LookUpEdit 实现多列查询 gridview弹出下拉选择 z
  8. 源码篇——Handler消息机制
  9. Percona Xtradb Cluster的设计与实现
  10. 01: Django基础篇
  11. UVA11374_Airport Express
  12. 控制系统音量,自己定义MPVolumeView
  13. 7-8 List Leaves(25 分)
  14. django drf安装和doc生成
  15. Markdown语法简编
  16. python中浅拷贝和深度拷贝的区别
  17. bash: hadoop:command not found
  18. pdo 预处理
  19. Oracle RAC集群删除节点
  20. hdu 1846 Brave Game(bash)

热门文章

  1. How to Use DHCP Relay over LAN? - DrayTek Corp
  2. 生成sde
  3. 使用DBMS_REDEFINITION在线切换普通表到分区表
  4. swift UI专项训练39 用Swift实现摇一摇功能
  5. C语言控制台窗体图形界面编程(总结)
  6. HDU 5446 CRT+Lucas+快速乘
  7. 【XSY3209】RGB Sequence
  8. curl 采集的时候遇到60报错怎么办?
  9. ACM_整数反转
  10. 题解报告:hdu 2066 一个人的旅行