unity摄像机运动到头像脸部,正对摄像机功能

8 篇文章 2 订阅
4 篇文章 0 订阅

  开发游戏的时候,有时候点击NPC,摄像机会移动到角色面前正视NPC脸部这个功能。今天实现了下,确实需要点底子。注释里解释应该已经很详细了 。 一串白色的小球主要是用来参考相机运动轨迹的,可以 IsShowTip=false 来隐藏掉。支持相机任意角度,任意位置,就是这么任性。speed 可以调节运动快慢。Distance可以调节相机到人脸的距离 ,有瑕疵的地方可能就相机旋转不够自然,不过问题不大,足以应付。没到吹毛求疵的地步没啥大碍。先来两幅GIF瞧瞧

2021-7-8 升级组件,更灵活的功能,需要DoTween的插件支持,dotween不用说,好用之极

using System;
using DG.Tweening;
using UnityEngine;
public class MoveToFront: MonoBehaviour
{

    /// <summary>
    /// 运动时间
    /// </summary>
    public float duration = 1f;


    public float TargetDistance = 6.5f;

    private float _distance = 6.5f;



    public bool IsShowTip = true;

    public Transform Head;

    /// <summary>
    /// 需要旋转的角度
    /// </summary>
    private float _angle;

    



    /// <summary>
    /// 相机到头部的向量
    /// </summary>
    private Vector3 _camToheadDir;
    /// <summary>
    /// 相机到头部的相对高度
    /// </summary>
    private float _height;

    private Tween _tween;

    private float _target;
    // Use this for initialization
    void Start()
    {
        if (Head == null) throw new UnityException("头部物体为空,请先确定头部物体");
    }

    // Update is called once per frame
    void Update()
    {


        if (_tween != null)
        {
            Transform cam = Camera.main.transform;
            //不好理解可以先吧_timeTemp=1的时候理解
            //角度插值系数
            float lerpValue = Mathf.Lerp(0f, _angle, _target);
            //Debug.Log(lerpValue);
            //高度插值系数
            float tempHeight = Mathf.Lerp(0f, _height, _target);
            //距离插值系数
            float dis = Mathf.Lerp(_distance, TargetDistance, _target);


            //相机到头部的向量  +  头部到相机的高度的向量  当_timeTemp=1时,dir的y轴必为0,这样就可以水平注视头部
            Vector3 dir = _camToheadDir + new Vector3(0f, tempHeight, 0f);
            dir = dir.normalized;

            //r为旋转量,当_timeTemp=1时,就是相机应该旋转多少度才能跟头部相对的 量 
            //-lerpValue可能为正,也可能为负数,这就是-号存在的意义 正数顺时针,负数逆时针 
            Quaternion r = Quaternion.Euler(new Vector3(0f, -lerpValue, 0f));

            Vector3 newDir = r * -dir;//用四元数旋转向量,很牛逼,必须记住//-号是因为我们需要的是反向的向量

            //新位置= 位置 +向量 这个公式不用说了吧  
            // newDir * dis单位向量乘以长度得到长度为dis的向量
            cam.position = Head.position + newDir * dis;//


            //旋转相对容易,难得是位置
            cam.transform.forward = Vector3.Lerp(cam.transform.forward, (-newDir).normalized, _target);//使相机慢慢朝向脸 timeTemp可另外使用一个变量参数
            if (IsShowTip)
            {
                GameObject go = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                go.transform.position = cam.position;
            }


        }
      
    }

    public void MoveToHead(Action completedEvent)
    {
        Transform cam = Camera.main.transform;

        _camToheadDir = Head.position - cam.position;

        _camToheadDir = new Vector3(_camToheadDir.x, 0f, _camToheadDir.z);

        Vector3 headDir = new Vector3(Head.forward.x, 0f, Head.forward.z);

        _angle = Vector3.Angle(_camToheadDir, headDir);

        Vector3 dir = Vector3.Cross(_camToheadDir, headDir);//叉乘主要判断在脸部的左边还是右边

        if (dir.y > 0)
        {
            _angle *= -1;
        }
        Debug.Log(_angle);

        



        //算出角度后,再重新获取完整的向量
        _camToheadDir = Head.position - cam.position;

        _distance = _camToheadDir.magnitude;

        _height = cam.position.y - Head.position.y;


        _target = 0f;

        _tween = DOTween.To(() => _target, x => _target = x, 1, duration).SetEase(Ease.InOutQuad).OnComplete((() =>
        {
            _tween = null;
            if (completedEvent != null)
                completedEvent();
        }));
        if (IsShowTip)
        {
            GameObject go = GameObject.CreatePrimitive(PrimitiveType.Sphere);

            go.transform.position = cam.position;
        }

    }
#if UNITY_EDITOR_WIN
    private void OnGUI()
    {
        if (GUI.Button(new Rect(0f, 0f, 100f, 100f), "Test"))
        {
            // MyScreenToWorldPoint(new Vector3(300, 400, 200));
            MoveToHead(null);
            //  StartCoroutine(  PrintPoints());
        }
    }
#endif


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值