İki oyun durumu arasında nasıl İnterpolasyon Yapılır?


24

Tüm nesnelerin konumlarının iki güncelleme durumu arasında enterpolasyona gireceği bir sistem oluşturmak için en iyi kalıp hangisidir?

Güncelleme her zaman aynı frekansta çalışır, ancak herhangi bir FPS'de iş yapmak istiyorum. Bu nedenle, oluşturma, saniye başına kare ne olursa olsun, güncelleme sıklığından düşük veya yüksek olsun, mümkün olduğu kadar yumuşak olacaktır.

Mevcut kareden gelecek kareye kadar 1 kareyi gelecekteki enterpolasyonda güncellemek istiyorum. Bu cevabın bunu yapmaktan bahseden bir bağlantısı var:

Yarı sabit mi yoksa Tamamen sabit zaman aralığı mı?

Düzenleme: İnterpolasyondaki son ve mevcut hızı nasıl kullanabilirim? Örneğin, sadece doğrusal enterpolasyon ile, konumlar arasında aynı hızda hareket edecektir. İki nokta arasındaki konumu enterpolasyona sokacak bir yola ihtiyacım var, ancak enterpolasyon için her noktadaki hızı göz önünde bulundurmalıyım. Parçacık efektleri gibi düşük oranlı simülasyonlar için yardımcı olacaktır.


2
keneler mantık kene olmak? Yani güncelleme fps <render fps?
Komünist Ördek

Terimi değiştirdim. Ama evet mantık keneler. Ve hayır, oluşturma işlemini güncelleme işleminden tamamen kurtarmayı istiyorum, böylece oyun 120HZ veya 22.8Hz'de görüntüleyebilir ve kullanıcının sistem gereksinimlerini karşılaması koşuluyla güncelleme aynı hızda çalışır.
AttackHobo

bu durum gerçekten zor olabilir çünkü tüm nesne konumlarınızı oluştururken sabit kalmanız gerekir (oluşturma işlemi sırasında bunları değiştirmek bazı tanımsız davranışlara neden olabilir)
Ali1S232

İnterpolasyon, durumu zaten hesaplanmış 2 güncelleme karesi arasında hesaplar. Bu soru , son güncelleme çerçevesinden sonraki bir süre için durumu hesaplayan ekstrapolasyonla ilgili değil mi? Bir sonraki güncelleme henüz hesaplanmadı beri.
Maik Semder

Bence sadece bir iş parçacığı güncelleme / oluşturma işlemi varsa, sadece oluşturma pozisyonunu tekrar güncelleyemez. Siz sadece GPU’ya pozisyon gönderir ve ardından tekrar güncellenir.
zacharmarz

Yanıtlar:


22

Güncelleme (mantık kene) ayırmak ve (kene kene) oranları çizmek istersiniz.

Güncellemeleriniz, çizilecek dünyadaki tüm nesnelerin konumunu üretecektir.

Burada, talep ettiğiniz, ekstrapolasyon ve başka bir yöntem olan interpolasyon olmak üzere iki farklı olasılık ele alınacaktır.

1.

Ekstrapolasyon , nesnenin (öngörülen) konumunu bir sonraki karede hesaplayacağımız ve mevcut nesnelerin konumu ile nesnenin bir sonraki karede olacağı konum arasında enterpolasyon yapacağımız yerdir.

Bunu yapmak için, çizilecek her nesnenin ilişkilendirilmiş olması velocityveposition . Nesnenin bir velocity * draw_timestepsonraki karede olacağı konumu bulmak için, bir sonraki karenin öngörülen konumunu bulmak için sadece nesnenin o anki konumuna ekleriz . draw_timestepönceki render kene (yani önceki beraberlik çağrısı) beri geçen zaman miktarıdır.

Bunu burada bırakırsanız, öngörülen konumlarının bir sonraki karedeki gerçek konum ile uyuşmadığı durumlarda nesnelerin "titremeye" başladığını göreceksiniz. Titremeyi gidermek için, önceki güncellemeyi onaylamadan itibaren geçen süreyi lerp faktörü olarak geçen süreyi kullanarak, öngörülen pozisyonu saklayabilir ve önceden tahmin edilen pozisyon ile her çekme adımında öngörülen yeni pozisyon arasında lerp kullanabilirsiniz. Bu, hızlı hareket eden nesnelerin aniden yerini değiştirmesi durumunda kötü davranışa neden olur ve bu özel durumu ele almak isteyebilirsiniz. Bu paragrafta belirtilen her şey, sizin yok kullanımı ekstrapolasyon istiyorum.

2.

