ทำไมต้องใช้ Time.deltaTime ในฟังก์ชั่น Lerping


12

เพื่อความเข้าใจของฉัน, ฟังก์ชั่น Lerp สอดแทรกระหว่างสองค่า ( aและb) โดยใช้ค่าที่สาม ( t) ระหว่างและ0 1ที่t = 0ค่า a ถูกส่งคืน at ที่t = 1ค่าbจะถูกส่งคืน ที่ 0.5 ค่าครึ่งทางระหว่างaและbจะถูกส่งกลับ

(ภาพต่อไปนี้เป็นแบบสเต็ปสเตปซึ่งมักจะเป็นการแก้ไขแบบลูกบาศก์)

ป้อนคำอธิบายรูปภาพที่นี่

ฉันได้ดูฟอรัมและคำตอบนี้ฉันพบบรรทัดของรหัสต่อไปนี้:transform.rotation = Quaternion.Slerp(transform.rotation, _lookRotation, Time.deltaTime);

ฉันคิดกับตัวเองว่า "เป็นคนโง่เขาไม่มีความคิดอะไรเลย" แต่เนื่องจากมีผู้โหวตมากกว่า 40+ ครั้งฉันจึงได้ลองและแน่นอนว่ามันใช้ได้ดี!

float t = Time.deltaTime;
transform.rotation = Quaternion.Slerp(transform.rotation, toRotation, t);
Debug.Log(t);

ผมได้รับค่าสุ่มระหว่าง0.01และสำหรับ0.02 tฟังก์ชั่นไม่ควรแก้ไขตามหรือไม่ ทำไมค่าเหล่านี้สแต็ก มันเกี่ยวกับ lerp อะไรที่ฉันไม่เข้าใจ?


1
A คือตำแหน่งปกติซึ่งการเปลี่ยนแปลงและการสุ่มตัวอย่างที่ 1/60 (60 fps) จะย้ายวัตถุโดยการแก้ไขที่ 0.16 ทำให้ระยะห่างระหว่าง A และ B แคบลงเรื่อย ๆ (ดังนั้นตัวอย่างจะเล็กลงและเล็กลงในแต่ละครั้ง)
Sidar

คุณเข้าสู่ระบบ t และ lerped ด้วย tt ... นั่นคือตัวแปรที่แตกต่างกัน
user253751

คำตอบ:


18

ดูคำตอบนี้ด้วย

มีวิธีการทั่วไปสองวิธีในการใช้Lerp:

1. การผสมเชิงเส้นระหว่างจุดเริ่มต้นและจุดสิ้นสุด

progress = Mathf.Clamp01(progress + speedPerTick);
current = Mathf.Lerp(start, end, progress);

นี่เป็นรุ่นที่คุณคุ้นเคยมากที่สุด

2. ความง่ายในการอธิบายต่อเป้าหมาย

current = Mathf.Lerp(current, target, sharpnessPerTick);

โปรดทราบว่าในรุ่นนี้currentค่าจะปรากฏเป็นทั้งเอาต์พุตและอินพุต มันแทนที่startตัวแปรดังนั้นเราจึงเริ่มต้นจากทุกที่ที่เราย้ายไปยังการปรับปรุงล่าสุด นี่คือสิ่งที่ให้Lerpหน่วยความจำรุ่นนี้จากเฟรมหนึ่งไปอีกเฟรมหนึ่ง จากนี้ย้ายจุดเริ่มต้นเราแล้วจากนั้นย้ายส่วนของระยะทางที่ไปทางtargetdictated โดยsharpnessพารามิเตอร์

พารามิเตอร์นี้ไม่มาก "ความเร็ว" อีกต่อไปเพราะเราเข้าใกล้เป้าหมายในนักปราชญ์เหมือนแฟชั่น ถ้าsharpnessPerTickเป็น0.5เช่นนั้นในการอัปเดตครั้งแรกเราจะย้ายไปครึ่งทางเพื่อบรรลุเป้าหมายของเรา จากนั้นในการอัพเดทครั้งต่อไปเราจะเลื่อนระยะทางที่เหลืออีกครึ่งหนึ่ง (ดังนั้นหนึ่งในสี่ของระยะทางเริ่มต้นของเรา) จากนั้นเราก็จะย้ายอีกครึ่งหนึ่ง ...

สิ่งนี้จะช่วยให้ "ความง่ายในการอธิบาย" ซึ่งการเคลื่อนที่นั้นรวดเร็วเมื่ออยู่ห่างจากเป้าหมายและค่อยๆช้าลงเมื่อเข้าใกล้ asymptotically (แม้ว่าจะมีจำนวนความแม่นยำที่ไม่มีที่สิ้นสุด เข้าใกล้พอ) มันยอดเยี่ยมสำหรับการไล่ล่าค่าเป้าหมายที่เคลื่อนไหวหรือการป้อนข้อมูลที่มีเสียงรบกวนให้เรียบโดยใช้ " ค่าเฉลี่ยเคลื่อนที่แบบเอ็กซ์โปเนนเชียล" โดยปกติจะใช้sharpnessPerTickพารามิเตอร์ขนาดเล็กมากเช่น0.1หรือเล็กกว่า


