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

Помогите написать физический движок :) (6 стр)

Страницы: 15 6 7 836 Следующая »
#75
18:20, 1 мая 2018

vindast
> Видимо я  не правильно понял смысл псевдоимпульсов. У меня они сразу на позицию
> влияют, и только на нее.
псевдоимпульсы придают телам временную линейную и угловую скорость, точно так же, как работают обычные импульсы.

vindast
> Допустим, если все переделать в матричную систему, должна пройти необходимость
> что либо как либо перерассчитывать несколько раз на каждой итерации
я не знаю, что ты называешь "переделать в матричную систему", но итеративный солвер является аппроксимацией решения linear complimentarity system. итеративный солвер часто используют, потому что она гораздо дешевле (O(N)), чем честное решение LCP, которое решается за O(N^3) в самом лучшем случае.

точное решение LCP даёт лямбды, которые имеют смысл импульсов, которым тела обмениваются за dt. поэтому если тебе во что бы ты ни стало приспичило именно силу найти, то её можно вычислить из формулы [cht]\vec p = \vec F \cdot dt[/cht]. если корректно аккумулировать импульсы через warmstarting, то система быстро сойдётся к точному решению (которое ты, видимо, называешь решением матрицы, что бы это ни значило).


#76
(Правка: 6 мая 2018, 5:09) 17:29, 5 мая 2018

Думаю, тему надо переименовать в помогите мне написать физ. движ.

#77
(Правка: 5:32) 4:55, 6 мая 2018

Не могу разобраться с тем как применять псевдоскорости.

Нахожу псевдоскорости так (удар об непреодолимое препятсвтие):

   void computeCorrection(TRigidBody* body, vec3 n, vec3 w,float ERP)
  {
    float a = dot(n, body->pseudoVelosytiLinear) + dot(w, body->pseudoVelosytiAngular);
    float b = dot(n,n) * body->invMass + dot(w,w) * body->invInertia;

    float lambda =  (ERP - a) / b;

    if (lambda > 0)
    {
      body->pseudoVelosytiLinear += n * lambda * body->invMass;
      body->pseudoVelosytiAngular += w * lambda * body->invInertia;
    }
  }


Применяю их так.

_pos += pseudoVelosytiLinear * dT;

pseudoVelosytiLinear = vec3(0);
pseudoVelosytiAngular = vec3(0);

Не понимаю что делать с угловой составляющей. Помогите.

#78
5:45, 6 мая 2018

vindast
точно так же, как с обычной угловой скоростью. вращай тело на угол pseudoAngularVelocity * dt.

#79
(Правка: 5:49) 5:49, 6 мая 2018
angle = length(pseudoVelosytiAngular) * dT;

    if (angle > 0.0f)
    {
      vec3 axis = normalize(pseudoVelosytiAngular);

      xVector = normalize(vec3(rotate(mat4(1.0f), angle, axis) * vec4(xVector, 1)));
      yVector = normalize(vec3(rotate(mat4(1.0f), angle, axis) * vec4(yVector, 1)));
      zVector = normalize(vec3(rotate(mat4(1.0f), angle, axis) * vec4(zVector, 1)));
    }

Значит, дребезжит не из-за этого.
А как сделать так что бы тела не дребезжали?

#80
5:51, 6 мая 2018

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

#81
5:52, 6 мая 2018

Suslik

#82
(Правка: 6:00) 5:59, 6 мая 2018

vindast
во-первых, у тебя вот тут чёрт знает что:
> float lambda = (ERP - a) / b
фактически ты ставишь джойнт, у которого условие решения — это выталкивание тел со скоростью ERP. разумеется, такой контакт не является стабильным, потому что он будет то исчезать, то пропадать. должно быть что-то в духе

float dstVelocity = contact->depth * ERP
lambda = (dstVelocity - a) / b;

и потом ещё может быть несколько причин, например, тела никогда не надо выталкивать полностью — из-за этого контакты будут то исчезать, то появляться. должно быть что-то в духе std::max(contact->depth - skinWidth, 0.0f) * ERP

основная хитрость написания стабильного физического движка — это делать контакты как можно более стабильными во времени, тогда warmstarting очень быстро сойдётся к точному решению системы.

#83
6:00, 6 мая 2018

Suslik
> float dstVelocity = contact->depth * ERP

float ERP = 0.77;
****
omputeCorrection(rectBody, n1, w1, -depths[i] * ERP);
#84
6:01, 6 мая 2018

depths - отрицательное число в случае контакта

#85
6:06, 6 мая 2018

