Обнаружение столкновений между ускоряющимися сферами - PullRequest
6 голосов
/ 16 декабря 2009

Я пишу физический движок / симулятор, который включает в себя трехмерный космический полет, планетарную / звездную гравитацию, тягу корабля и релятивистские эффекты. Пока что все идет хорошо, но мне нужна помощь по математике алгоритма обнаружения столкновений.

Используемое мной итеративное моделирование движения в основном выглядит следующим образом:

(Примечание. 3D-векторы - это ВСЕ КАПСЫ.)

For each obj

    obj.ACC = Sum(all acceleration influences)

    obj.POS = obj.POS + (obj.VEL * dT) + (obj.ACC * dT^2)/2     (*EQ.2*)

    obj.VEL = obj.VEL + (obj.ACC * dT)

Next

Где:

obj.ACC is the acceleration vector of the object
obj.POS is the position or location vector of the object
obj.VEL is the velocity vector of the object

obj.Radius is the radius (scalar) of the object

dT is the time delta or increment

Что мне в основном нужно сделать, так это найти некоторую эффективную формулу, которая выводится из ( EQ.2 ) выше для двух объектов (obj1, obj2) и сказать, сталкиваются ли они когда-либо, и если да, то в сколько времени. Мне нужно точное время как для того, чтобы я мог определить, находится ли оно в этом конкретном приращении времени (потому что ускорения будут отличаться при разных приращениях времени), а также чтобы я мог определить точное положение (что я знаю, как сделать, учитывая время)

Для этого движка я моделирую все объекты как сферы, все, что нужно этой формуле / algortithim, это выяснить, в каких точках:

(obj1.POS - obj2.POS).Distance = (obj1.Radius + obj2.Radius)

где .Distance - положительное скалярное значение. (Вы также можете заключить квадрат в обе стороны, если это проще, чтобы избежать функции квадратного корня, неявной в расчете .Distance).

(да, мне известно о многих, многих других вопросах обнаружения столкновений, однако все их решения кажутся очень специфичными для их движка и предположений, и ни один из них не соответствует моим условиям: 3D, сферы и ускорение, применяемые в приращения симуляции. Дайте мне знать, если я ошибаюсь.)


Некоторые уточнения:

1) Мне недостаточно проверить * Пересечение * двух сфер до и после увеличения времени. Во многих случаях их скорости и изменения положения будут намного превышать их радиусы.

2) RE: эффективность, мне не нужна помощь (на данном этапе в любом случае) в отношении определения вероятных кандидатов на столкновения, я думаю, что у меня есть это.


Еще одно уточнение, которое, похоже, очень скоро появится:

3) Мое уравнение ( EQ.2 ) инкрементального движения представляет собой квадратное уравнение, в котором применяются скорости и Ускорение:

obj.POS = obj.POS + (obj.VEL * dT) + (obj.ACC * dT^2)/2

физические движки, которые я видел, (и, конечно, каждый игровой движок, о котором я когда-либо слышал) только линейные уравнения инкрементального движения, которые применяются только Скорость:

obj.POS = obj.POS + (obj.VEL * dT)

Вот почему я не могу использовать общепринятые решения для обнаружения столкновений, найденные в StackOverflow, в Википедии и во всем Интернете, такие как поиск пересечения / сближения двух отрезков. Моя симуляция имеет дело с переменными ускорениями, которые имеют основополагающее значение для результатов, поэтому мне нужно пересечение / ближайший подход двух параболических сегментов.

Ответы [ 4 ]

4 голосов
/ 16 декабря 2009

На веб-странице, на которую ссылается А.Шелли, метод Ближайшей точки подхода разработан для случая, когда два объекта движутся с постоянной скоростью. Однако я полагаю, что один и тот же метод векторного исчисления можно использовать для получения результата в случае двух объектов, движущихся с постоянным ненулевым ускорением (квадратичная зависимость от времени).

В этом случае производная по времени функции квадрата расстояния равна 3-му порядку (кубическому) вместо 1-го порядка. Таким образом, будет предложено 3 решения для времени ближайшего сближения, что неудивительно, поскольку путь обоих объектов изогнут, поэтому возможны многочисленные пересечения. Для этого приложения вы, вероятно, захотите использовать самое раннее значение t, которое находится в пределах интервала, определенного текущим шагом моделирования (если такое время существует).

