unity 的Cinemachine组件运用

unity 的Cinemachine组件运用1.第三人称视角控制通过PackageManager安装CineMachine1) 最简单的方法使用freeLook虚拟相机常用的调整为:1.观察目标:将要看的目标放在这里。2输入控制:把你想用来控制的虚拟轴(就是InputManager里的)的名字输入进去就行。默认是填mouse那个输入轴。注意:似乎不支持NewInputSystem。所以在用NewInputSystem时要么用在projectSetting/player里改成both设置。要么自己写脚本去调用这个组件中的

大家好,又见面了,我是你们的朋友全栈君。

1.第三人称视角控制

通过Package Manager 安装CineMachine
1) 最简单的方法使用freeLook虚拟相机

常用的调整为:
1.观察目标:
在这里插入图片描述

将要看的目标放在这里。
2输入控制:
在这里插入图片描述
把你想用来控制的虚拟轴(就是InputManager里的)的名字输入进去就行。默认是填mouse那个输入轴。
注意:似乎不支持New InputSystem。所以在用New InputSystem时要么用在projectSetting/player里改成both设置。
在这里插入图片描述
要么自己写脚本去调用这个组件中的Input Axis Value值

//第三人称相机
public CinemachineFreeLook thridPersonVCam;
…
thridPersonVCam.m_XAxis.m_InputAxisValue = mov.x; //x轴旋转
thridPersonVCam.m_YAxis.m_InputAxisValue = mov.y; //y轴旋转

2) 是我在一个项目中实现的方法:
参考了unity官方视频:https://www.bilibili.com/video/BV1Xa4y1j7iP
就是先让虚拟摄像机看向角色身上的子物体,玩家通过控制子物体的旋转来控制虚拟摄像机的朝向。但是要解决一个问题,就是子物体会随着父物体一起旋转的问题。视频中的解决方法是在移动或射击时强制将角色转向视角方向,同时将视点子物体的yz轴local的旋转值置零。
但是我是想实现个能在移动是也能自由观察的相机,所以采用了一个更简单但可能更耗性能的方法,就是在脚本内部另外保存一个实际子物体应该的世界坐标下的旋转值。在每次的lateUpdate里将子物体的世界坐标的旋转值强制改为这个脚本中的值。实现效果如下:
在这里插入图片描述
实现的主要脚本如下:

public class ViewController : MonoBehaviour
{ 
   
    [Tooltip("相机左右旋转速度")] public float rotSpeedLR = 100f;
    //用来给调整灵敏度的UI进行最大最小值的限制
    [Tooltip("相机左右旋转最大速度")] public float maxRotSpeedLR = 360f;
    [Tooltip("相机左右旋转最小速度")] public float minRotSpeedLR = 90f;
    [Tooltip("左右是否反向")] public bool LRInvert;
    [Tooltip("相机上下旋转速度")] public float rotSpeedUD = 50f;
    //用来给调整灵敏度的UI进行最大最小值的限制
    [Tooltip("相机上下旋转最大速度")] public float maxRotSpeedUD = 360f;
    [Tooltip("相机上下旋转最小速度")] public float minRotSpeedUD = 90f;
    [Tooltip("上下是否反向")] public bool UDInvert = true;
    [Tooltip("相机向上限值")] public float upRange = 40f;
    [Tooltip("相机向下限值")] public float downRange = -15f;
    //视点子物体
    public Transform viewPoint;
    //实际playerViewPoint的旋转
    [SerializeField]private Vector3 playerViewPointRotation;

    private void Start()
    { 
   
        //开始时将视角转向同角色方向
        playerViewPointRotation = transform.eulerAngles;
    }

    void LateUpdate()
    { 
   
        TrdViewControl();
    }

    /// <summary>
    /// 第三人称视角控制
    /// </summary>
    void TrdViewControl()
    { 
   
        //计算实际旋转分量
        var rotVector = new Vector3((UDInvert ? 1 : -1) * rotSpeedUD, (LRInvert ? 1 : -1) * rotSpeedLR, 0);
        Vector3 rotation = rotVector * viewInput * Time.deltaTime;
        playerViewPointRotation += rotation;
        var angleX = playerViewPointRotation.x;
        //clamp限制垂直方向的角度
        if (angleX > upRange)
        { 
   
            angleX = upRange;
        }
        if (angleX < downRange)
        { 
   
            angleX = downRange;
        }
        playerViewPointRotation.x = angleX;
        //会在lateUpdate里实时地改变视点的方向来改变视角
        viewPoint.eulerAngles = playerViewPointRotation;
    }