İnterpolasyon , son iki güncellemenin durumunu kaydettiğimiz ve güncellemeden bu yana geçen güncel süreyi temel alarak aralarındaki enterpolasyondur. Bu kurulumda, her nesnenin bir ilişkili positionve olması gerekir previous_position. Bu durumda, çizimimiz mevcut oyun ekranının arkasındaki en kötü güncelleme işaretini ve en iyi ihtimalle güncel güncelleme işaretiyle aynı durumda olacak.


Benim düşünceme göre, muhtemelen tanımladığım gibi enterpolasyon yapmak istiyorsunuz, çünkü ikisinin uygulaması daha kolay ve mevcut güncellenmiş durumunuzun ardında bir saniyenin (örneğin 1/60 saniye) küçük bir kısmını çizmek gayet iyi.


Düzenle:

Yukarıdakilerin bir uygulamayı gerçekleştirmenize izin vermemesi durumunda, burada tarif ettiğim interpolasyon yönteminin nasıl yapılacağına bir örnek. Ekstrapolasyonu ele almayacağım, çünkü tercih etmen gereken gerçek dünya senaryosunu düşünemiyorum.

Çizilebilir bir nesne oluşturduğunuzda, çizilmesi gereken özellikleri (yani çizmesi için gereken durum bilgisi) depolar .

Bu örnekte, pozisyon ve rotasyonu kaydedeceğiz. Ayrıca renk veya doku koordinat konumu gibi diğer özellikleri de depolamak isteyebilirsiniz (yani bir doku kayarsa).

Oluşturma iş parçacığı çizilirken verilerin değiştirilmesini önlemek için (yani, oluşturma iş parçacığı çizilirken bir nesnenin konumu değiştirildi, ancak diğerleri henüz güncellenmedi), bir tür çift tamponlama uygulamamız gerekiyor.

Bir nesne iki kopyasını saklar previous_state. Ben onları bir diziye koymak ve onlara bakın edecektir previous_state[0]ve previous_state[1]. Aynı şekilde iki kopyasına ihtiyacı varcurrent_state .

Çift tamponun hangi kopyasının state_indexkullanıldığını takip etmek için, hem güncelleme hem de iş parçacığı için mevcut olan bir değişken saklıyoruz.

Güncelleme iş parçacığı, öncelikle kendi verilerini (istediğiniz veri yapıları) kullanarak bir nesnenin tüm özelliklerini hesaplar. Sonra, bu kopyalar current_state[state_index]için previous_state[state_index], çizim için yeni veri alakalı ve kopyalar positionve rotationiçine current_state[state_index]. Daha sonra state_index = 1 - state_index, çift tamponun o anda kullanılan kopyasını çevirmek için yapar .

Yukarıdaki paragraftaki her şey kilitlenerek yapılmalıdır. current_state . Güncelleme ve çizme iplikleri bu kilidi çıkartır. Kilit, yalnızca hızlı olan durum bilgilerinin kopyalanması süresince alınmaktadır.

Render ipinde, daha sonra pozisyon ve rotasyonda doğrusal bir enterpolasyon yaparsınız:

current_position = Lerp(previous_state[state_index].position, current_state[state_index].position, elapsed/update_tick_length)

Nerede elapsedson güncelleme kene beri kılmak dizisindeki geçen zamanın miktarı ve update_tick_lengthSabit güncelleme oranı (örn 20fps güncellemelere, kene başına aldığı süredir update_tick_length = 0.05).

LerpYukarıdaki işlevin ne olduğunu bilmiyorsanız , konuyla ilgili wikipedia yazısını inceleyin: Linear Interpolation . Bununla birlikte, hangi gecikmenin ne olduğunu bilmiyorsanız, o zaman muhtemelen enterpolasyonlu çizim ile dekuplajlı güncelleme / çizim yapmaya hazır değilsiniz.


1
+1 aynı yönlerde / rotasyonlar ve diğer durumlar için yapılması gereken zaman içinde değişim, örneğin, parçacık sistemlerinin vb malzeme animasyon gibi
Maik Semder

1
İyi nokta Maik, sadece örnek olarak pozisyonu kullandım. Ekstrapolasyon kullanmak istiyorsanız, tahmin etmek istediğiniz herhangi bir özelliğin "hızını" (yani o mülkün zaman içindeki değişim oranını) kaydetmeniz gerekir. Sonunda, dış değerlemenin enterpolasyondan daha iyi olduğu bir durum düşünemiyorum, sadece sorucunun sorusu talep ettiği için dahil ettim. Enterpolasyon kullanıyorum. Enterpolasyon ile, enterpolasyon yapılacak herhangi bir özelliğin mevcut ve önceki güncelleme sonuçlarını, sizin dediğiniz gibi kaydetmemiz gerekir.
Olhovsky

Bu, sorunun düzeltilmesi ve enterpolasyon ile ekstrapolasyon arasındaki farktır; bu bir cevap değil.

