Es gibt ein paar Vorbehalte bei meiner Antwort, die ich zuerst aus dem Weg räumen werde: Es geht nur um nicht rotierende Begrenzungsrahmen. Es wird davon ausgegangen, dass Sie versuchen, mit dem Tunnelbau umzugehen lösen, dh Probleme, die durch Objekte verursacht werden, die sich mit hoher Geschwindigkeit bewegen.
Sobald Sie das MTV identifiziert haben, kennen Sie die Kante / Oberflächennormale, gegen die Sie testen müssen. Sie kennen auch den Lineargeschwindigkeitsvektor des durchdringenden Objekts.
Sobald Sie festgestellt haben, dass zu einem bestimmten Zeitpunkt während des Frames eine Schnittmenge aufgetreten ist, können Sie binäre Halbschrittoperationen ausführen, die auf den folgenden Ausgangspunkten basieren:
vec3 vertex;
float mindot = FLT_MAX;
for ( vert : vertices )
{
if (dot(vert, MTV) < mindot)
{
mindot = dot(vert, MTV);
vertex = vert;
}
}
Sobald Sie den Scheitelpunkt identifiziert haben, wird der binäre Halbschritt weitaus günstiger:
//mindistance is the where the reference edge/plane intersects it's own normal.
//The max dot product of all vertices in B along the MTV will get you this value.
halfstep = 1.0f;
vec3 cp = vertex;
vec3 v = A.velocity*framedurationSeconds;
float errorThreshold = 0.01f; //choose meaningful value here
//alternatively, set the while condition to be while halfstep > some minimum value
while (abs(dot(cp,normal)) > errorThreshold)
{
halfstep*=0.5f;
if (dot(cp,normal) < mindistance) //cp is inside the object, move backward
{
cp += v*(-1*halfstep);
}
else if ( dot(cp,normal) > mindistance) //cp is outside, move it forward
{
cp += v*(halfstep);
}
}
return cp;
Dies ist einigermaßen genau, liefert jedoch nur einen einzigen Kollisionspunkt in einem einzigen Fall.
Die Sache ist, es ist normalerweise möglich, im Voraus zu sagen, ob sich ein Objekt pro Frame schnell genug bewegt, um so tunneln zu können. Daher ist es der beste Rat, die führenden Scheitelpunkte entlang der Geschwindigkeit zu identifizieren und einen Strahlentest entlang des Geschwindigkeitsvektors durchzuführen. Bei rotierenden Objekten müssen Sie eine Art binären Halbschritt-Slerp ausführen, um den korrekten Kontaktpunkt sicherzustellen.
In den meisten Fällen kann jedoch davon ausgegangen werden, dass sich die meisten Objekte in Ihrer Szene nicht schnell genug bewegen, um so weit in ein einzelnes Bild einzudringen. Daher ist kein halbes Springen erforderlich und eine diskrete Kollisionserkennung wird ausreichen. Hochgeschwindigkeitsobjekte wie Kugeln, die sich zu schnell bewegen, um gesehen zu werden, können für Kontaktpunkte verfolgt werden.
Interessanterweise können Sie mit dieser Halbschrittmethode auch die (fast) genaue Zeit ermitteln, zu der das Objekt während des Frames aufgetreten ist:
float collisionTime = frametimeSeconds * halfstep;
Wenn Sie eine Art physikalische Kollisionsauflösung durchführen, können Sie die Position von A folgendermaßen korrigieren:
v - (v*halfstep)
dann kannst du deine physik normal von dort aus machen. Der Nachteil ist, dass das Objekt, wenn es sich relativ schnell bewegt, entlang seines Geschwindigkeitsvektors zurück teleportiert.