    //視角改变量
    private Vector2 viewInput;
    /// <summary>
    /// 视角输入的控制函数
    /// </summary>
    /// <param name="context"></param>
    public void OnViewControl(InputAction.CallbackContext context)
    { 
   
        var tempInput = context.ReadValue<Vector2>();
        viewInput = new Vector2(tempInput.y, tempInput.x).normalized;
    }

}

与freelook虚拟相机相比:实现上麻烦了许多,但相应的修改自由度就比较高,可以应用于其他的跟随和朝向的算法。

2.锁定相机

是想做一个类似塞尔达旷野之息锁定视角。
在这里插入图片描述

首先想到cinemachine的Target Group Camera。
但是用了下感觉偏向于固定方向的多目标锁定,不能让玩家自己旋转视角(估计也可以实现,但没什么好的想法)。
关于Target Group Camera设置可以参考以下博客:
https://www.pianshen.com/article/63141639747/
锁定的相机似乎是绕着角色和目标做一个椭圆的轨道旋转。
于是用MixingCamera,将主角的相机和一个绕着目标的相机融合,形成一个偏椭圆的轨道。
效果如下:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
黄色为最终混合的相机轨迹,蓝色为目标相机的轨道,可见有两个点要实现:

  1. 目标相机的轨道大小要随着角色和玩家的距离改变,targetOffset = playerOffset + dis
  2. 目标相机的视角角度要同角色相机。
    实现的步骤如下:
    1.创建mixingCamera相机
    2.删除默认子相机,保留一个Orbital transposer跟随算法的子相机作为目标相机。
    注意:由于目标相机用的是Orbital transposer跟随算法,默认打开Recenter to target Heading。
    在这里插入图片描述

我们要关掉它,否则目标相机会一直想回正,导致相机抖动。
3. 为mixingCamera添加一个脚本代码如下:

using Cinemachine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LockVcamController : MonoBehaviour
{ 
   
    private Transform target;
    private CinemachineMixingCamera lockVcam;
    //当前相机的组件
    private CinemachineVirtualCamera currentVcam;
    private CinemachineTransposer currentVcamTrans;
    //角色身上视点
    private Transform viewPoint;
    //目标相机的组件
    private CinemachineVirtualCamera targetVcam;
    private CinemachineOrbitalTransposer lockTargetObi;
    //判断是否锁定
    private bool _isLock;

    private void Awake()
    { 
   
        //获取当前混合相机控件
        lockVcam = GetComponent<CinemachineMixingCamera>();
        //克隆一个当前的玩家虚拟相机,并放在混合相机下
        currentVcam = Instantiate(GameObject.Find("PlayerVcam"), transform).GetComponent<CinemachineVirtualCamera>();
        currentVcamTrans = currentVcam.GetCinemachineComponent<CinemachineTransposer>();
        //获取viewPoint
        viewPoint = currentVcam.Follow;
        //获取锁定目标的圆形轨道相机组件
        targetVcam = lockVcam.ChildCameras[0] as CinemachineVirtualCamera;
        lockTargetObi = targetVcam.GetCinemachineComponent<CinemachineOrbitalTransposer>();
    }

    /// <summary>
    /// 开始锁定并设定锁定目标
    /// </summary>
    /// <param name="target">锁定目标</param>
    /// <returns></returns>
    public bool SetLock(Transform target,int priority)
    { 
   
        this.target = target;
        if (this.target == null)//如果没目标就返回失败
            return false;
        //将目标相机的跟随和朝向设为指定目标
        targetVcam.Follow = target;
        targetVcam.LookAt = target;
        lockVcam.Priority = priority + 1;
        _isLock = true;
        return true;
    }

    /// <summary>
    /// 解锁
    /// </summary>
    public void Unlock()
    { 
   
        lockVcam.Priority = lockVcam.Priority - 2;
        _isLock = false;
    }

    private void LateUpdate()
    { 
   
        
        if (_isLock)
        { 
   
            if (target == null)
                Unlock();
            else
                SetObi();
        }
        
    }
    /// <summary>
    /// 设置目标相机的轨道
    /// </summary>
    private void SetObi()
    { 
   
        var tempPos = viewPoint.position;
        tempPos.y = target.position.y;
        var dis = Vector3.Distance(tempPos, target.position) + Mathf.Abs(currentVcamTrans.m_FollowOffset.z);
        lockTargetObi.m_FollowOffset.z = -dis;//都是从后向前看与玩家设置保持一致
        lockTargetObi.m_XAxis.Value = viewPoint.eulerAngles.y;//将target相机的方向同视点方向
        //如果是用freeLook相机,就要去获取freelook中组件也有个m_XAxis,lockTargetObi.m_XAxis = TPVcam.m_XAis;
    }
}

