Danke für die Tips. Mein Hauptproblem ist jedoch nicht unbedingt das finden von Kollisionen sondern das Filtern der gefundenen.
Wenn man sich das Bild oben anschaut: Das Level ist ein großes Mesh. Der Ball rollt auf dem Mesh, und knallt dann in die Wand. Aber weil er rollt, gibt es in jedem Frame ein Kollisionsevent (außer der Ball springt) - und es ist immer mit dem selben Objekt. Man könnte jetzt Boden und Wand in getrennte Objekte packen. Aber es soll ja später auch bewegliche Dinge wie Schaufelräder oder so geben - also im allgemeinen nicht-konvexe Objekte die man nicht weiter zerlegen will. Alles einfach in viele kleine Objekte zerlegen wird also vermutlich früher oder später scheitern, vom Aufwand mal ganz abgesehen.
Problem Nummer 2, ist dass ein leichtes Berühren und ein frontaler Aufschlag zwei unterschiedliche Dinge sind, die unterschiedliche Sounds erzeugen sollten. Selbst wenn das Aufteilen in unterschiedliche Objekte wenig Aufwand wäre und immer gut funktionieren würde, würde dieses Problem also bleiben. Man muss zwangsläufig mehr Informationen über die Kollision verarbeiten.
Aber gut. Ich kann über alle Events iterieren und auf die Kollisionspunkte zugreifen - nur waren die Infos da für mich auch nach langem rumspielen einfach nicht nützlich. Dann probier ich halt was eigenes aus, hehe. Ich tracke jetzt die Geschwindigkeit des Balls. Wenn die sich von einem Frame auf den nächsten Signifikant verändert (im Betrag oder Richtung, beides ist möglich!) während gleichzeitig ein Kollisionsevent stattfindet, dann impliziert das einen Aufprall. Zusätzlich solle man nach jedem Event noch ein paar Frames warten, manchmal passieren 2 Richtungsänderungen direkt nacheinander (wenn man in eine Ecke rollt). Der Code sieht dann so aus:
Code: Alles auswählen
// handle collisions:
auto world = m_scene_manager.get_collision_world();
const int num_manifolds = world->getDispatcher()->getNumManifolds();
auto ball_velocity = as_glmVec(m_ball_physic->get_collision_object()->getLinearVelocity());
for( int i=0; i<num_manifolds; i++ )
{
btPersistentManifold* contact_manifold = world->getDispatcher()->getManifoldByIndexInternal(i);
for( int j=0; j<contact_manifold->getNumContacts(); j++ )
{
//btManifoldPoint& pt = contact_manifold->getContactPoint(j); // no useful info :(
// velocity change
auto vel_change = length(ball_velocity) / length(m_ball_last_velocity);
if( vel_change < 1.f) // basically and absolute value
vel_change = 1.f/vel_change;
// check for velocity changes:
if( m_ball_collision_free_frames > 5 &&
length(m_ball_last_velocity) > 1.0 && //only if ball is sufficiently fast
(dot(normalize(ball_velocity), normalize(m_ball_last_velocity)) < 0.8 // sudden change of direction
|| vel_change > 1.5f ) // sudden speed difference
)
{
m_sound_ball_collide.Play();
m_ball_collision_free_frames = 0;
}
}
}
m_ball_collision_free_frames++;
m_ball_last_velocity = ball_velocity;
Das funktioniert fürs erste ganz gut. Die Threshold sind halt wichtig, die muss man richtig einstellen. Man kann aber anhand derer auch vergleichen, wie stark der Aufprall denn nun war (also nicht nur eine binäre Entscheidung treffen) und entsprechend den richtigen Sound spielen (oder Lautstärke anpassen).
Zusätzlich kann es noch passieren, dass man mehrere Frames betrachten muss. Es gibt zum Beispiel eine Halfpipe, wo es dann in sehr sehr kurzer Zeit viele kleine Richtungsänderungen gibt. Möchte man da auch einen Kollisionssound haben? Vielleicht. Dann müsste man halt gucken, ob die Gesamtänderung über die letzten X Frames über einem Schwellwert liegt.
Aber fürs erste reicht das hier schon. Einen Rollsound hätte ich noch gerne, dafür werd ich wohl ähnliche Kriterien finden. Und dann geht es an komplexere Level :)