Lerping işlevlerinde neden Time.deltaTime kullanılır?


12

Anladığım kadarıyla, bir Lerp işlevi iki değer ( ave ) arasında ve arasında büçüncü bir değer ( t) kullanarak enterpolasyon yapar . Konumunda , a değeri döndürülür , konumunda, değer döndürülür. 0,5 değerinde ve arasındaki değer döndürülür.01t = 0t = 1bab

(Aşağıdaki resim pürüzsüz, genellikle kübik enterpolasyondur)

resim açıklamasını buraya girin

Forumlara göz atıyorum ve bu cevap aşağıdaki kod satırını buldum:transform.rotation = Quaternion.Slerp(transform.rotation, _lookRotation, Time.deltaTime);

Kendi kendime, "ne bir aptal, hiçbir fikri yok" diye düşündüm ama 40+ upvotes olduğu için denedim ve yeterince eminim, işe yaradı!

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

Ben arasına rastgele değerler var 0.01ve 0.02için t. İşlev buna göre enterpolasyon yapmamalı mı? Bu değerler neden yığınlanıyor? Lerp ile ilgili anlamadığım şey nedir?


1
A genellikle konumdur, değişen ve bunun için 1/60 (60 fps) 'de örnekleme, A ve B arasındaki mesafeyi sürekli olarak daraltarak 0.16 enterpolasyonu ile nesneyi hareket ettirir (böylece örnek her seferinde daha küçük ve daha küçüktür).
Sidar

T ile oturum açtınız ve tt ... ile değiştirdiniz. Bunlar farklı değişkenlerdir.
user253751

Yanıtlar:


18

Ayrıca bu cevaba bakınız .

Kullanmanın iki yaygın yolu vardır Lerp:

1. Başlangıç ​​ve bitiş arasında doğrusal karıştırma

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

Bu muhtemelen en tanıdığınız sürümdür.

2. Hedefe doğru üstel kolaylık

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

Not Bu sürümde bu currentdeğer çıkışı hem olarak görünür ve bir girdi. Değişkeni değiştirir start, bu yüzden her zaman son güncellemeye taşındığımız yerden başlıyoruz. LerpBelleğin bu sürümünü bir kareden diğerine veren şey budur . Bu hareketli başlangıç ​​noktasından sonra, mesafenin bir kısmını targetbir sharpnessparametre tarafından dikte edilen yöne doğru hareket ettiririz .

Bu parametre artık bir "hız" değil, çünkü hedefe Zeno benzeri bir şekilde yaklaşıyoruz . Eğer sharpnessPerTickidi 0.5, daha sonra ilk güncelleme biz hedefimize yarıya taşımak istiyorum. Sonra bir sonraki güncellemede kalan mesafenin yarısını hareket ettiririz (başlangıç ​​mesafemizin dörtte biri). Sonra bir sonraki yarıyı tekrar hareket ettirirdik ...

Bu, hareketin hedeften uzak olduğunda hızlı olduğu ve asimptotik olarak yaklaştıkça kademeli olarak yavaşladığı "üstel bir rahatlık" verir (sonsuz hassasiyetli sayılarla hiçbir zaman sınırlı sayıda güncellemede ona ulaşmaz - bizim amacımız için) yeterince yakınlaşır). Hareketli bir hedef değeri kovalamak veya " üstel hareketli ortalama " kullanarak gürültülü bir girişi düzeltmek , genellikle çok küçük veya çok küçük bir sharpnessPerTickparametre kullanarak mükemmeldir 0.1.


Ama haklısın, yukarı doğru cevap verdiğiniz bağlantıda bir hata var. O için düzeltme değil deltaTimedoğru şekilde. Bu stili kullanırken çok yaygın bir hatadır Lerp.

İlk stili Lerpdoğrusaldır, bu nedenle hızı çarparak doğrusal olarak ayarlayabiliriz deltaTime:

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

Ancak üstel genişlememiz doğrusal değildir , bu nedenle sharpnessparametremizi çarpmak deltaTimedoğru zaman düzeltmesini vermeyecektir. Bu, kare hızımız dalgalanırsa harekette bir titreme veya 30'dan 60'a sürekli olarak giderseniz hareket hızı keskinliğinde bir değişiklik olarak görünecektir.

Bunun yerine, üstel kolaylığımız için üstel bir düzeltme uygulamamız gerekir:

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

Burada referenceFramerate, zaman düzeltmeden önce 30üniteleri kullandığımız gibi tutmak gibi bir sabit var sharpness.


Bu kodda başka bir tartışmalı hata daha var Slerp- küresel doğrusal enterpolasyon, tüm hareket boyunca tam olarak tutarlı bir dönüş hızı istediğimizde yararlıdır. Ama yine de doğrusal olmayan bir üstel kolaylık Lerpkullanacaksak, neredeyse ayırt edilemez bir sonuç verecektir ve daha ucuzdur. ;) Kuaterniyonlar matrislerden çok daha iyi ler, bu yüzden bu genellikle güvenli bir ikame.


1

Bence bu temel senaryoda eksik olan temel kavram sabit değildir. A her adımda güncellenir, ancak Time.deltaTime olan enterpolasyon boyunca güncellenir.

Böylece, A her adımda B'ye yaklaştıkça, enterpolasyonun toplam alanı her Lerp / Slerp çağrısıyla değişir. Gerçek matematiği yapmadan, efektin Smoothstep grafiğinizle aynı olmadığından şüphelenirim, ancak A'nın B'ye yaklaştıkça bir yavaşlamaya yaklaşmanın ucuz bir yoludur.

Ayrıca, B de statik olmayabileceğinden bu sıklıkla kullanılır. Tipik durum bir oynatıcıyı izleyen bir kamera olabilir. Fotoğraf makinesinin bir yere veya rotasyona atlamasını sağlayarak sarsıntıdan kaçınmak istersiniz.


1

Haklısınız, yöntem miktar Quaternion Slerp(Quaternion a, Quaternion b, float t)arasında ave arasında enterpolasyon yapar . Ama ilk değeri izleyin, başlangıç ​​değeri değil.bt

Burada yönteme verilen ilk değer, geçerli nesne dönüşüdür transform.rotation. Böylece, her kare için geçerli döndürme ve hedef döndürme _lookRotationarasında miktarla enterpolasyon yapar Time.deltaTime.

Bu yüzden düzgün bir dönüş üretir.


2
Şimdi salak gibi hissediyorum
AzulShiva

@AzulShiva Merak etmeyin herkese olur;)
Ludovic Feltz
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.