Нормализация пространственных векторов без квадратного корня
Итак, я узнал, что использование квадратного корня в программировании-это всегда плохая практика, особенно на каждом этапе обновления. Я пытаюсь сделать реалистичные упругие столкновения между кругами, и я читал это: http://www.vobarian.com/collisions/2dcollisions2.pdf есть ли способ нормализовать вектор без использования квадратного корня? Или какой-нибудь быстрый способ сделать то, что я делаю?
1 ответ:
Умножьте набыстрый обратный квадратный корень из квадрата величины для нормализации.
Нормализация вектора означает деление каждой его компоненты на величину этого вектора. Величина равнаsqrt(x**2 + y**2)
, гдеx
иy
- компоненты вектора. Но квадратный корень-это медленно, мы предпочитаем избегать его. Таким образом, вместо деления наsqrt(x**2 + y**2)
мы выбираем умножение на обратный квадратный корень из величины, которая равна1 / sqrt(x**2 + y**2)
.Почему это помогает? Потому что хорошие люди, которые сделали Quake III, придумали очень быстрый способ вычисления
Другими словами,1 / sqrt(x**2 + y**2)
, который мы называем быстрым обратным квадратным корнем.fisqrt(x)
равно1 / sqrt(x)
, но вычислениеfisqrt(x)
намного быстрее, чем вычисление1 / sqrt(x)
.Вот несколько псевдопифонов, чтобы проиллюстрировать, как все это собрать.
def fisqrt(x): # See article for implementation details. def normalize(vector): magnitude_squared = vector.x**2 + vector.y**2 invsqrt = fisqrt(magnitude_squared) vector.v *= invsqrt vector.y *= invsqrt return vector
Кроме того, вы можете "отбраковывать" более дорогие проверки столкновений (псевдо-python ниже):
def magnitudeSquared(vector): return vector.x ** 2 + vector.y ** 2 def cull(circleA, circleB): # Save a square root by calling magnitudeSquared. # Assuming that circle.center is a vector with x and y components. minCollisionDistance = circleA.radius + circleB.radius if magnitudeSquared(circleA.center - circleB.center) <= minCollisionDistance ** 2: # Circles overlap, can't cull. return false # Circles do not overlap, can cull! return true
Позвоните
cull
, прежде чем делать другие проверка столкновений. Когдаcull
возвращает true, вам не нужно делать никаких дальнейших проверок, потому что два круга не могут касаться друг друга. Это хорошо, потому чтоcull
почти наверняка будет быстрее, чем другие методы обнаружения столкновений, которые вы можете использовать. Еслиcull
возвращает false, то область окружностей где-то перекрывается, поэтому вы вызываете свой более дорогой алгоритм физического моделирования.