界面UI跟随相机转动(2D图标始终面向用户)Unity操作记录

一、背景

在unity模型里,我需要对一个建筑楼层模型的地面拆分若干个区域,并向用户指示这些区域,需要做到用户通过鼠标旋转任何角度,指示区域的图标及内的文字信息都始终面向用户。

二、实践过程

(1)在楼层中地面追加Plane

选中指定楼层模型,右键3D对象--->平面 即可创建一个平面,调整位置、大小。我根据需要建立了3个平面,每个平面代表一个测试区

image

 (2)素材准备与导入操作

右键unity项目层级的Img文件夹----->点击 在资源管理器中显示 ---->将所需的素材复制进去

image

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

image

 (3)将定位图标拖入模型中并调整位置、大小显示;修改文件名称

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

image

  (4)将区域名称显示框图标拖入模型中并调整位置、大小显示;修改文件名称;建立两个文本对象并设置相应介绍

 直接将项目层级的区域名称显示框图标直接拖入XXXX区域标签对象下作为他的子级,修改名称为:区域名称,调整位置、大小显示。

image

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

image

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

image

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

image

 (5)挂载面向用户的脚本

在XXX区域标签这个对象上,挂载AlwaysFaceTargetTool.cs脚本

image

 脚本如下:

 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 }

 最终效果:

image

 

posted @ 2026-05-06 18:22  上清风  阅读(43)  评论(0)    收藏  举报