Yarıçap içindeki tüm varlıkları nasıl verimli bir şekilde bulabilirim?


14

Çok fazla sayıda varlığım (birimlerim) var. Her adımda, her birimin yakınındaki tüm birimlerin konumlarını bilmesi gerekir (mesafe, R sabitinden daha azdır ). Tüm birimler sürekli hareket eder. Bu 3D.

Ortalama olarak, verilen kısıtlamalara sahip herhangi bir diğer birimin yanında toplam birim sayısının% 1'i olacaktır.

Bruteforcing olmadan bunu nasıl verimli bir şekilde yapabilirim?


7
Bir çeşit
uzaysal

Yanıtlar:


15

Quadtree, Octree, BSP ağacı ve hatta basit bir Izgara Sistemi gibi ortak alan bölümleme algoritmalarından birini kullanın. Her bir senaryo için her birinin kendi artıları ve eksileri vardır. Bu kitaplarda onlar hakkında daha fazla bilgi edinebilirsiniz .

Genel olarak (ya da duydum, bunun arkasındaki gerekçeye çok aşina değilim), bir Quadtree veya Octree dış ortamlar için daha uygun, BSP ağacı iç mekan sahnelerine daha iyi uyuyor. Ve Quadtree veya Octree kullanmak arasındaki seçim, dünyanızın ne kadar düz olduğuna bağlıdır. Y ekseninde bir Octree kullanarak çok az değişiklik varsa israf edersiniz. Bir Octree temel olarak ek bir boyuta sahip bir Quadtree'dir.

Son olarak, Izgara çözümünün basitliğini göz ardı etmeyin. Birçok insan, problemleri için basit bir ızgaranın bazen yeterli (ve hatta daha verimli) olabileceğini görmezden gelir ve bunun yerine doğrudan daha karmaşık bir çözüme atlar.

Bir ızgara kullanmak, sadece dünyayı eşit aralıklı bölgelere bölmek ve varlıkları dünyanın uygun bölgesinde depolamaktan ibarettir. Daha sonra, bir pozisyon verildiğinde, komşu varlıkları bulmak, arama yarıçapınızla kesişen bölgeler üzerinde tekrarlama meselesi olacaktır.

Diyelim ki dünyanız XZ düzleminde (-1000, -1000) ile (1000, 1000) arasında değişiyor. Örneğin, 10x10 ızgaraya bölebilirsiniz, şöyle:

var grid = new List<Entity>[10, 10];

Sonra varlıkları ızgaradaki uygun hücrelere yerleştirirsiniz. Örneğin, XZ (-1000, -1000) olan bir varlık (0,0) hücresine, XZ (1000, 1000) olan bir varlık ise hücrenin (9, 9) üzerine düşer. Daha sonra dünyadaki bir konum ve yarıçap verildiğinde, bu "daire" ile hangi hücrelerin kesiştiğini belirleyebilir ve sadece bunların üzerinde basit bir çift ile yineleyebilirsiniz.

Her neyse, tüm alternatifleri araştırın ve oyununuza daha uygun olanı seçin. Hangi algoritmaların sizin için en iyi olacağına karar verecek konuda hala yeterince bilgili olmadığımı itiraf ediyorum.

Düzenle Bunu başka bir forumda bulduğunuzda karar vermenize yardımcı olabilir:

Izgaralar, büyük çoğunluk nesneleri ızgara karesine sığdığında ve dağıtım oldukça homojen olduğunda en iyi sonucu verir. Tersine, nesneler değişken boyutlara sahip olduğunda veya küçük alanlarda kümelendiğinde, dörtlü çalışır.

Sorunun belirsiz tanımına bakıldığında, ızgara çözümüne de yaslanıyorum (yani birimlerin küçük ve oldukça homojen bir şekilde dağıldığı varsayılarak).


Ayrıntılı cevap için teşekkürler. Evet, basit görünüyor Grid çözümü benim için yeterince iyi.
OCyril

0

Yazdığım bu biraz zaman geri. Şimdi ticari bir sitede, ancak kişisel kullanım için kaynağı ücretsiz olarak alabilirsiniz. Aşırı olabilir ve Java ile yazılmıştır, ancak iyi belgelenmiştir, bu nedenle başka bir dilde kırpmak ve yeniden yazmak çok zor olmamalıdır. Temelde bir Octree kullanır, gerçekten büyük nesneleri ve çok iş parçacığını işlemek için ince ayarlar yapar.

