В моем ответе есть несколько предостережений, которые я сначала уберу с дороги: это касается только не вращающихся ограничительных рамок. Предполагается, что вы пытаетесь справиться с проблемами туннелирования , то есть проблемами, вызванными объектами, движущимися с высокой скоростью.
После того, как вы определили MTV, вы знаете норму кромки / поверхности, с которой вам нужно проверить. Вам также известен линейный вектор скорости взаимопроникающего объекта.
Как только вы установили, что в какой-то момент во фрейме произошло пересечение, вы можете выполнить двоичные полушаговые операции, основанные на следующих начальных точках: Определите вершину, которая проникла первой во фрейме:
vec3 vertex;
float mindot = FLT_MAX;
for ( vert : vertices )
{
if (dot(vert, MTV) < mindot)
{
mindot = dot(vert, MTV);
vertex = vert;
}
}
Как только вы определили вершину, бинарный полушаг становится намного менее дорогим:
//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;
Это достаточно точно, но обеспечит только одну точку столкновения в одном случае.
Дело в том, что обычно можно заранее определить, будет ли объект перемещаться достаточно быстро за кадр, чтобы иметь возможность туннелирования подобным образом, поэтому лучший совет - определить ведущие вершины вдоль скорости и выполнить проверку луча вдоль вектора скорости. В случае с вращающимися объектами вам нужно будет выполнить какой-то бинарный полушаговый шаг, чтобы установить правильную точку контакта.
В большинстве случаев, однако, можно с уверенностью предположить, что большинство объектов в вашей сцене не будут двигаться достаточно быстро, чтобы проникнуть так далеко в одном кадре, поэтому нет необходимости в половинном шаге, и будет достаточно дискретного обнаружения столкновений. Высокоскоростные объекты, такие как пули, которые движутся слишком быстро, чтобы их можно было увидеть, можно проследить по точкам контакта.
Интересно, что этот метод полушагов также может дать вам (почти) точное время, когда объект произошел во время кадра:
float collisionTime = frametimeSeconds * halfstep;
Если вы выполняете какое-то физическое разрешение столкновений, вы можете исправить положение A следующим образом:
v - (v*halfstep)
тогда ты сможешь нормально заниматься физикой оттуда. Недостатком является то, что если объект движется достаточно быстро, вы увидите, что он телепортируется обратно по вектору скорости.