Xem thêm câu trả lời này .
Có hai cách phổ biến để sử dụng Lerp
:
1. Pha trộn tuyến tính giữa bắt đầu và kết thúc
progress = Mathf.Clamp01(progress + speedPerTick);
current = Mathf.Lerp(start, end, progress);
Đây là phiên bản có lẽ bạn quen thuộc nhất.
2. Dễ dàng theo cấp số nhân đối với mục tiêu
current = Mathf.Lerp(current, target, sharpnessPerTick);
Lưu ý rằng trong phiên bản này, current
giá trị xuất hiện ở cả đầu ra và đầu vào. Nó thay thế start
biến, vì vậy chúng tôi luôn bắt đầu từ bất cứ nơi nào chúng tôi chuyển đến trên bản cập nhật cuối cùng. Đây là những gì mang lại cho phiên bản Lerp
bộ nhớ này từ khung hình này sang khung hình tiếp theo. Từ điểm bắt đầu di chuyển này, sau đó chúng tôi sau đó di chuyển một phần của khoảng cách về phía target
được chỉ định bởi một sharpness
tham số.
Thông số này không còn là "tốc độ" nữa, bởi vì chúng tôi tiếp cận mục tiêu theo cách giống như Zeno . Nếu sharpnessPerTick
là vậy 0.5
, thì trong lần cập nhật đầu tiên, chúng ta sẽ đi được nửa đường đến mục tiêu của mình. Sau đó, trên bản cập nhật tiếp theo, chúng tôi sẽ di chuyển một nửa khoảng cách còn lại (vì vậy một phần tư khoảng cách ban đầu của chúng tôi). Sau đó, tiếp theo chúng ta sẽ di chuyển một nửa ...
Điều này mang lại "sự dễ dàng theo cấp số nhân" khi chuyển động nhanh khi cách xa mục tiêu và dần dần chậm lại khi nó tiếp cận một cách không có triệu chứng (mặc dù với số lượng chính xác vô hạn, nó sẽ không bao giờ đạt được nó trong bất kỳ số lượng cập nhật hữu hạn nào - vì mục đích của chúng tôi đủ gần). Thật tuyệt vời khi theo đuổi một giá trị mục tiêu di động hoặc làm mịn đầu vào nhiễu bằng cách sử dụng " trung bình di chuyển theo cấp số nhân ", thường sử dụng một sharpnessPerTick
tham số rất nhỏ như 0.1
hoặc nhỏ hơn.
Nhưng bạn đã đúng, có một lỗi trong câu trả lời nâng cao mà bạn liên kết. Nó không sửa cho deltaTime
đúng cách. Đây là một lỗi rất phổ biến khi sử dụng phong cách này Lerp
.
Kiểu đầu tiên Lerp
là tuyến tính, vì vậy chúng ta có thể điều chỉnh tuyến tính tốc độ bằng cách nhân với deltaTime
:
progress = Mathf.Clamp01(progress + speedPerSecond * Time.deltaTime);
// or progress = Mathf.Clamp01(progress + Time.deltaTime / durationSeconds);
current = Mathf.Lerp(start, end, progress);
Nhưng việc nới lỏng theo cấp số nhân của chúng tôi là phi tuyến tính , do đó, chỉ cần nhân sharpness
tham số của chúng tôi deltaTime
sẽ không đưa ra sự điều chỉnh thời gian chính xác. Điều này sẽ hiển thị như một sự rung chuyển trong chuyển động nếu tốc độ khung hình của chúng ta dao động, hoặc thay đổi độ sắc nét nới lỏng nếu bạn đi từ 30 đến 60 một cách nhất quán.
Thay vào đó, chúng ta cần áp dụng một sự điều chỉnh theo cấp số nhân để dễ dàng theo cấp số nhân:
blend = 1f - Mathf.Pow(1f - sharpness, Time.deltaTime * referenceFramerate);
current = Mathf.Lerp(current, target, blend);
Đây referenceFramerate
chỉ là một hằng số muốn 30
giữ các đơn vị sharpness
giống như chúng ta đã sử dụng trước khi sửa lỗi cho thời gian.
Có một lỗi khác có thể tranh cãi trong mã đó, đó là sử dụng Slerp
- phép nội suy tuyến tính hình cầu rất hữu ích khi chúng ta muốn có tốc độ quay chính xác nhất quán trong toàn bộ chuyển động. Nhưng nếu chúng ta sẽ sử dụng một sự dễ dàng theo cấp số nhân phi tuyến tính, Lerp
sẽ cho một kết quả gần như không thể phân biệt và nó rẻ hơn. ;) Đệ tứ lerp tốt hơn nhiều so với ma trận, vì vậy đây thường là sự thay thế an toàn.