Я разработал производное уравнение, которое должно дать времена ближайшего приближения:

0 = |D_ACC|^2 * t^3 + 3 * dot(D_ACC, D_VEL) * t^2 + 2 * [ |D_VEL|^2 + dot(D_POS, D_ACC) ] * t + 2 * dot(D_POS, D_VEL)

где:

D_ACC = ob1.ACC-obj2.ACC

D_VEL = ob1.VEL-obj2.VEL (до обновления)

D_POS = ob1.POS-obj2.POS (также до обновления)

и dot(A, B) = A.x*B.x + A.y*B.y + A.z*B.z

(Обратите внимание, что квадрат величины |A|^2 может быть вычислен с использованием dot(A, A))

Чтобы решить эту проблему для t , вам, вероятно, потребуется использовать формулы, подобные , найденным в Википедии .

Конечно, это даст вам только момент ближайшего приближения . Вам нужно будет проверить расстояние в данный момент (используя что-то вроде уравнения 2). Если оно больше (obj1.Radius + obj2.Radius), оно может быть проигнорировано (т.е. нет столкновения). Однако, если расстояние меньше, это означает, что сферы сталкиваются до этого момента. Затем вы можете использовать итеративный поиск, чтобы проверить расстояние в более ранние времена. Также может быть возможно придумать другой (даже более сложный) вывод, который учитывает размер, или можно найти какое-то другое аналитическое решение, не прибегая к итеративному решению.

Редактировать : из-за более высокого порядка некоторые решения уравнения на самом деле являются моментами самого дальнего разделения . Я считаю, что во всех случаях 1 из 3 решений или 2 из 3 решений будут временем самого дальнего разделения. Вы можете аналитически проверить, находитесь ли вы на минимуме или максимуме, оценивая вторую производную по времени (при значениях t, которые вы нашли, установив первую производную в ноль):

D''(t) = 3 * |D_ACC|^2 * t^2 + 6 * dot(D_ACC, D_VEL) * t + 2 * [ |D_VEL|^2 + dot(D_POS, D_ACC) ]

Если вторая производная оценивается как положительное число, то вы знаете, что расстояние является минимальным, а не максимальным, для данного времени t.

2 голосов
/ 16 декабря 2009

Нарисуйте линию между начальной точкой и конечной точкой каждой сферы. Если полученные отрезки линии пересекаются, сферы определенно столкнулись в некоторой точке, и некоторая умная математика может найти, в какое время произошло столкновение. Также убедитесь, что минимальное расстояние между сегментами (если они не пересекаются) всегда меньше 2 * радиуса. Это также будет указывать на столкновение.

Оттуда вы можете отступить от времени вашего дельты, чтобы оно произошло точно при столкновении, чтобы вы могли правильно рассчитать силы.

Рассматривали ли вы использовать физическую библиотеку, которая уже работает? Многие библиотеки используют гораздо более совершенные и более стабильные (лучшие интеграторы) системы для решения систем уравнений, с которыми вы работаете. Bullet Physics приходит на ум.

1 голос
/ 28 декабря 2018

оп попросил время столкновения. Немного другой подход вычислит это точно ...

Помните, что уравнение проекции положения:

NEW_POS=POS+VEL*t+(ACC*t^2)/2

Если мы заменим POS на D_POS=POS_A-POS_B, VEL на D_VEL=VEL_A-VEL_B и ACC=ACC_A-ACC_B для объектов A и B, мы получим:

$D_NEW_POS=D_POS+D_VEL*t+(D_ACC*t^2)/2

Это формула для векторного расстояния между объектами. Чтобы получить квадрат скалярного расстояния между ними, мы можем взять квадрат этого уравнения, который после расширения выглядит следующим образом:

distsq(t) = D_POS^2+2*dot(D_POS,D_VEL)*t + (dot(D_POS, D_ACC)+D_VEL^2)*t^2 + dot(D_VEL,D_ACC)*t^3 + D_ACC^2*t^4/4

Чтобы найти время, когда происходит столкновение, мы можем установить уравнение равным квадрату суммы радиусов и решить для t:

