Unity中A、B位置间Lerp插值时Y轴最大最小值限制问题
解决方案:保持插值点在AB连线同时钳制Y轴上限
核心问题是直接修改Y值会让点脱离A(当前物体)与B(centerGround)的连线,正确的做法是在AB连线的范围内找到Y值不超过listenerMaxY的点,而不是硬改坐标。
实现思路
- 先按原有逻辑计算出AB连线上的插值点(记为
targetPoint) - 如果
targetPoint的Y值超过listenerMaxY,则重新计算在AB连线上、Y值恰好等于listenerMaxY的点 - 否则直接使用原插值点
修改后的核心代码
float percentageDistance = downwardDistance / listenerMinY; float lerpRatio = Mathf.Clamp(percentageDistance, 0, .5f); Vector3 targetPoint = Vector3.Lerp(transform.position, centerGround.position, lerpRatio); // 处理Y轴上限钳制,同时保持在AB连线上 if (targetPoint.y > listenerMaxY) { // 计算A到B的Y轴差值 float yDiff = centerGround.position.y - transform.position.y; // 如果A和B的Y值相同(极端情况),直接钳制Y if (Mathf.Abs(yDiff) < 0.001f) { targetPoint.y = listenerMaxY; } else { // 计算需要调整的lerp比例,让Y刚好等于listenerMaxY float requiredRatio = (listenerMaxY - transform.position.y) / yDiff; // 确保比例不超过原插值的范围(0到0.5),避免点超出AB段的插值区间 requiredRatio = Mathf.Clamp(requiredRatio, 0, lerpRatio); targetPoint = Vector3.Lerp(transform.position, centerGround.position, requiredRatio); } } listener.position = targetPoint; listener.rotation = transform.rotation;
完整修改后的代码
public class CameraRay : MonoBehaviour { [SerializeField] LayerMask groundLayer; [SerializeField] Transform centerGround; [SerializeField] Transform listener; [SerializeField] int listenerMinY = 20; [SerializeField] int listenerMaxY = 60; private void Update() { RaycastHit hit; float forwardDistance = 0; float downwardDistance = 0; // 控制地面目标点B的位置 if (Physics.Raycast(transform.position, transform.forward, out hit, Mathf.Infinity, groundLayer)) { forwardDistance = hit.distance; Debug.DrawRay(transform.position, transform.forward * forwardDistance, Color.blue); centerGround.position = hit.point; } // 检测到地面的垂直距离,用颜色区分状态 if (Physics.Raycast(transform.position, Vector3.down, out hit, Mathf.Infinity, groundLayer)) { downwardDistance = hit.distance; Color rayColor = Color.yellow; if (downwardDistance < listenerMinY) rayColor = Color.green; else if (downwardDistance > listenerMaxY) rayColor = Color.red; Debug.DrawRay(transform.position, Vector3.down * downwardDistance, rayColor); } float percentageDistance = downwardDistance / listenerMinY; float lerpRatio = Mathf.Clamp(percentageDistance, 0, .5f); Vector3 targetPoint = Vector3.Lerp(transform.position, centerGround.position, lerpRatio); // 处理Y轴上限钳制,同时保持在AB连线上 if (targetPoint.y > listenerMaxY) { float yDiff = centerGround.position.y - transform.position.y; if (Mathf.Abs(yDiff) < 0.001f) { targetPoint.y = listenerMaxY; } else { float requiredRatio = (listenerMaxY - transform.position.y) / yDiff; requiredRatio = Mathf.Clamp(requiredRatio, 0, lerpRatio); targetPoint = Vector3.Lerp(transform.position, centerGround.position, requiredRatio); } } listener.position = targetPoint; listener.rotation = transform.rotation; } }
逻辑解释
- 当原插值点的Y超过上限时,通过线性计算找到AB连线上Y等于
listenerMaxY的精确位置,确保点始终在A和B的连线上 - 加入了Y差极小的判断,避免除以0的异常
- 用
Mathf.Clamp(requiredRatio, 0, lerpRatio)确保调整后的点不会超出原插值的范围(不会跑到原插值点的外侧)
内容的提问来源于stack exchange,提问作者Majs
相关产品推荐
相关产品推荐

