You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中用Vector3 Lerp移动相机如何实现缓入缓出并控制总时间

固定总时长的相机缓入缓出移动实现

原有代码的核心问题

要同时满足「严格按totalMovementTime指定时长抵达目标」和「平滑缓入缓出」两个要求,首先需要修正原代码的两个逻辑硬伤:

  • 原代码将transform.localPosition作为每帧插值的起点,是指数趋近的运动逻辑,根本无法卡准设定的总时长,甚至会因为浮点数精度问题,在离目标极近的位置持续漂移,触发不了循环退出条件
  • 原代码直接把时间比值作为Lerp的插值系数,是完全匀速的线性运动,启动瞬间就达到最高速度、抵达终点瞬间直接刹停,没有任何速度平滑变化,自然没有缓入缓出效果

实现逻辑

  • 协程启动时提前记录相机的固定起始位置,所有插值都在这个固定起始位置和目标位置之间计算,不跟每帧的当前位置绑定,从根源上避免总时长失控
  • 计算严格绑定总时长的归一化线性进度t = 累计移动时间 / totalMovementTime,范围落在0~1之间,保证累计时间走完设定值时,进度必然到100%
  • 对线性进度t套用缓动函数,把匀速进度映射成「启动时从0逐步加速(缓入)、中途达到最高速度、临近终点逐步减速到0(缓出)」的速度曲线,用转换后的缓动值作为Lerp的插值系数
  • 循环退出条件从「距离目标点的距离大于0」改成「累计移动时间小于总时长」,时间到点直接对齐目标位置,彻底解决漂移问题

修正后代码

public IEnumerator MoveToDestination () {
    float totalMovementTime = 2f; 
    float currentMovementTime = 0f;
    // 协程启动时记录固定起始位置,避免插值基线漂移
    Vector3 startCamPos = transform.localPosition;
    Vector3 targetCamPos = destinationCamPos;

    while (currentMovementTime < totalMovementTime) {
        currentMovementTime += Time.deltaTime;
        // 计算0-1范围的线性进度,严格和总时长绑定
        float t = Mathf.Clamp01(currentMovementTime / totalMovementTime);
        // 三次方缓入缓出:t<0.5时加速(缓入),t>0.5时减速(缓出)
        float easedT;
        if (t < 0.5f) {
            easedT = 4 * t * t * t;
        } else {
            easedT = 1 - Mathf.Pow(-2 * t + 2, 3) / 2;
        }
        // 基于固定起止位置做插值,位置和缓动进度严格绑定
        transform.localPosition = Vector3.Lerp(startCamPos, targetCamPos, easedT);
        yield return null;
    }
    // 时间到点直接对齐目标,消除累计浮点误差
    transform.localPosition = targetCamPos;
}

效果说明

  • 全程移动总耗时严格等于totalMovementTime的设定值,不管速度曲线怎么调整,都不会提前或延后抵达目标
  • 启动相机移动时,速度从0逐步提升,不会出现突然窜动的生硬感;即将抵达目标位置时,速度逐步降低,最后速度为0时刚好停在目标点
  • 如果觉得当前缓动的幅度不合适,可以替换不同阶数的缓动公式,只要是基于归一化t计算的进度映射,都不会破坏总时长的控制逻辑

内容的提问来源于stack exchange,提问作者Pifo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.29 04:54:03