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)否则会造成相机抖动。

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • java手机编译器_Java编译器手机版[通俗易懂]

    Java编译器手机版是一款十分好用的手机办公软件,用户可以使用此软件适用在线从文件浏览器中开启编码文档,便捷客户访问查询。全自动储存作用能够让客户在各种各样情景撰写编码,便捷客户应用。感兴趣的用户赶紧来下载Java编译器手机安卓版吧。Java编译器手机版特色1、Java编译器手机版将编译程序您的编码以最短的时间完成;2、app也可以编译程序C,C++编码及其Java程序流程;3、Java视频动画,…

    2022年4月9日
    47
  • 工具帮助达到高潮_php代码用什么工具

    工具帮助达到高潮_php代码用什么工具网站挂马检测工具,网站被挂马在线检测工具作者:dthost|时间:2015-09-06|9,672次阅读做网站时间比较长的老站长都应该知道,网站最担心的事情就是网站被挂马,网站被挂马后,会被安全联盟列入名单,所有的安全软件以及联盟,都会提示这个网站谨慎访问,那么我们如何查到这些挂马,从而删除,但是问题来了,我们怎么来发现这些挂马呢?别给我说那些老站长才知道的技术,我现在一点会需要怎么办呢?首…

    2022年9月30日
    2
  • 遗传算法_aforge遗传算法

    遗传算法_aforge遗传算法一、遗传算法简介:遗传算法是进化算法的一部分,是一种通过模拟自然进化过程搜索最优解的方法。二、遗传算法思想:遗传算法组成:1.编码2.适应度函数3.遗传算子:选择、交叉、变异4.运行参数借鉴生物进化论,遗传算法将要解决的问题模拟成一个生物进化的过程,通过复制、交叉、突变等操作产生下一代的解,并逐步淘汰掉适应度函数值低的解,增加适应度函数值高的解。这样进化N代后就很有可能会进化出适应度函数值很高的个体。2.1.编码将问题的解编码称字符串形式才能使用遗传算法。最简单的一种编码是二进制编码,即

    2025年8月27日
    6
  • flask web开发实战 入门 pdf_常用的web开发框架

    flask web开发实战 入门 pdf_常用的web开发框架Flask简介什么是Flask?Flask是一个用Python编写的Web应用程序框架。Flask基于Werkzeug(WSGI工具包)和Jinja2模板引擎。什么是WebFramework?WebApplicationFramework(Web应用程序框架)或简单的WebFramework(Web框架)表示一个库和模块的集合,使Web应用程序开发人员能够编写应用程序,而……

    2022年8月26日
    6
  • 关于我

    关于我

    2021年6月15日
    92
  • 实现textarea内换行

    为什么会出现这个问题呢?是因为我在做自己个人网站的留言板时,我想预设好textarea的值,像这样,让用户输入的时候直接另起一行!不墨墨唧唧了,直接告诉你们,下面两种方法是没有用的。1.企图在html里面加上&amp;lt;br/&amp;gt;&amp;lt;textareacols=&quot;15&quot;rows=&quot;8&quot;id=&quot;Txt&quot;&amp;gt;To

    2022年4月3日
    61

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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