Войти
ПрограммированиеСтатьиФизика

Моделирование физики в компьютерных играх с помощью частиц.

Автор: Александр Куприн


Вступление:

В этой статье описывается принцип создания физической модели и один конкретный способ, который нравится автору,  но хочу заметить, что в данной статье вы не найдете описания полного пути моделирования физики. Цель данной статьи дать точку опоры и задать дальнейшее направление для исследования.

Моделирование для игры:

Создание модели для описания физического явления вещь сложная. Нужно набить руку, для того, чтобы достаточно быстро осознать какие факторы влияют на данный физический процесс. Из них нужно выделить те, которые являются основными, а какими можно и нужно пренебречь. Почему чем-то нужно пренебрегать? Дело в том, что все учесть невозможно и бессмысленно. Например, моделируя падение камня на землю с высоты одного метра, явно можно пренебречь изменением ускорения свободного падения с высотой, а также притяжением луны и другими факторами.  Моделируя же приливы и отливы, притяжением луны пренебречь нельзя, так как оно является основным фактором.

При моделировании физики в играх нужно заботиться о том, чтобы ваша физическая модель не "сожрала" чрезмерно много ресурсов компьютера. Пренебрегать придется даже тем, чем на первый взгляд пренебрегать нежелательно, а возможно даже придется заменить некоторые факторы на эквивалентные им. Вот мы и подошли к самому главному. Не стремитесь воссоздать реальность, стремитесь создать нечто похожее. Кроме того, физика в игре должна подчеркивать какие-то особенности. Если вы делаете веселую аркаду, то делайте физику соответствующую. Можно, а порой и нужно придумывать свои факторы, которых в жизни нет, и не было. Если же вы покушаетесь на реализм, то обманывайте пользователя, придумывайте упрощенную физику похожую на реальную. Реальность неповторима, вы должны лишь поймать основные особенности и воплотить их подобие.

Но нужно помнить и о том, что технологии идут вперед и нужно придумывать новые, более сложные модели. Многие моделируют физику так:  создают для объектов би-боксы, при столкновении отталкивают их друг от друга по какому-то правилу. Метод хороший, и при усовершенствовании и доведении до ума может выдать приличные результаты. Если читатель не знает что такое би-бокс, я думаю, найти некоторую информацию в интернете не составит особых проблем. А сейчас я хочу рассказать о другом методе.

Связанные частицы:

Пусть есть две частицы, координаты первой x1, координаты второй x2, где x1 и x2 - вектора. Расстояние между частицами четко задано и равно L. Получается, что между ними существует упругая связь. Для того чтобы восстановить между двумя частицами заданное расстояние, мы должны проделать следующие операции:

  vector3f delta = x2-x1;
  float deltalength = Magnitude(delta);
  float diff = (deltalength-L)/deltalength;
  x1 = x1+delta*(0.5f*diff);
  x2 = x2-delta*(0.5f*diff);
Где Magnitude() возвращает длину вектора.

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

Сейчас разберемся, с тем, как такую систему частиц перемещать. Казалось бы, чем плохо считать, для каждой частицы, на каждом шаге, её перемещение по формуле x1+=v1*timestep+a1*timestep*timestep/2 ,где v1 - скорость данной частицы, a1 - ускорение данной частицы, а timestep шаг по времени. И скорость еще надо изменить: v1+=a1*timestep. Но дело в том, что после перемещения всей системы нам нужно восстановить начальное расстояние между соединенными частицами. И это может привести к тому, что какая-то частица в итоге сдвинулась вовсе не на рассчитанное нами расстояние, она даже могла уйти в сторону противоположную своей скорости. Что в дальнейшем будет происходить с такой противоречивой системой, я не знаю и знать не хочу.

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

 x1+=x1-oldx1+a1*timestep*timestep. 

Так в движении системы будет учитываться взаимодействие частиц. Но отсутствие значения скорости сильно усложняет работу с системой частиц.

Поэтому, я решил поступать следующим образом. Сохраним положение частиц. Изменим скорость и расстояние, как в первом методе. После, рассчитав положение частиц в зависимости от связей, скорость каждой частицы вычисляем вот так v=(x-oldx)/timestep. Таким образом, мы учтем взаимодействие частиц между собой.

А так выглядит класс на c++.

struct Constraint 
{
      int   particleA, particleB;
      float restlength;
};

class ParticleSystemPhys 
{
public:
    Vector3f    m_x[NUM_PARTICLES]; // Current positions
    Vector3f    m_oldx[NUM_PARTICLES]; // Previous positions
    Vector3f    m_v[NUM_PARTICLES]; //velocity
    Vector3f    m_a[NUM_PARTICLES]; // acceleration
    Constraint  m_constraints[NUM_CONSTRAINTS];
    float       m_fTimeStep;
    int         NUM_PARTICLES;
    int         NUM_CONSTRAINTS;
    int         NUM_ITERATIONS;
    void        TimeStep();
private:
    void        Motion();
    void        SatisfyConstraints();
    void        AccumulateForces();
};

Думаю, читатель, основываясь на данном куске кода и рассуждениях автора, сможет написать функции для работы с системой частиц.

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

Двигаемся дальше.

Поведение твердых тел при столкновении:

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

Вспомним столкновение упругих шаров. m1,m2 - масса первого и второго шаров соответственно, v1,v2 - проекции скоростей шаров на нормаль столкновения до столкновения, u1,u2 - проекции скоростей шаров на нормаль после столкновения. Запишем законы сохранения импульса и энергии.

m1*v1+m2*v2=m1*u1+m2*u2

m1*v1*v1 /2+m2*v2*v2 /2=m1*u1*u1 /2+m2*u2*u2 /2

Запишем эти уравнения так:

m1(u1-v1)=m2(v2-u2)           (*)

m1(u1*u1-v1*v1)=m2(v2*v2-u2*u2)

Разделив второе уравнение на первое, получим:

v1+u1=v2+u2

Умножив обе части уравнения на m2 и сложив с (*) получим

u1=((m1-m2)v1+2*m2*v2)/(m1+m2).

Аналогично

u2=((m2-m1)v2+2*m1*v1)/(m1+m2).

А сейчас рассмотрим столкновение двух твердых тел с вершинами-частицами. Рассмотрим первое тело. Сделаем так, чтобы импульс, переданный точке столкновения частицей, зависел от расстояния до этой частицы. То есть чем дальше частица, тем меньше импульс она передала. Не забываем, о том, что частица отдала импульс, то есть скорость у нее должна стать соответствующей. То же самое делаем со вторым телом.

У нас будет скорость и масса для обоих тел в точке пересечения. Рассчитываем новые скорости, как было сделано с шарами. Дальше передаем скорости каждой частице в зависимости от расстояния до точки пересечения.

Итак, я представил модель, для поведения систем связанных частиц при столкновении. И не важно, как с точки зрения физики все происходит в реальности, ведь цель была не воссоздать реальность, а сделать поведение тел похожим на реальное. И на самом деле, тела визуально правдоподобно отскакивают, при чем после столкновения может начаться вращение.

Что дальше?

Ну, нужно программно реализовать идею, изложенную выше (а может и не нужно, если не хочется). Возможно, стоит изменить модель или дополнить. Нужно придумать, как реализовать силу трения, а также подумать об оптимизации. Вот, собственно, основные темы, над которыми стоит задуматься читателю.

И на последок, http://www.ioi.dk/Homepages/thomasj/publications/gdc2001.htm - ссылка на статью о связанных частицах.

#частицы

20 июня 2002

Комментарии [2]