O mecanismo de física é capaz de diminuir essa complexidade, por exemplo, agrupando objetos que estão próximos um do outro e verificar se há colisões dentro deste grupo em vez de contra todos os objetos? (por exemplo, objetos distantes podem ser removidos de um grupo observando sua velocidade e distância de outros objetos).
Caso contrário, isso torna a colisão trivial para esferas (em 3d) ou disco (em 2d)? Devo fazer um loop duplo ou criar uma matriz de pares?
EDIT: Para motores de física como bullet e box2d, a detecção de colisão ainda é O (N ^ 2)?
Respostas:
A divisão espacial é sempre O (N ^ 2) no pior caso e é disso que trata a complexidade em informática.
No entanto, existem algoritmos que funcionam no tempo linear O (N) . Todos eles são baseados em algum tipo de linha de varredura.
Basicamente, você precisa ter seus objetos classificados por uma coordenada. Digamos X. Se você executar a classificação todas as vezes antes da detecção de colisão, a complexidade será O (N * logN). O truque é classificar somente quando você estiver adicionando objetos à cena e depois quando algo na cena mudar. Classificar após o movimento não é trivial. Veja o artigo vinculado abaixo para um algoritmo que leva em movimento e ainda funciona em tempo linear.
Então você varre da esquerda para a direita. Cada vez que sua linha de varredura cruza o início de um objeto, você a coloca em uma lista temporária. Sempre que sua linha de varredura sai do objeto, você a retira da lista. Você considera colisões apenas dentro desta lista temporária.
A linha de varredura ingênua também é O (N ^ 2) na pior das hipóteses (você faz com que todos os objetos abranjam todo o mapa da esquerda para a direita), mas você pode torná-lo O (N) tornando-o mais inteligente (veja o link abaixo). Um algoritmo realmente bom será bastante complexo.
Este é um diagrama simples de como a linha de varredura funciona:
A linha varre da esquerda para a direita. Os objetos são classificados pela coordenada X.
Algoritmos como esse têm complexidade O (C * N) = O (N).
Fonte: Dois anos de cursos de geometria computacional.
Na detecção de colisões, isso geralmente é chamado de varredura e remoção , mas a família de algortitmos da linha de varredura é útil em muitos outros campos.
Outras leituras recomendadas que acredito estarem fora do escopo desta pergunta, mas, no entanto, são interessantes: Métodos eficientes de varredura e remoção em larga escala com inserção e remoção de AABB - Este artigo apresenta um algoritmo aprimorado de varredura e remoção que usa caixas delimitadoras alinhadas a eixos (AABB ) com a classificação que leva em consideração o movimento. O algoritmo apresentado no trabalho funciona em tempo linear.
Agora observe que este é o melhor algoritmo da teoria . Isso não significa que é usado. Na prática, o algoritmo O (N ^ 2) com divisão espacial terá melhor velocidade de desempenho em casos típicos (próximo a O (N)) e algum requisito extra para memória. Isso ocorre porque a constante C em O (C * N) pode ser muito alta! Como geralmente temos memória suficiente e casos típicos têm objetos espalhados uniformemente no espaço - esse algoritmo terá um desempenho MELHOR. Mas O (N) é a resposta para a pergunta original.
fonte
Não. A detecção de colisão nem sempre é O (N ^ 2).
Por exemplo, digamos que temos um espaço de 100x100 com objetos com tamanho 10x10. Poderíamos dividir esse espaço em células de 10x10 com uma grade.
Cada objeto pode estar em até 4 células da grade (pode caber em um bloco ou estar "entre" células). Poderíamos manter uma lista de objetos em cada célula.
Só precisamos verificar colisões nessas células. Se houver um número máximo de objetos por célula da grade (digamos, nunca há mais de 4 objetos no mesmo bloco), a detecção de colisão para cada objeto é O (1) e a detecção de colisão para todos os objetos é O (N).
Essa não é a única maneira de evitar a complexidade de O (N ^ 2). Existem outros métodos, mais adequados para outros casos de uso - geralmente usando estruturas de dados baseadas em árvore.
O algoritmo que descrevi é um tipo de particionamento espacial , mas existem outros algoritmos de particionamento espacial. Consulte Tipos de estruturas de dados de particionamento de espaço para obter mais algoritmos que evitam a complexidade temporal O (N ^ 2).
O Box2D e o Bullet suportam mecanismos para reduzir o número de pares verificados.
No manual , seção 4.15:
Do Bullet Wiki :
fonte
O (N ^ 2) refere-se ao fato de que se você tiver N objetos, descobrir o que está colidindo com o que é, na pior das hipóteses , os cálculos de colisão N ^ 2. Digamos que você tenha 3 objetos. Para encontrar "quem está acertando quem", você deve encontrar:
São 6 verificações de colisões ou N * (N-1). Na análise assintótica, expandiríamos o polinômio e aproximaríamos como O (N ^ 2). Se você tivesse 100 objetos, seria 100 * 99, o que é próximo o suficiente para 100 * 100.
Portanto, se você particionar espaço usando uma octree, por exemplo, o número médio de comparações entre corpos é reduzido. Se for possível que todos os objetos se agrupem em uma área muito pequena (digamos, se você estiver fazendo algum tipo de simulação de fluxo de partículas, onde partículas podem se reunir na mesma área), o O (N ^ 2) ainda poderá ocorrer em pontos na simulação (nos quais você verá a desaceleração).
Portanto, todo o ponto de O (N ^ 2) existe devido à natureza de cada corpo que verifica todos os outros corpos na cena. Essa é apenas a natureza da computação. Muitas coisas podem ajudar a tornar isso mais barato. Mesmo um gráfico de cena (digamos, detectar apenas objetos na mesma sala ) reduzirá significativamente o número de cálculos de colisão a serem feitos, mas ainda será O (M ^ 2) (onde M é o número de objetos na sala a ser detecção de colisão). Os volumes delimitadores esféricos tornam a verificação inicial muito rápida (
if( distance( myCenter, hisCenter ) > (myRadius+hisRadius) ) then MISS
), portanto, mesmo que a detecção de colisão seja O (N ^ 2), é provável que os cálculos da esfera delimitadora ocorram muito rapidamente.fonte