Bir Octree esneklik ve verimlilik en iyi kombinasyonu sunulan bulundu. Bir ızgara ile başladım, ancak kareleri düzgün bir şekilde boyutlandırmak imkansızdı ve boş karelerin büyük yamaları boş alan ve hesaplama gücü kullanıyordu. (Ve bu sadece 2 boyuttaydı.) Kodum, karmaşıklığa çok şey ekleyen birden çok iş parçacığından gelen sorguları işler , ancak belgelere ihtiyacınız yoksa bu sorunu çözmenize yardımcı olur.


0

Verimliliğinizi artırmak için, çok ucuz bir sınırlayıcı kutu kontrolü kullanarak hedef birimin yakınında olmayan "birimlerin"% 99'unu önemsiz bir şekilde reddetmeye çalışın. Ve umarım bunu verilerinizi mekânsal olarak yapılandırmadan yapabilirsiniz. Dolayısıyla, tüm birimleriniz düz bir veri yapısında depolanmışsa, baştan sona yarışmayı deneyebilirsiniz ve ilk önce ilgili birimin sınırlayıcı kutusunun dışındaki geçerli birim olup olmadığını kontrol edebilirsiniz.

İlgilenilen birim için "yakın" olarak değerlendirilme şansı olmayan öğeleri güvenle reddedebilecek şekilde büyük boyutlu bir sınırlama kutusu tanımlayın. Sınırlayıcı kutudan hariç tutma kontrolü, yarıçap denetiminden daha ucuz yapılabilir. Ancak, bunun test edildiği bazı sistemlerde durum böyle değildi. İkisi neredeyse eşit performans gösteriyor. Bu, aşağıdaki tartışmalardan sonra düzenlenmiştir.

İlk olarak: 2D sınırlayıcı kutu klipsi.

// returns true if the circle supplied is completely OUTSIDE the bounding box, rectClip
bool canTrivialRejectCircle(Vertex2D& vCentre, WorldUnit radius, Rect& rectClip) {
  if (vCentre.x + radius < rectClip.l ||
    vCentre.x - radius > rectClip.r ||
    vCentre.y + radius < rectClip.b ||
    vCentre.y - radius > rectClip.t)
    return true;
  else
    return false;
}

Böyle bir şeyle karşılaştırıldığında (3D olarak):

BOOL bSphereTest(CObject3D* obj1, CObject3D* obj2 )
{
  D3DVECTOR relPos = obj1->prPosition - obj2->prPosition;
  float dist = relPos.x * relPos.x + relPos.y * relPos.y + relPos.z * relPos.z;
  float minDist = obj1->fRadius + obj2->fRadius;
  return dist <= minDist * minDist;
}.

Nesne önemsiz bir şekilde reddedilmezse, daha pahalı ve daha doğru bir çarpışma testi gerçekleştirirsiniz. Ama sadece yakınlıkları arıyorsun, bu yüzden küre testi bunun için uygun, ancak önemsiz reddetmeden kurtulan nesnelerin sadece% 1'i için.

Bu makale önemsiz ret kutusunu desteklemektedir. http://www.h3xed.com/programming/bounding-box-vs-bounding-circle-collision-detection-performance-as3

Bu doğrusal yaklaşım size ihtiyacınız olan performansı vermezse, diğer posterlerden bahsedildiği gibi hiyerarşik bir veri yapısı gerekebilir. R-Ağaçları dikkate değer. Dinamik değişiklikleri desteklerler. Onlar mekânsal dünyanın BTrees'idir.

Bundan kaçınabiliyorsan böyle bir karmaşıklığı ortaya koyma sorununa gitmeni istemedim. Ayrıca, nesneler saniyede birkaç kez hareket ettikçe bu karmaşık veri yapısını güncel tutmanın maliyeti nedir?

Bir ızgaranın bir seviye derin mekansal veri yapısı olduğunu unutmayın. Bu sınır, gerçekten ölçeklenebilir olmadığı anlamına gelir. Dünya büyüdükçe, kaplamanız gereken hücre sayısı da büyüyor. Sonunda bu hücre sayısının kendisi bir performans problemi haline gelir. Bununla birlikte, belirli büyüklükteki bir dünya için, uzamsal bölümleme olmadan size büyük bir performans artışı sağlayacaktır.


1
OP özellikle kaba paragraf kuvvetinden kaçınmak istediğini söyledi, ki bu ilk paragrafınızda tam olarak tarif ettiğiniz şeydir. Ayrıca, bir sınırlayıcı kutu kontrolünün sınırlayıcı bir küre kontrolünden daha ucuz olduğunu nasıl anlarsınız ?! Bu açıkça yanlış.
notlesh

