İki hareketli AABB'nin kesişip kesişmediğini kontrol etmenin en hızlı yolu nedir?


12

Hareket eden iki AABB'm var, bir çerçeve altında kesişip kesişmeyeceklerini kontrol etmenin en hızlı yolu nedir?

Hareket ettirerek, sadece normal dikdörtgen kavşak yöntemiyle kontrol etmekle kalmayıp, sadece bir boolean döndüren, isabet süresi veya başka bir şey döndüren bir tür basit kolay süpürme testi demek istiyorum.

Bence sadece böyle yapmak:

Bu

Ama bu Altıgen oldukça karmaşık ve AABB - Poligon kavşağının nasıl hesaplanacağını bilmiyorum, belki daha kolay bir yol var mı?

En sevdiğiniz herhangi bir programlama dili, kolayca bağlantı kurabilirim.

Teşekkürler.


3
Kafam karıştı. Özellikle "süpürüp testi" den bahsediyorsunuz, tipik AABB süpürme testini denediniz mi? Tam olarak ne istersen yapar.
SomeWritesReserved

1
Yukarıdaki yoruma katılıyorum - "klasik" testte sorun nedir? Ayrıca, burada önerilen çözümlerin çoğu açıkça daha yavaştır ... artı bazıları yanlış sonuçlar verebilir (sağlam değil).
wondra

Yanıtlar:


8

Minkowski toplamını kullanma

Bu sorunu çözmek için iyi bir yol, bir hareket hattı arasında kesişim dikkate etmektir ( V ) başlangıç konumuna (çevrilmiş V ' ) ve Minkowsky toplamı ve A başlangıç konumuna (180 derece döndürülmüş bir' ) ve bunun engeller (sadece B Bu durumda): A'B .

Aşağıdaki resimde keyfi bir koordinat sisteminin kökenine bir şaplak takıyorum. Bu, A'nın 180 derece döndürülmesi ile anlaşılmayı kolaylaştırır, A 'ile sonuçlanır ve v , kökenine çevrilen v' e eşittir ' .

Minkowski toplamı yeşil dikdörtgendir ve hareketli A ile sabit B'nin kesişim noktaları, çizgi AABB kesişimini yaparak bulunabilir . Bu noktalar mavi dairelerle işaretlenmiştir.

Minkowski Sum - Dejenere Olgu

Aşağıdaki resimde farklı bir başlangıç ​​noktası kullanılmış ve aynı kesişim noktaları bulunmuştur.

Minkowski toplamı - daha genel durum

Çok hareketli AABB'ler

Bu işi belirli bir süre boyunca doğrusal bir şekilde hareket eden iki AABB için yapmak için B'nin hız vektörünü A'nın hız vektöründen çıkarır ve bunu AABB kesişimi için çizgi parçası olarak kullanırsınız.

Sahte kod