แต่คุณพูดถูกมีข้อผิดพลาดในลิงค์ upvote ที่คุณตอบ มันไม่ถูกต้องสำหรับdeltaTimeวิธีที่ถูกต้อง นี่เป็นข้อผิดพลาดทั่วไปมากเมื่อใช้รูปแบบLerpนี้

รูปแบบแรกของLerpคือเชิงเส้นดังนั้นเราจึงสามารถปรับความเร็วเชิงเส้นได้โดยการคูณด้วยdeltaTime:

progress = Mathf.Clamp01(progress + speedPerSecond * Time.deltaTime);
// or progress = Mathf.Clamp01(progress + Time.deltaTime / durationSeconds);
current = Mathf.Lerp(start, end, progress);

แต่การผ่อนคลายแบบเอ็กซ์โปเนนเชียลของเราไม่ใช่แบบเชิงเส้นดังนั้นเพียงแค่คูณsharpnessพารามิเตอร์ของเราด้วยdeltaTimeจะไม่ทำให้การแก้ไขเวลาถูกต้อง สิ่งนี้จะปรากฏเป็นผู้ตัดสินในการเคลื่อนไหวหากอัตราเฟรมของเราผันผวนหรือการเปลี่ยนแปลงของความคมชัดที่ผ่อนคลายหากคุณเปลี่ยนจาก 30 เป็น 60 อย่างสม่ำเสมอ

แต่เราจำเป็นต้องใช้การแก้ไขเลขชี้กำลังสำหรับความง่ายในการอธิบายของเรา:

blend = 1f - Mathf.Pow(1f - sharpness, Time.deltaTime * referenceFramerate);
current = Mathf.Lerp(current, target, blend);

นี่referenceFramerateเป็นเพียงค่าคงที่ที่ต้องการ30เก็บหน่วยให้sharpnessเหมือนกับที่เราใช้ก่อนที่จะแก้ไขเวลา


มีข้อผิดพลาดที่พิสูจน์ได้อีกข้อหนึ่งในรหัสนั้นซึ่งใช้Slerp- การแก้ไขเชิงเส้นทรงกลมมีประโยชน์เมื่อเราต้องการอัตราการหมุนที่สอดคล้องกันตลอดการเคลื่อนไหวทั้งหมด แต่ถ้าเราจะใช้การแจกแจงแบบไม่เป็นเชิงเส้นตรงนั้นLerpจะให้ผลที่ไม่สามารถแยกแยะได้และมันก็ถูกกว่า ;) Quaternions lerp ดีกว่าเมทริกซ์ทำดังนั้นนี่จึงเป็นการทดแทนที่ปลอดภัย


1

ฉันคิดว่าแนวคิดหลักที่ขาดหายไปจะอยู่ในสถานการณ์จำลอง A นี้ไม่ได้รับการแก้ไข A ได้รับการอัปเดตในแต่ละขั้นตอนอย่างไรก็ตามตามการแก้ไขที่ Time.deltaTime มาก

ดังนั้นเมื่อ A ใกล้ถึง B ในแต่ละขั้นตอนพื้นที่ทั้งหมดของการแก้ไขจะเปลี่ยนไปด้วยการโทร Lerp / Slerp แต่ละครั้ง โดยไม่ต้องทำคณิตศาสตร์จริงฉันสงสัยว่าเอฟเฟกต์จะไม่เหมือนกับกราฟ Smoothstep ของคุณ แต่เป็นวิธีที่ถูกกว่าในการประมาณการชะลอตัวเมื่อ A เข้าใกล้ B.

นอกจากนี้มักใช้เนื่องจาก B อาจไม่คงที่เช่นกัน กรณีทั่วไปอาจเป็นกล้องที่ติดตามผู้เล่น คุณต้องการหลีกเลี่ยงการกระตุกโดยให้กล้องกระโดดไปยังตำแหน่งหรือการหมุน


1

คุณมีสิทธิวิธีการQuaternion Slerp(Quaternion a, Quaternion b, float t)สอดแทรกระหว่างaและโดยจำนวนเงินที่b tแต่ดูค่าแรกมันไม่ใช่ค่าเริ่มต้น

transform.rotationนี่คือค่าแรกที่กำหนดให้วิธีการหมุนวัตถุปัจจุบัน ดังนั้นสำหรับแต่ละกรอบมันสอดแทรกระหว่างหมุนในปัจจุบันและการหมุนเป้าหมายตามจำนวนของ_lookRotationTime.deltaTime

นั่นคือเหตุผลที่ทำให้เกิดการหมุนที่ราบรื่น


2
ตอนนี้ฉันรู้สึกเหมือนคนโง่
AzulShiva

@AzulShiva ไม่ต้องกังวลว่าจะเกิดขึ้นกับทุกคน;)
Ludovic Feltz
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.