野区捕龙为宠头像
unity 模型标签一直朝向摄像机封面图

unity 模型标签一直朝向摄像机

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

主要是用在 模型部件的标签使用。
在这里插入图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一、代码

代码挂载在标签UI上。
功能(可以在编辑器面板调整):
1.永远朝向相机
相机随着相机变化,一直朝向相机
2.位置跟随物体
标签一直跟随物体
3.尺寸控制
无论相机远近怎么变换,标签大小随之变化。
在这里插入图片描述

using UnityEngine;
using UnityEngine.Rendering;

[RequireComponent(typeof(RectTransform))] // 如果是UI
public class RobustWorldSpaceUIFacer : MonoBehaviour
{
    [Header("核心目标")]
    [Tooltip("要朝向的相机。如果为空,则使用Main Camera。")]
    public Camera targetCamera;

    [Header("朝向控制")]
    [Tooltip("启用后,UI将始终旋转以面向相机。")]
    public bool faceCamera = true;
    [Tooltip("旋转平滑时间(秒)。0为立即旋转。")]
    [Range(0f, 2f)]
    public float rotationSmoothTime = 0.15f;
    [Tooltip("自定义的向上轴方向(世界空间)。用于防止翻转。")]
    public Vector3 worldUp = Vector3.up;

    [Header("位置跟随")]
    [Tooltip("UI要跟随的目标Transform。如果为空,则UI在世界中静止。")]
    public Transform followTarget;
    [Tooltip("相对于跟随目标的偏移量。")]
    public Vector3 targetOffset = new Vector3(0, 2f, 0); // 例如,在目标头顶2米
    [Tooltip("位置跟随的平滑时间(秒)。0为立即移动。")]
    [Range(0f, 2f)]
    public float positionSmoothTime = 0.1f;

    [Header("尺寸控制")]
    [Tooltip("启用后,将尝试根据与相机的距离调整缩放,以保持视觉大小一致。")]
    public bool scaleWithDistance = false;
    [Tooltip("参考距离。在此距离下,UI的缩放为1。")]
    public float referenceDistance = 5f;
    [Tooltip("缩放平滑时间(秒)。")]
    [Range(0f, 2f)]
    public float scaleSmoothTime = 0.2f;

    // 用于平滑计算的私有变量
    private Quaternion _targetRotation;
    private Vector3 _rotationSmoothVelocity; // 用于Quaternion.Slerp的模拟速度(这里简化处理,实际用插值系数)
    private Vector3 _positionSmoothVelocity;
    private float _currentScale = 1f;
    private float _scaleSmoothVelocity;

    private Transform _myTransform;
    private RectTransform _rectTransform; // 如果是UI Canvas,可能需要获取

    // ... [所有SerializedField参数同上] ...

    [Header("性能")]
    public bool updateOnlyWhenVisible = true;
    public float maxUpdateDistance = 100f;
    private float _sqrMaxUpdateDistance;

    private Transform _transform;
    private Camera _cam;
    private Renderer _renderer; // 可选,用于可见性检测

    private Quaternion _targetRot;
    private Vector3 _posSmoothVel;
    private float _scaleSmoothVel;
    private float _currentScaleFactor = 1f;

    void Awake()
    {
        _transform = transform;
        _renderer = GetComponent<Renderer>(); // 可能为null,如果是Canvas
        _sqrMaxUpdateDistance = maxUpdateDistance * maxUpdateDistance;
    }

    void Start()
    {
        if (targetCamera == null) targetCamera = Camera.main;
        _cam = targetCamera;
        if (_cam == null) Debug.LogError("No camera assigned and no Main Camera found!", this);

        _targetRot = _transform.rotation;
        _currentScaleFactor = _transform.localScale.x;
    }

    void LateUpdate()
    {
        if (_cam == null) return;

        // 1. 距离裁剪
        float sqrDist = (_transform.position - _cam.transform.position).sqrMagnitude;
        if (sqrDist > _sqrMaxUpdateDistance) return;

        // 2. 可见性裁剪 (粗略)
        if (updateOnlyWhenVisible && _renderer != null && !_renderer.isVisible) return;

        // 3. 位置跟随
        if (followTarget != null)
        {
            Vector3 desiredPos = followTarget.TransformPoint(targetOffset); // 等价于 position + TransformDirection
            _transform.position = positionSmoothTime > 0 ?
                Vector3.SmoothDamp(_transform.position, desiredPos, ref _posSmoothVel, positionSmoothTime) :
                desiredPos;
        }

        // 4. 计算并应用旋转
        if (faceCamera)
        {
            CalculateStableRotation();
            ApplyRotation();
        }

        // 5. 计算并应用缩放
        if (scaleWithDistance)
        {
            float desiredScale = Mathf.Clamp(Vector3.Distance(_transform.position, _cam.transform.position) / referenceDistance, 0.1f, 10f);
            _currentScaleFactor = scaleSmoothTime > 0 ?
                Mathf.SmoothDamp(_currentScaleFactor, desiredScale, ref _scaleSmoothVel, scaleSmoothTime) :
                desiredScale;
            _transform.localScale = Vector3.one * _currentScaleFactor;
        }
    }

    void CalculateStableRotation()
    {
        Vector3 toCamVector = _cam.transform.position - _transform.position;
        if (toCamVector.sqrMagnitude < 0.001f) return;

        Vector3 desiredForward = -toCamVector.normalized;
        Vector3 desiredUp = worldUp;

        // 防翻转处理
        if (Mathf.Abs(Vector3.Dot(desiredForward, desiredUp)) > 0.9999f)
        {
            desiredUp = _cam.transform.right;
        }

        _targetRot = Quaternion.LookRotation(desiredForward, desiredUp);
    }

    void ApplyRotation()
    {
        if (rotationSmoothTime > 0)
        {
            float t = Mathf.Min(1, Time.deltaTime / rotationSmoothTime);
            _transform.rotation = Quaternion.Slerp(_transform.rotation, _targetRot, t);
        }
        else
        {
            _transform.rotation = _targetRot;
        }
    }

    // 在编辑器中可视化跟随偏移
    void OnDrawGizmosSelected()
    {
        if (followTarget != null)
        {
            Gizmos.color = Color.green;
            Gizmos.DrawWireSphere(followTarget.TransformPoint(targetOffset), 0.1f);
            Gizmos.DrawLine(followTarget.position, followTarget.TransformPoint(targetOffset));
        }
    }
}

总结

好记性不如烂笔头

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/qq_37524903/article/details/170722010

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--