1
Örneğimde durum ve dönme halini sakladım. Sadece hızı (ya da hızı) halihazırda da saklayabilirsiniz. Daha sonra aynı hızda aynı hızda ( Lerp(previous_speed, current_speed, elapsed/update_tick_length)). Bunu, durumunda saklamak istediğiniz herhangi bir numara ile yapabilirsiniz. Lerping sadece bir lp faktörü verilen iki değer arasında bir değer verir.
Olhovsky

1
Açısal hareketin enterpolasyonu için lerp yerine slerp kullanılması önerilir. En kolayı, her iki devletin kuaterniyonlarını depolamak ve aralarındaki slerp olmaktır. Aksi takdirde, aynı kurallar açısal hız ve açısal hızlanma için de geçerlidir. İskelet animasyonu için bir test vakanız var mı?
Maik Semder

-2

Bu problem başlangıç ​​ve bitiş tanımlarınızı biraz farklı düşünmenizi gerektirir. Başlangıçta programcılar genellikle çerçeve başına pozisyondaki değişimi düşünürler ve bu başlangıçtan başlamak için iyi bir yoldur. Cevabım uğruna, tek boyutlu bir cevabı düşünelim.

Diyelim ki x konumunda bir maymunun var. Şimdi ayrıca klavyeye veya başka bir kontrole bağlı olarak maymun başına kare başına eklediğiniz bir "addX" de var. Bu, garantili bir kare hızına sahip olduğunuz sürece çalışacaktır. Diyelim ki x'iniz 100'dür ve addX'iniz 10'dur. 10 kareden sonra, x + = addX'iniz 200'e çıkmalıdır.

Şimdi, addX yerine, değişken bir kare hızına sahip olduğunuzda, hız ve ivme açısından düşünmelisiniz. Tüm bu aritmetikte size yol göstereceğim ama bu çok basit. Bilmek istediğimiz şey, milisaniye başına ne kadar seyahat etmek istediğiniz (saniyenin 1 / 1000'i).

30 FPS için çekim yapıyorsanız, velX'iniz saniyenin 1 / 3'ü olmalıdır (30 FPS'deki son örnekten 10 kare) ve o sırada 100 'x' seyahat etmek istediğinizi biliyorsunuzdur; 100 mesafe / 10 FPS veya çerçeve başına 10 mesafe. Milisaniyede, bu 3.3 milisaniyede 1 x x veya milisaniyede 0.3 'x' olur.

Şimdi, her güncellediğinizde, yapmanız gereken tek şey geçen süreyi bulmak. 33 ms geçerse (saniyenin 1 / 30'u) veya her neyse, sadece 0.3 mesafesini geçen milisaniye sayısı ile çarpın. Bu, size ms (milisaniye) doğruluk kazandıran bir zamanlayıcıya ihtiyaç duyduğunuz anlamına gelir, ancak çoğu zamanlayıcı size bunu verir. Basitçe böyle bir şey yapın:

var beginTime = getTimeInMillisecond ()

... sonra ...

var time = getTimeInMillisecond ()

var elapsedTime = time-beginTime

beginTime = time

... şimdi tüm mesafelerinizi hesaplamak için bu geçen süreyi kullanın.


1
Değişken güncelleme oranına sahip değil. Sabit bir güncelleme oranı var. Dürüst olmak gerekirse, burada ne yapmaya çalıştığınızı gerçekten bilmiyorum: /
Olhovsky

1
??? -1. Tüm mesele bu, garantili bir güncelleme oranım var, ancak değişken bir oluşturma oranı var ve kekemelik yapmadan pürüzsüz olmasını istiyorum.
AttackHobo

Değişken güncelleme oranları ağa bağlı oyunlar, rekabetçi oyunlar, yeniden oynatma sistemleri veya oyun oynamayı belirleyici kılan herhangi bir şeyle iyi çalışmaz.
AttackHobo

1
Sabit güncelleme, sözde sürtünmenin kolay entegrasyonuna da izin verir. Örneğin, hızınızı her karede 0,9 ile çarpmak istiyorsanız, hızlı veya yavaş bir kareniz varsa, ne kadar çarpmanız gerektiğini nasıl anlarsınız? Sabit güncelleme bazen çok tercih edilir - neredeyse tüm fizik simülasyonları sabit güncelleme oranı kullanır.
Olhovsky

2
Değişken kare hızı kullandıysam ve birbirinden sıçrayan çok sayıda nesneyle karmaşık bir başlangıç ​​durumu ayarladıysam, tamamen aynı şekilde takılacağının garantisi de yok. Aslında, büyük olasılıkla, her seferinde biraz farklı şekilde, başlangıçta küçük farklarla birlikte, kısa bir sürede her simülasyon çalışması arasında tamamen farklı durumlara bileşik oluşturacak.
SaldıranHobo
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.