Evet, uygulamasına hiyerarşik bir veri yapısı getirme çabasıyla kaçınılacak kaba kuvvetten kaçınmak istediğini biliyorum. Ancak bu çok çaba gerektirebilir. Henüz bunu yapmak istemiyorsa, kaba kuvvet olan ancak listesi çok büyük değilse çok kötü performans göstermeyecek olan doğrusal yaklaşımı deneyebilir. 2B sınırlayıcı kutumu önemsiz reddetme işlevine koymak için yukarıdaki kodu düzenlemeye çalışacağım. Yanlış olduğumu düşünmüyorum.
Ciaran

GDnet bağlantısı koptu, ama kanonik küre testi çok basit, çok ucuz ve dallanmadı:inside = (dot(p-p0, p-p0) <= r*r)
Lars Viklund

Bunun yerine yukarıdaki kodu yapıştırdım. Sınırlayıcı kutuya kıyasla ucuz bir şey görünüyor.
Ciaran

1
@Ciaran Dürüst olmak gerekirse, bu makale gerçekten kötü görünüyor. Her şeyden önce testleri gerçekçi verilerle yapmaz, aksine aynı değerleri tekrar tekrar kullanır. Gerçek bir senaryoda karşılaşacağınız bir şey değil. Ve hayır, makaleye göre, BB sadece bir çarpışma olmadığında daha hızlıdır (örneğin, ilk ififadede kontrol başarısız olur ). Ayrıca çok gerçekçi değil. Ama dürüst olmak gerekirse, böyle şeyleri optimize etmeye başlıyorsanız, kesinlikle yanlış yerden başlıyorsunuz demektir.
bummzack

0

Bunu cevaplamak zorundayım çünkü yorum yapacak veya oylayacak noktalara sahip değilim. Bu soruyu soranların% 99'u için, Ciaran'ın tanımladığı gibi bir sınırlayıcı kutu çözümdür. Derlenmiş bir dilde, bir göz açıp kapayıncaya kadar 100.000 ilgisiz birimi reddedecektir. Kaba kuvvet dışı çözümlerle ilgili çok fazla ek yük var; daha küçük sayılarla (1000'in altında), işlem süresi açısından kaba kuvvet kontrolünden daha pahalı olacaktır. Ve çok daha fazla programlama süresi alacaklar.

Sorudaki "çok büyük bir sayının" ne anlama geldiğinden veya yanıt arayan diğer insanların bununla ne anlama geleceğinden emin değilim. Yukarıdaki sayılarımın muhafazakar olduğunu ve 10 ile çarpılabileceğini düşünüyorum; Şahsen kaba kuvvet tekniklerine karşı oldukça önyargılıyım ve ne kadar iyi çalıştıklarından ciddi şekilde rahatsızım. Ancak, birkaç hızlı kod satırı işe yarayacağı zaman, 10.000 üniteye sahip birinin süslü bir çözümle zaman kaybetmesini istemem. Gerekirse daha sonra her zaman fantezi olabilirler.

Ayrıca, bir sınırlayıcı küre kontrol sınırlayıcı kutu değil çarpma gerektirir unutmayın. Çarpma, doğası gereği, toplama ve karşılaştırma işlemlerinin birkaç katını alır. Küre kontrolünün bir kutu kontrolünden daha hızlı olacağı bazı dil, işletim sistemi ve donanım kombinasyonuna bağlı olmak zorundadır, ancak çoğu yerde ve zamanda, küre birkaç alakasız birimi reddetse bile kutu kontrolünün daha hızlı olması gerekir. kutu kabul eder. (Ve kürenin daha hızlı olduğu yerlerde, derleyici / yorumlayıcı / optimize edicinin yeni bir sürümünün bunu değiştirmesi muhtemeldir.)


Cevabınızla ilgili yanlış bir şey olmasa da, soruyu cevaplamıyorsunuz. Özellikle "kaba kuvvet dışı" bir yaklaşım istendi. Ayrıca Ciaran'ın yazdıklarını tekrarlıyor gibi görünüyorsunuz ve AABB'ye karşı daire testleri hakkında uzun bir yorum tartışmamız vardı. Performans farkı önemsizdir. Çarpışma adaylarınızın çoğuna uyan, gerçek dar faz testlerinin miktarını azaltacağı için genel olarak performans üzerinde daha büyük bir etkisi olacak bir sınırlayıcı hacim daha iyi seçin.
bummzack
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.