0 = D_POS^2-(r_A+r_B)^2 + 2*dot(D_POS,D_VEL)*t + (dot(D_POS, D_ACC)+D_VEL^2)*t^2 + dot(D_VEL,D_ACC)*t^3 + D_ACC^2*t^4/4

Теперь мы можем найти уравнение, используя формулу четвертого порядка .

Формула квартики даст 4 корня, но нас интересуют только вещественные корни. Если существует двойной реальный корень, то два объекта касаются краев ровно в один момент времени. Если существует два реальных корня, то объекты непрерывно перекрываются между корнем 1 и корнем 2 (то есть корень 1 - это время, когда начинается столкновение, а корень 2 - это время, когда прекращается столкновение). Четыре реальных корня означают, что объекты сталкиваются дважды, непрерывно между парами корней 1,2 и 3,4.

В R я использовал polyroot() для решения следующим образом:

# initial positions
POS_A=matrix(c(0,0),2,1)
POS_B=matrix(c(2,0),2,1)
# initial velocities
VEL_A=matrix(c(sqrt(2)/2,sqrt(2)/2),2,1)
VEL_B=matrix(c(-sqrt(2)/2,sqrt(2)/2),2,1)
# acceleration
ACC_A=matrix(c(sqrt(2)/2,sqrt(2)/2),2,1)
ACC_B=matrix(c(0,0),2,1)
# radii
r_A=.25
r_B=.25
# deltas
D_POS=POS_B-POS_A
D_VEL=VEL_B-VEL_A
D_ACC=ACC_B-ACC_A


# quartic coefficients
z=c(t(D_POS)%*%D_POS-r*r, 2*t(D_POS)%*%D_VEL, t(D_VEL)%*%D_VEL+t(D_POS)%*%D_ACC, t(D_ACC)%*%D_VEL, .25*(t(D_ACC)%*%D_ACC))
# get roots
roots=polyroot(z)
# In this case there are only two real roots...
root1=as.numeric(roots[1])
root2=as.numeric(roots[2])

# trajectory over time
pos=function(p,v,a,t){
  T=t(matrix(t,length(t),2))
  return(t(matrix(p,2,length(t))+matrix(v,2,length(t))*T+.5*matrix(a,2,length(t))*T*T))
}

# plot A in red and B in blue
t=seq(0,2,by=.1) # from 0 to 2 seconds.
a1=pos(POS_A,VEL_A,ACC_A,t)
a2=pos(POS_B,VEL_B,ACC_B,t)
plot(a1,type='o',col='red')
lines(a2,type='o',col='blue')

# points of a circle with center 'p' and radius 'r'
circle=function(p,r,s=36){
  e=matrix(0,s+1,2)
  for(i in 1:s){
    e[i,1]=cos(2*pi*(1/s)*i)*r+p[1]
    e[i,2]=sin(2*pi*(1/s)*i)*r+p[2]
  }
  e[s+1,]=e[1,]
  return(e)
}

# plot circles with radius r_A and r_B at time of collision start in black
lines(circle(pos(POS_A,VEL_A,ACC_A,root1),r_A))
lines(circle(pos(POS_B,VEL_B,ACC_B,root1),r_B))
# plot circles with radius r_A and r_B at time of collision stop in gray
lines(circle(pos(POS_A,VEL_A,ACC_A,root2),r_A),col='gray')
lines(circle(pos(POS_B,VEL_B,ACC_B,root2),r_B),col='gray')

Resulting R plot showing trajectories and start/stop collision location of objects

Объект A следует красной траектории от нижнего левого до верхнего правого. Объект B следует по синей траектории от нижнего правого до верхнего левого. Два объекта непрерывно сталкиваются между временем 0,9194381 и временем 1,167549. Два черных круга просто касаются друг друга, показывая начало наложения - и наложение продолжается во времени, пока объекты не достигнут расположения серых кругов.

1 голос
/ 16 декабря 2009

Похоже, вы хотите Ближайшая точка приближения (CPA) . Если это меньше, чем сумма радиусов, у вас есть столкновение. Пример кода в ссылке. Вы можете рассчитать каждый кадр с текущей скоростью и проверить, меньше ли время CPA, чем ваш размер тика. Вы даже можете кешировать время cpa и обновлять его только тогда, когда к любому элементу применяется ускорение.

...