def normalize(aabb):
    return {x1: min(aabb.x1, aabb.x2), x2: max(aabb.x1, aabb.x2),
            y1: min(aabb.y1, aabb.y2), y2: max(aabb.y1, aabb.y2),

def rotate_about_origin(aabb):
    return normalize({x1: -aabb.x1, x2: -aabb.x2
                      y1: -aabb.y1, y2: -aabb.y2})

# given normalized aabb's
def minkowski_sum(aabb1, aabb2):
    return {x1: aabb1.x1+aabb2.x1, x2: aabb1.x2+aabb2.x2,
            y1: aabb1.y1+aabb2.y1, y2: aabb1.y2+aabb2.y2}

def get_line_segment_from_origin(v):
    return {x1: 0, y1: 0, x2: v.x, y2: v.y}

def moving_objects_with_aabb_intersection(object1, object2):
    A = object1.get_aabb()
    B = object2.get_aabb()

    # get A'⊕B
    rotated_A = rotate_about_origin(A)
    sum_aabb = minkowski_sum(rotated_A, B)

    # get v'
    total_relative_velocity = vector_subtract(object1.get_relative_velocity(), object2.get_relative_velocity())
    line_segment = get_line_segment_from_origin(total_relative_velocity)

    # call your favorite line clipping algorithm
    return line_aabb_intersection(line_segment, sum_aabb)

Çarpışma yanıtı

Oyuna bağlı olarak, daha ince taneli çarpışma algılaması (belki AABB'lerde ağlar içerebilir) veya bir sonraki aşamaya geçersiniz: çarpışma yanıtı.

Bir çarpışma olduğunda, AABB kesişme algoritması, A'nın B içindeki hareketini bitip bitmediğine veya içinden geçip geçmediğine bağlı olarak 1 veya 2 kesişme noktası döndürür. (Bu, A'nın B'yi kendi kenarları boyunca veya ilgili köşelerinden biri boyunca sıyırdığı dejenere vakaları iskonto ediyor.)

Her iki durumda da doğru parçasının boyunca ilk kesişim noktası çarpışma noktası, dünyanın doğru konuma koordinat sistemi için bu geri (orijinal boyunca ikinci resimde ilk açık mavi daire çevirmek istiyorum v , diyoruz p ) ve daha sonra (karar örneğin, yansıtarak elastik çarpışmalar v normal çarpışma boyunca p gerçek konumu hangi) A çerçevenin sonunda (olacaktır + 1 'de ).

Çarpışma yanıtı

2'den fazla çarpıştırıcı varsa, v'nin ikinci, yansıyan kısmı için çarpışma algılama yapmak istediğiniz için bu biraz daha karmaşık hale gelecektir .


Teşekkürler, en ilginç. A ve B hareket sırasında kesiştiği, ancak kesişme olmadan hareketi bitirdiğinde durumu nasıl ele aldığınızı açıklar mısınız?
GameAlchemist

@GameAlchemist Bu çarpışma yanıtıdır ve çok fazla çarpışma tespiti olmaz (sorunun asıl konusu). Ama Paint'i seviyorum, bu yüzden düzenlemeye göz atın. :-)
Eric

Güncelleme için teşekkürler (ve şemalar için hurra :-)), bu benim sorum değildi ama A'nın B'den tamamen geçtiğinde algoritmanızın zaten davayı ele aldığını anlamama yardımcı oldu
GameAlchemist

5

OBB - Yönlendirilmiş sınırlayıcı kutu. İşte bir eğitim

Etkili bir şekilde, A nesnesinin Hız ekseni ile y ekseni (yukarı) olarak hizalanan bir sınırlama kutusu. Genişliği ve yüksekliği, A nesnesinin başlangıç ​​ve bitiş noktaları ile hesaplanabilir. Ardından bunu B nesnesinin AABB'si (OOBB olarak kabul edilir) ve altın ile karşılaştırırsınız.

Sadece kesişebildikleri takdirde hızlı bir kavşak testi arıyorsanız, A'nın AABB nesnesini hem başlangıç ​​hem de bitiş konumlarında çevreleyen bir AABB oluşturabilirsiniz. Bir AABB, tüm bunları kapsayan AABB ile kesişmiyorsa, kesişme olmaz; Bununla birlikte, bu yanlış pozitiflere yol açabilir, bu yüzden bunu sadece bir ön test olarak kullanmalısınız.


4

OOB'lara ihtiyacınız yoktur ve zaman atlama çarpışma algılaması kullanmanız gerekmez. Sadece normal AABB süpürme testini kullanın , bu bağlantıya bakın . Temel olarak şemanızda tam olarak ne yapar: hareketli AABB başlangıç ​​noktasından bitiş noktasına "süpürülür" ve daha sonra diğer statik AABB'lere karşı çarpışma tespiti için kullanılır.

Bu süpürme testinin "etki süresi" döndürdüğü için daha pahalı olduğundan endişeleniyorsanız, bence erken optimizasyon yaptığınızı düşünüyorum.

Süpürülen testler hakkında daha ayrıntılı bilgi mükemmel kitapta bulunabilir: Christer Ericson tarafından Gerçek Zamanlı Çarpışma Tespiti .


3

AABB yaklaşık uç durumu zayıflığı

Öncelikle hareketi daha küçük adımlara ayırmanız ve bu bilgileri yüksek seviyeli bir AABB'yi hesaplamak için kullanmanız gerekir. Büyük AABB'nin kesişmesi durumunda, daha doğru olmak için daha küçük adımları kontrol edebilirsiniz.

Yalnızca başlangıç ​​ve bitiş konumlarını kullanarak AABB'yi (veya OOBB) kontrol ederek bir çarpışma olup olmadığını tahmin etmek, herhangi bir nesne hızlı bir şekilde dönüyorsa ve bir boyutta diğerinden daha uzunsa çarpışmaları kaçırabilir.

Daha doğru bir tahmin AABB hesaplamak için, hareketi daha küçük adımlara ayrıştırın ve yalnızca ilk AABB'yi (nesne ağı değil) kullanarak, nesne her biri döneceği ve hareket edeceği için AABB'yi (şimdi yalnızca eksenli değil, bir kutu) döndürün adım. Her eksen için maksimum ve min noktaları, nesnenin tüm hareketini kapsayan AABB'yi verecektir.

Daha büyük AABB ile bir kavşak varsa, çarpışmanın nerede olabileceğini belirlemek için zaten hesaplanmış olan daha küçük AABB'leri kullanabilirsiniz. Diğer nesneyle kesişen küçük AABB'lerin her biri için, daha pahalı kafes kavşak algılamasını yapabilirsiniz.


2
veya herhangi bir rotasyon için BB'nin maksimum genişliğini önceden hesaplayın ve bunu kullanın
cırcır ucube

2

Hareketi daha küçük hareket adımlarına parçalamanız gerekir. Örneğin:

Hareketi daha büyük bileşenleri (bu durumda X ekseni) kullanarak ayrıştırmak ve ardından her adımda çarpışma olup olmadığını kontrol etmek istersiniz.

Bu çok pahalı görünebilir, ancak her döngüden kendi genişliğinden daha hızlı hareket eden bir nesnenin ÇOK hızlı olacağını göz önünde bulundurun, bu nedenle bu senaryo ilk düşündüğünüz kadar yaygın değildir.


2
Bu yöntem kötüdür, çünkü bazı vakaları yakalamayacaktır (örneğin, birinciye ve çizdiğiniz ikinci kutuya yakın olmak) ve artan örnekleme aşırıya kaçacaktır. SAT kullanarak basit çokgen testi yeterince hızlı ve güvenilir olmalıdır.
Sopel

1
Evet, bu iyi bir çözüm ama çok büyük değil. Çarpışma, nesnelerin köşelerine yaklaştığında doğruluk hızla azalır, hız arttıkça performans düşer (veya uygulamaya bağlı olarak doğruluk) ve sadece gereksiz bir şekilde hacky olur.
BWG

2

Çarpışma kontrolü için göreli hızları da kullanmalısınız, böylece bir AABB "statik" ve diğeri kendi hızındaki bir hızda eksi "statik" olanın hızı.

Onlar eğer hızlı yolu görmek may kesiştiği sadece hız ile hareket eden AABB genişletmektir.

örneğin AABB 0,1 x / kare ile sağa hareket eder, ardından sol kenar aynı kalacak ve sağ kenar 0,1 daha ileri olacak şekilde uzatırsınız. Ardından yeni AABB ile kontrol edebilirsiniz. Eğer yanlışsa, çarpışma olmaz. (erken dönüş ve küçük hızlar için doğru).

Ardından hareketli nesnenin bitiş ve başlangıç ​​AABB'sinin kesişip kesişmediğini kontrol edebilirsiniz. true ise true değerini döndürür.

Aksi takdirde, diyagonalin statik ABB ile kesişip kesişmediğini kontrol etmeniz gerekir.

Bu, diyagonal koordinatların alınmasını içerir; burada x = statikin sol kenarı ve sağ kenar, y'nin altta ve üstte olup olmadığını görür. (tersini tekrarlayın)

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.