На мою відповідь є кілька застережень, що я вийду спочатку зі шляху: Це стосується лише не обертових обмежувальних коробок. Це передбачає, що ви намагаєтеся вирішити проблеми тунелювання , тобто проблеми, викликані об'єктами, що рухаються з великою швидкістю.
Після того, як ви визначили 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)
тоді ви можете нормально займатися фізикою. Мінус полягає в тому, що якщо об’єкт рухається досить швидко, ви побачите його телепортування назад по його вектору швидкості.