界面UI跟随相机转动(2D图标始终面向用户)Unity操作记录
一、背景
在unity模型里,我需要对一个建筑楼层模型的地面拆分若干个区域,并向用户指示这些区域,需要做到用户通过鼠标旋转任何角度,指示区域的图标及内的文字信息都始终面向用户。
二、实践过程
(1)在楼层中地面追加Plane
选中指定楼层模型,右键3D对象--->平面 即可创建一个平面,调整位置、大小。我根据需要建立了3个平面,每个平面代表一个测试区

(2)素材准备与导入操作
右键unity项目层级的Img文件夹----->点击 在资源管理器中显示 ---->将所需的素材复制进去

在操作的unity项目层级的Img文件夹里,依次点击每一个刚刚导入的图片,在检查器层级中 纹理类型 --->选择Sprite(2D和UI)---->点击应用

(3)将定位图标拖入模型中并调整位置、大小显示;修改文件名称
在每个plane下面建立一个XX区域标签作为父级对象,用于管理标签的定位图标、区域图标、及文本文字。
直接将项目层级的定位点图标直接拖入XXXX区域标签对象下作为他的子级,修改名称为:定位点,调整位置、大小显示

(4)将区域名称显示框图标拖入模型中并调整位置、大小显示;修改文件名称;建立两个文本对象并设置相应介绍
直接将项目层级的区域名称显示框图标直接拖入XXXX区域标签对象下作为他的子级,修改名称为:区域名称,调整位置、大小显示。

右击区域名称----->3D对象------>文本-TextMeshPro ---->先后建立两个文本框,写入介绍文字,调整位置、大小

注意:Canvas节点的渲染模式设置成 世界空间 :

字体选择能兼容中文显示的字体:

(5)挂载面向用户的脚本
在XXX区域标签这个对象上,挂载AlwaysFaceTargetTool.cs脚本

脚本如下:
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 /// <summary> 5 /// 根据一个角度去计算自身坐标朝向 6 /// 主要作用:实现广告牌效果(Billboard),让物体始终正对摄像机,并且可以根据物体与摄像机的距离动态改变自身的大小 7 /// 通常用于游戏中的角色头顶血条、名字、UI 提示或者 2D 特效贴片,确保无论玩家怎么旋转视角,这些元素始终正对屏幕且大小合适。 8 /// </summary> 9 public class AlwaysFaceTargetTool : MonoBehaviour 10 { 11 public bool ScaleChange = false;// 是否开启“根据距离动态缩放”的功能开关 12 public float RateMin = 1; // 最小缩放倍率 13 public float RateMax = 1; // 最大缩放倍率 14 public float LengthMin = 0; // 最小距离参考值(注意:代码中声明了但实际并未被使用) 15 public float LengthMax = 0; // 最大距离参考值(用于计算当前距离在总距离中的比例)----后续依情况调整 16 public Vector3 InitScale; // 用于保存物体最开始的缩放值(Scale) 17 18 19 // Start is called before the first frame update 20 void Start() 21 { 22 //将物体初始的缩放大小( localScale )记录在 InitScale 中。 23 //这是因为后续如果开启了缩放功能,物体的缩放值会不断变化,我们需要一个“基准值”来乘以缩放倍率,否则会导致物体无限变大或缩小。 24 InitScale = transform.localScale; 25 } 26 27 // Update is called once per frame 28 void Update() 29 { 30 //第一步:计算物体相对于相机的局部坐标 31 //InverseTransformPoint 是一个非常核心的空间转换方法。它把物体当前在游戏世界中的绝对坐标(世界坐标),转换成了 相对于主相机( Camera.main )的局部坐标 32 //转换后, localPosition.z 就代表了物体距离相机的 深度 (即物体在相机正前方多远的距离)。 33 Vector3 localPosition = Camera.main.transform.InverseTransformPoint(transform.position); 34 35 //第二步:动态缩放逻辑 36 //只有当 ScaleChange 勾选时才执行。目的 :实现“近大远小”或“远大近小”的视觉补偿(例如:为了防止UI离相机太远时看不清,可以设置让它在远处变大)。 37 if (ScaleChange) 38 { 39 //localPosition.z / LengthMax :计算当前物体到相机的距离占设定的“最大距离”的比例(0 到 1 之间,如果超出会大于 1)。 40 //Mathf.Lerp(RateMin, RateMax, 比例) :线性插值。根据上面算出的比例,在最小倍率和最大倍率之间取一个值。比如距离比例是 0.5,倍率就会取 RateMin 和 RateMax 的中间值。 41 float rate = Mathf.Lerp(RateMin, RateMax, localPosition.z / LengthMax); 42 43 //用基准大小乘以计算出的倍率,得到最终的缩放并应用给物体。 44 transform.localScale = InitScale * rate; 45 } 46 47 //第三步:始终朝向相机逻辑(广告牌效果) 48 ///- 解读 : 49 //1.localPosition.z = 0; :将刚才计算的相对坐标的深度(Z轴)清零。这意味着这个点被“拍扁”到了相机所在的平面上。 50 //2.TransformPoint :把这个拍扁后的点,重新转换回世界坐标。这个新点实际上是 物体在相机屏幕平面上的垂直投影点 。 51 //3.transform.LookAt(Position); :让物体的正前方(Z轴)看向这个投影点。 52 //意义 :这是一种非常巧妙的算法。因为物体看向的是自己在相机平面上的投影点,这就保证了 物体的正交平面始终与相机的屏幕平面完全平行 。不管相机怎么转,这个物体都会完美正对着玩家的屏幕。 53 54 //Debug.Log(localPosition); 55 localPosition.z = 0; 56 Vector3 Position = Camera.main.transform.TransformPoint(localPosition); 57 transform.LookAt(Position); 58 } 59 }
最终效果:


浙公网安备 33010602011771号