注意:本文中每个功能都是分别使用cinemachine和camera两种组件分别实现的,请按需提取。如果有问题可以直接下方留言,看到我会解答。另外加个关注你也不亏是不是?。本文2021.1.5日会再更新其他功能实现
一、多个摄像机平滑切换
当场景中存在多个虚拟相机时,关闭当前的主虚拟相机,就会平滑切换到所有开启状态中priority值比较高的相机。也就是说当关闭一个相机,并同时开启一个相机时,镜头就会平滑平移过去。
FreeLocckCam、Camera实现
//先停再开,可以在权值相同且同时开启的情况下切换相机
//FreeLocckCam、Camera都可以使用这种方式
camerObject.SetActive (false)
camerObject.SetActive (true)
在inspector中能设置切换速度和平滑曲线
二、重置 摄像机
重置摄像机包括重置位置、视角、视距
Camera组件实现
public void ResetCamera(){
// 重置视距
this.Camera.main.OrthographicSize = this.defaultViewScale;
this.Camera.main.FieldOfView = this.defaultViewScale;
// 重置位置
this.Camera.main.tansform.position = this.defaultPos;
this.Camera.main.tansform.rotation = this.defaultRot;
}
FreeLookCam组件实现
由于freelook 有自己的环顾坐标体系,所以重置时不止要重置摄像机,还要重置freelook组件的相关参数
public void ResetCamera(){
// 重置角度
//将binding mode改为LockToTargetWithWorldUp
freeLookCam.PreviousStateIsValid = false;
freeLookCam.m_XAxis.Value = 0;
freeLookCam.m_YAxis.Value = 0.5f;
//如果X轴位置有问题,请查看heading>bias值
// 重置视距
this.mainCineCamera.m_Lens.OrthographicSize = this.defaultViewScale;
this.mainCineCamera.m_Lens.FieldOfView = this.defaultViewScale;
// 重置位置
this.mainCineCamera.LookAt.tansform = this.LookAtDefaultPos;
this.mainCineCamera.Follow.transform = this.followDefalutPos;
}
三、旋转视角
旋转视角有两种方式,一种是以摄像机自身为中心,环顾四周。另一种是以目标为中心,摄像机围绕目标旋转。
使用FreeLookCam 围绕目标旋转
首先在场景中添加好freelookCam组件,然后在inspector中设置follow物体和lookat物体。follow物体指的是相机围绕物体旋转时的原点。lookat指的是香镜头聚焦的位置。不管怎么旋转,摄像机总会面对这个物体。
在inspector的 top、middle、buttom中可以设置这个旋转范围的高度和半径
public float rotateAxisSpeed_x = 3f;
public float rotateAxisSpeed_y = 3f;
public void RotateAxis(float x, float y)
{
mainCineCamera.m_XAxis.m_InputAxisValue = x * rotateAxisSpeed_x;
mainCineCamera.m_YAxis.m_InputAxisValue = y * rotateAxisSpeed_y;
}
void Update(){
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
this.RotateAxis(h,v);
}
四、平移视角
所谓平移视角,就是在当前摄像机的视角下,对摄像机进行相对平移操作。
Camera组件实现
public float moveSpeedXY = 10f;
// 以前后移动速度
public float moveSpeedZ = 60f;
void Update()
{
// 获取水平及滚轮按键值 区间为 0-1f
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
float mouse = Input.GetAxis("Mouse ScrollWheel");
//调用平移的方法
transform.Translate(new Vector3(h * moveSpeedXY, v * moveSpeedXY, mouse * moveSpeedZ) * Time.deltaTime, Space.Self);
}
FreeLocckCam组件实现
使用这个组件需要考虑两种情况:
1 有跟随无目标的情况
这个实现比较简单,和上面用Camera组件实现的差不多,只需不过需要移动的不是摄像机本身,而是要移动 Follow的物体。
2 有跟随有目标的情况
有跟随目标代表环顾功能和平移功能需要共存。由于旋转摄像机时相机始终面向目标,所以如果单纯移动Follow物体,视角还是会依然顶着目标方向的。所以需要保证follow的物体和lookat的物体同时轻易。由于我们的需求是“根据相机视角平移”,那么为了避免产生死循环,需要将这几个对象分别建立跟踪关系。 这个功能的实现也有很多种方式,下面介绍两种
第一种实现方式:
进行平移时移动follow和lookat目标的父物体,在移动的同时关闭freecamera组件,移动结束后再打开。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
public class CameraController: MonoBehaviour
{
// 上下左右的移动速度
public float moveSpeedXY = 10f;
// 以前后移动速度
public float moveSpeedZ = 60f;
public CinemachineFreeLook freeLook;
private bool isCameraMoving = false;
Vector3 defaultPos;
Vector3 defaultRot;
void Update()
{
// 获取水平及滚轮按键值 区间为 0-1f
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
float mouse = Input.GetAxis("Mouse ScrollWheel");
if (h + v != 0f)
{
//调用平移的方法
if (!isCameraMoving)
{
// 获取移动前的偏移
defaultPos = Camera.main.transform.position - transform.position;
defaultRot = Camera.main.transform.rotation.eulerAngles - transform.rotation.eulerAngles;
// 关闭组件避免死循环
freeLook.gameObject.SetActive(false);
isCameraMoving = true;
}
// 平移镜头
Camera.main.transform.Translate(new Vector3(h * moveSpeedXY, v * moveSpeedXY, mouse * moveSpeedZ) * Time.deltaTime, Space.Self);
}
else
{
if (isCameraMoving)
{
// 重置跟随和瞄准目标位置与主摄像机对齐
transform.position = Camera.main.transform.position - defaultPos;
transform.eulerAngles = Camera.main.transform.rotation.eulerAngles - defaultRot;
// 启动freelook
freeLook.gameObject.SetActive(true);
isCameraMoving = false;
}
}
}
}
第二种方式(推荐):
让lookat目标与相机的方向保持一致,然后让相机的follow目标跟随lookat目标。当平移时,只需移动lookat目标物体即可。比较推荐这种方式,简单合理。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
public class CameraController: MonoBehaviour
{
// 上下左右的移动速度
public float moveSpeedXY = 10f;
// 以前后移动速度
public float moveSpeedZ = 60f;
public CinemachineFreeLook freeLook;
void Update()
{
//
freeLook.LookAt.transform.eulerAngles = new Vector3(0f, Camera.main.transform.rotation.eulerAngles.y, 0f);
// 获取水平及滚轮按键值 区间为 0-1f
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
float mouse = Input.GetAxis("Mouse ScrollWheel");
if (h + v != 0f)
{
freeLook.LookAt.transform.Translate(new Vector3(h * moveSpeedXY, mouse * moveSpeedZ, v * moveSpeedXY) * Time.deltaTime, Space.Self);
}
}
}
特别注意
需要特别注意的当你进行平移操作的时候你会发现相机可能会跟着旋转。这并不是我们代码造成的,而是cinecamera为了相机平滑过渡而设计的一个功能导致的。只需要做以下设置就行了:
- 在freelookcam组件的inspector窗口中找到Orbits->Binding Mode改为 Lock to target with world up
- 分别找到top、middle、buttom 中的bady,把里面相关的Damping设置为0就可以了。
- 请务必注意此处,如果以上设置无效,依然有某个轴抖动的情况,那么有可能是相机跟随的物体使用了刚体移动。需要在rigidbody组件中找到interpolate,并尝试那几个选项进行差值设置就能解决问题~!!
五、缩放视角
视角缩放是通过修改摄像机的FieldOfView和orthographic实现的。
Camera组件实现
private float currentViewScale;
public float scaleSpeed = 10.0f;
public float scaleMinScale = 1.0f;
public float scaleMaxScale = 150.0f;
void Start() {
// for camera view scale
this.currentViewScale = Camera.main.orthographic?Camera.main.OrthographicSize:Camera.main.FieldOfView;
}
void Update(){
this.currentViewScale += Input.GetAxis("Mouse ScrollWheel") * this.scaleSpeed;
this.currentViewScale = Mathf.Clamp(this.currentViewScale, this.minScale, this.maxScale);
if (Camera.main.orthographic)
{
Camera.main.OrthographicSize = this.currentViewScale;
}
else
{
Camera.main.FieldOfView = this.currentViewScale;
}
}
cinemachine组件实现
private float currentViewScale;
public float scaleSpeed = 10.0f;
public float scaleMinScale = 1.0f;
public float scaleMaxScale = 150.0f;
void Start() {
// for camera view scale
this.currentViewScale = Camera.main.orthographic? mainCineCamera.m_Lens.OrthographicSize:this.currentViewScale = mainCineCamera.m_Lens.FieldOfView;
}
void Update(){
this.currentViewScale += Input.GetAxis("Mouse ScrollWheel") * this.scaleSpeed;
this.currentViewScale = Mathf.Clamp(this.currentViewScale, this.minScale, this.maxScale);
if (Camera.main.orthographic == true)
{
this.mainCineCamera.m_Lens.OrthographicSize = this.currentViewScale;
}
else
{
this.mainCineCamera.m_Lens.FieldOfView = this.currentViewScale;
}
}
六、自动绕过障碍物
该功能只使用FreeLocckCam实现
- 虚拟相机需添加 cinemachine collider组件
- 在 cinemachine collider 设置作用层
- 在 cinemachine collider 可以设置镜头绕物的方式,距离,数量,和平滑度等等