如何实现Cinemachine正交相机的平滑缩放?
Cinemachine正交相机平滑缩放实现方案
需求:让Cinemachine正交相机实现平滑缩放,按下按键后自动缓慢缩放到设定的最小(7.0f)/最大(14.0f)值,类似《最终幻想战术》的变焦效果,而非瞬间完成缩放。当前代码直接赋值正交大小导致瞬间变化,尝试添加Time.deltaTime后出现缩放过度且仍无平滑效果的问题。
方法一:协程实现固定时长平滑缩放
这种方式可以精确控制缩放完成的时间,按下一次按键后自动完成整个缩放过程:
using UnityEngine; using Cinemachine; using UnityEngine.InputSystem; using System.Collections; public class Zoom : MonoBehaviour { public CinemachineVirtualCamera currentCamera; public float zoomDuration = 1.5f; // 缩放总时长(秒),可调整快慢 private Coroutine _activeZoomCoroutine; public void OnZoomIn(InputAction.CallbackContext context) { if (context.started) { TriggerSmoothZoom(7.0f); } } public void OnZoomOut(InputAction.CallbackContext context) { if (context.started) { TriggerSmoothZoom(14.0f); } } private void TriggerSmoothZoom(float targetSize) { // 停止正在进行的缩放,避免冲突 if (_activeZoomCoroutine != null) { StopCoroutine(_activeZoomCoroutine); } _activeZoomCoroutine = StartCoroutine(ZoomToTarget(targetSize)); } private IEnumerator ZoomToTarget(float targetSize) { float startSize = currentCamera.m_Lens.OrthographicSize; float elapsedTime = 0f; while (elapsedTime < zoomDuration) { elapsedTime += Time.deltaTime; // 线性插值实现平滑过渡,用Mathf.SmoothStep可获得缓动效果 currentCamera.m_Lens.OrthographicSize = Mathf.Lerp(startSize, targetSize, elapsedTime / zoomDuration); yield return null; } // 确保最终精确到达目标值 currentCamera.m_Lens.OrthographicSize = targetSize; _activeZoomCoroutine = null; } }
关键说明:
zoomDuration:控制缩放的快慢,值越小缩放越快,越大越慢- 协程
ZoomToTarget:通过逐帧插值,在指定时间内将相机正交大小从当前值过渡到目标值 - 每次触发缩放时先停止之前的协程,避免多次按键导致的冲突
方法二:Update帧更新实现平滑缩放
这种方式更简洁,通过每帧逐步逼近目标值,适合不需要严格固定时长的场景:
using UnityEngine; using Cinemachine; using UnityEngine.InputSystem; public class Zoom : MonoBehaviour { public CinemachineVirtualCamera currentCamera; public float zoomSpeed = 5f; // 每秒缩放的变化幅度,可调整快慢 private float _targetOrthographicSize; private void Start() { // 初始化目标值为当前相机的正交大小 _targetOrthographicSize = currentCamera.m_Lens.OrthographicSize; } private void Update() { // 每帧向目标值逼近,保证平滑过渡 currentCamera.m_Lens.OrthographicSize = Mathf.MoveTowards( currentCamera.m_Lens.OrthographicSize, _targetOrthographicSize, zoomSpeed * Time.deltaTime ); } public void OnZoomIn(InputAction.CallbackContext context) { if (context.started) { _targetOrthographicSize = 7.0f; } } public void OnZoomOut(InputAction.CallbackContext context) { if (context.started) { _targetOrthographicSize = 14.0f; } } }
关键说明:
zoomSpeed:控制每秒缩放的变化量,值越大缩放越快Mathf.MoveTowards:保证每帧的变化量基于Time.deltaTime,避免帧率波动影响缩放速度- 只需要设置目标值,Update会自动完成平滑过渡
为什么之前的尝试失败?
你之前添加Time.deltaTime后出现异常,大概率是因为只在按键触发时执行了一次缩放逻辑,没有在Update或协程中持续更新相机的正交大小,导致要么瞬间完成,要么计算错误出现过度缩放。上面两种方法都是通过逐帧更新实现平滑过渡,解决了这个问题。
内容的提问来源于stack exchange,提问作者NectarNoks
相关产品推荐
相关产品推荐