之后只要去调用脚本中的SetLock()方法,把目标和优先级传进去就可以了。

3. cinemachine的分屏

主要是翻译了cinemachine官方文档。
https://docs.unity3d.com/Packages/com.unity.cinemachine@2.6/manual/CinemachineMultipleCameras.html
分为4步:
1) 首先添加player层。有几个player就要分几个层。
在这里插入图片描述
2) 添加对应个数的unityCamera(不是虚拟相机),并添加各自的cinemachineBrain组件
3) 设置每个unityCamera的cullingMask,把除了本相机对应的层的其它之前添加的层取消。例如:P1Cam的话就把P2层取消。
4) 添加各个分屏对应的虚拟相机,虚拟相机要设置到相应的层里。
5) 修改各个unityCamera里的viewportRect,确定要在屏幕里显示的范围形成分屏效果。
最后效果如下:
在这里插入图片描述

其他使用上的注意:

  1. 注意cinemachine的调用顺序:
    想我这样在脚本中有视角控制相关的脚本,如果出现相机抖动,主要是相同的update系列的函数cinemachine里的先调用。可以在projectSetting里设定同级的系统函数在不同脚本时的调用顺序。
    在这里插入图片描述

  2. 其实跟Cinemachine没什么关系,人物用刚体移动时,刚体要用插值(interpolate)否则会造成相机抖动。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/145048.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 已刻游戏目录

    已刻游戏目录单机游戏1.生化奇兵1、2、32.蔷薇少女格斗3.全女格斗2.04.劲乐团5.魔兽争霸6.生化危机1-6启示录7.MaxPayne2+38.寄生前夜9.恐龙危机1、210.梦幻模拟战4、511.PS模拟器:北欧女神、放浪冒险谭、寄生前夜、寂静岭1、异度装甲、月下夜想曲、古惑狼1-3、封神演义、苍魔灯、鬼屋魔影、武藏传12.FC模拟器13.MD模拟器14.杀手4…

  • Django(1)初识Django「建议收藏」

    Django(1)初识Django「建议收藏」前言Django是一个开放源代码的Web应用框架,由Python写成,最初用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站,即CMS(内容管理系统)软件,于2005年7月在BSD许可证下发布,这

  • java 数组转化为list_java中如何将数组转为list集合?

    java 数组转化为list_java中如何将数组转为list集合?java中将数组转为list集合的方法:1、使用原生方式,使用for()循环来拆分数组,并添加到List中;2、使用Arrays.asList()方法;3、使用Collections.addAll()方法;4、使用List.of()方法。问题描述:对于给定的如下数组,如何转换成List集合?String[]array={“a”,”b”,”c”};参考stackoverflow总结如下几种写法…

  • struts2 中 Actionsupport 的作用

    struts2 中 Actionsupport 的作用struts2中Actionsupport的作用Action跟Actionsupport的区别当我们在写action的时候,可以实现Action接口,也可以继承Actionsuppor

  • 100多个免费常用API接口分享,调用完全不限次数,以后总用得着![通俗易懂]

    100多个免费常用API接口分享,调用完全不限次数,以后总用得着![通俗易懂]各类无次数限制的免费API接口整理,主要是聚合数据上和APIStore上的一些,还有一些其他的。聚合数据提供30大类,160种以上基础数据API服务,国内最大的基础数据API服务,下面就罗列一些免

  • bat 剪切文件_bat延时命令

    bat 剪切文件_bat延时命令扩展名是bat(在nt/2000/xp/2003下也可以是cmd)的文件就是批处理文件。首先批处理文件是一个文本文件,这个文件的每一行都是一条DOS命令(大部分时候就好象我们在DOS提示符下执行的命令行一样),你可以使用DOS下的Edit或者Windows的记事本(notepad)等任何文本文件编辑工具创建和修改批处理文件。其次,批处理文件是一种简单的程序,可以通过条件语句(if)和流程控制语句(…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号