Suslik
> основная хитрость написания стабильного физического движка — это делать
> контакты как можно более стабильными во времени, тогда warmstarting очень
> быстро сойдётся к точному решению системы.
Мне надо забыть про псевдоипульсы ? У вас же написано, что warmstarting и псевдоскорости это плохая идея.

#86
6:10, 6 мая 2018

vindast
чтобы фиксить баги с дрожанием, я делаю так:
- делаю предельно простую сцену, где баг воспроизводится
- ставлю либо бесконечное(очень много), либо одну итерацию солвера, в зависимости от случая
- рендеринг контактов с глубиной и нормалями — необходимая фича для отладки
- включаю покадровый режим апдейта, при котором система обновляется на один dt при нажатии кнопки.
- если ERP=0.7, то после решения системы глубина всех контактов должна уменьшиться ровно в 0.7 раз. если этого не происходит, то стандартный путь: invInertia = 0, отладчик внутрь джойнта и так далее.

в твоём случае ошибка, потому что я немного криво объяснил. размерность псевдоскорости — это метры. то есть ты решаешь, на какое *расстояние* тела выталкиваются за 1 dt. при этом величина самого dt значения не имеет. то есть после решения псевдоимпульсов их применять надо не так:
pos += pseudoLinearVelocity * dt;
coords.Rotate(pseudoAngularVelocity * dt);
а так:
pos += pseudoLinearVelocity;
coords.Rotate(pseudoAngularVelocity);

#87
6:11, 6 мая 2018

vindast
> Мне надо забыть про псевдоипульсы ? У вас же написано, что warmstarting и
> псевдоскорости это плохая идея.
системы на импульсы и псевдоимпульсы решаются абсолютно независимо друг от друга. warmstarting используется для решения системы импульсов. плохая идея — использовать warmstarting для решения системы псевдоимпульсов.

#88
6:17, 6 мая 2018

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

void doIt(TRectangularBody* rectBody, float dT)
  {

    float ERP = 0.77;
    rectBody->integrate(dT);

    vec3 normals[8];
    vec3 cPos[8];
    float depths[8];

    float count = 0;

 
    //Определяю столкновения
    for (int i = 0; i < 8; i++)
    {
      findCollisionWhisGround(rectBody->points[i], normals[i], cPos[i], depths[i]);

      if (depths[i] < 0.0f)
        count++;

    }

 


    vec3 fN = vec3(0);
    vec3 fT = vec3(0);
    vec3 fG = vec3(0, -9.8f, 0) / rectBody->invMass;


    if(count > 0)
    {
      //солвер
      for (int i = 0; i < 200; i++)
      for (int i = 0; i < 8; i++)
      {
        if (depths[i] < 0.0f)
        {

          vec3 n1 = normals[i];
          vec3 w1 = cross(normals[i], (cPos[i] - rectBody->_pos));



          solve(rectBody, n1, w1, cPos[i]);

          float x = (-depths[i] - 0.1) * ERP;

          if (x > 0)
          {
            computeCorrection(rectBody, n1, w1, x);
          }
          
          

          
        }
      }

      //вычисления сил нормальной реакции
      for (int i = 0; i < 8; i++)
      {
        if (depths[i] < 0.0f)
        {

          vec3 n1 = normals[i];


          vec3 currentFn = n1 * length(fG) * dot(n1, vec3(0, 1, 0)) / count;

          rectBody->torque += cross(cPos[i] - rectBody->_pos, currentFn);
          fN += currentFn;

        }
      }

    }


    rectBody->power = fG + fN + fT;
    
     
  }
#89
(Правка: 6:18) 6:18, 6 мая 2018

Suslik
> pos += pseudoLinearVelocity;
> coords.Rotate(pseudoAngularVelocity);
Проблема не решилась)

Suslik
> чтобы фиксить баги с дрожанием, я делаю так:
> - делаю предельно простую сцену, где баг воспроизводится
> - ставлю либо бесконечное(очень много), либо одну итерацию солвера, в
> зависимости от случая
> - рендеринг контактов с глубиной и нормалями — необходимая фича для отладки
> - включаю покадровый режим апдейта, при котором система обновляется на один dt
> при нажатии кнопки.
> - если ERP=0.7, то после решения системы глубина всех контактов должна
> уменьшиться ровно в 0.7 раз. если этого не происходит, то стандартный путь:
> invInertia = 0, отладчик внутрь джойнта и так далее.
Буду пока реализовывать соотвествующий функционал и курить это.

Страницы: 15 6 7 836 Следующая »
ПрограммированиеФорумФизика