Mengapa menggunakan Time.deltaTime dalam fungsi Lerping?

12

Untuk pemahaman saya, fungsi Lerp interpolasi antara dua nilai ( adan b) menggunakan nilai ketiga ( t) antara 0dan 1. Di t = 0, nilai a dikembalikan, at t = 1, nilai bdikembalikan. Nilai 0,5 di tengah jalan adan bdikembalikan.

(Gambar berikut adalah langkah mulus, biasanya interpolasi kubik)

masukkan deskripsi gambar di sini

Saya telah menjelajahi forum dan pada jawaban ini saya menemukan baris kode berikut:transform.rotation = Quaternion.Slerp(transform.rotation, _lookRotation, Time.deltaTime);

Saya berpikir dalam hati, "bodoh sekali, dia tidak tahu" tetapi karena ada 40+ peningkatan, saya mencobanya dan cukup yakin, itu berhasil!

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

Saya mendapat nilai acak antara 0.01dan 0.02untuk t. Bukankah seharusnya fungsi interpolasi sesuai? Mengapa nilai-nilai ini menumpuk? Ada apa dengan lerp yang tidak saya mengerti?

AzulShiva
sumber
1
Posisi A biasanya, yang berubah dan untuk itu pengambilan sampel pada 1/60 (60 fps) hanya akan memindahkan objek dengan interpolasi 0,16 terus-menerus mempersempit jarak antara A dan B (dengan demikian sampel lebih kecil dan lebih kecil setiap kali).
Sidar
Anda login t dan lerped dengan tt ... itu adalah variabel yang berbeda.
user253751

Jawaban:

18

Lihat juga jawaban ini .

Ada dua cara umum untuk digunakan Lerp:

1. Pencampuran linier antara awal dan akhir

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

Ini adalah versi yang mungkin paling Anda kenal.

2. Kemudahan eksponensial menuju target

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

Perhatikan bahwa dalam versi ini currentnilai muncul sebagai output dan input. Itu menggeser startvariabel, jadi kami selalu mulai dari mana pun kami pindah ke pada pembaruan terakhir. Inilah yang memberikan versi Lerpmemori ini dari satu frame ke yang berikutnya. Dari titik awal yang bergerak ini, kami kemudian memindahkan sebagian kecil dari jarak ke arah yang targetditentukan oleh sharpnessparameter.

Parameter ini bukan "kecepatan" lagi, karena kami mendekati target dengan cara yang mirip Zeno . Jika sharpnessPerTickberada 0.5, maka pada update pertama kami akan pindah setengah jalan untuk tujuan kami. Kemudian pada pembaruan berikutnya kami akan memindahkan setengah jarak yang tersisa (jadi seperempat dari jarak awal kami). Kemudian pada berikutnya kita akan bergerak setengah lagi ...

Ini memberikan "pelonggaran eksponensial" di mana gerakannya cepat ketika jauh dari target dan secara bertahap melambat ketika mendekati asimtotik (meskipun dengan angka presisi tak terbatas, ia tidak akan pernah mencapainya dalam jumlah pembaruan terbatas - untuk keperluan kami, cukup dekat). Ini bagus untuk mengejar nilai target bergerak, atau menghaluskan input berisik menggunakan " moving average eksponensial ," biasanya menggunakan sharpnessPerTickparameter yang sangat kecil suka 0.1atau lebih kecil.


Tapi Anda benar, ada kesalahan dalam jawaban yang Anda jawab tautannya. Itu tidak mengoreksi deltaTimedengan cara yang benar. Ini adalah kesalahan yang sangat umum ketika menggunakan gaya Lerp.

Gaya pertama Lerpadalah linear, jadi kami dapat menyesuaikan kecepatan secara linear dengan mengalikannya dengan deltaTime:

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

Tapi pelonggaran eksponensial kami adalah non-linear , jadi hanya mengalikan sharpnessparameter kami dengan deltaTimetidak akan memberikan koreksi waktu yang benar. Ini akan muncul sebagai juri dalam gerakan jika framerate kami berfluktuasi, atau perubahan dalam ketajaman pelonggaran jika Anda beralih dari 30 menjadi 60 secara konsisten.

Sebaliknya kita perlu menerapkan koreksi eksponensial untuk kemudahan eksponensial kita:

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

Berikut referenceFramerateini adalah konstanta yang ingin 30menjaga unit tetap sharpnesssama seperti yang kami gunakan sebelum mengoreksi waktu.


Ada satu kesalahan lain yang bisa diperdebatkan dalam kode itu, yang menggunakan Slerp- interpolasi linear bola berguna ketika kita menginginkan tingkat rotasi yang persis konsisten melalui seluruh gerakan. Tetapi jika kita akan menggunakan kemudahan eksponensial non-linear, Lerpakan memberikan hasil yang hampir tidak dapat dibedakan dan lebih murah. ;) Kuotaerner lebih baik daripada matriks, jadi ini biasanya pengganti yang aman.

DMGregory
sumber
1

Saya pikir konsep inti yang hilang dalam skenario ini A tidak diperbaiki. A diperbarui dengan setiap langkah, sejauh interpolasi Time.deltaTime.

Jadi, dengan semakin dekat ke B dengan setiap langkah, total ruang interpolasi berubah dengan setiap panggilan Lerp / Slerp. Tanpa melakukan matematika yang sebenarnya, saya menduga bahwa efeknya tidak sama dengan grafik Smoothstep Anda, tetapi merupakan cara murah untuk memperkirakan deselerasi karena A semakin mendekati B.

Juga, ini sering digunakan karena B mungkin juga tidak statis. Kasing yang umum adalah kamera mengikuti pemain. Anda ingin menghindari jerkiness, membuat kamera melompat ke lokasi atau rotasi.

Chris
sumber
1

Anda benar, metode ini Quaternion Slerp(Quaternion a, Quaternion b, float t)menginterpolasi antara adan bdengan jumlah t. Tapi perhatikan nilai pertama, itu bukan nilai awal.

Di sini nilai pertama yang diberikan pada metode ini adalah rotasi objek saat ini transform.rotation. Jadi untuk setiap frame itu interpolasi antara rotasi saat ini dan rotasi target _lookRotationdengan jumlah Time.deltaTime.

Itu sebabnya ia menghasilkan rotasi yang halus.

Ludovic Feltz
sumber
2
Sekarang saya merasa seperti orang idiot
AzulShiva
@AzulShiva Jangan khawatir hal itu terjadi pada semua orang;)
Ludovic Feltz