Вопрос по c++, algorithm – Определение покоящегося контакта между сферой и плоскостью при использовании внешних сил

9

У этого вопроса есть один главный вопрос и один второстепенный вопрос. Я считаю, что я прав в любом вопросе моего исследования, но не в обоих.

Для моей физической петли первое, что я делаю, это применяю силу гравитации к моейTotalForce для твердого тела объекта. Затем я проверяю наличие столкновений, используя мойTotalForce и мойVelocity, мойTotalForce сбрасывается на(0, 0, 0) после каждого цикла физики, хотя я буду держать свойvelocity.

Я знаком с проверкой столкновений между движущейся сферой и статической плоскостью при использовании только скорости. Однако, что если у меня есть другие силы, кромеvelocityнапример гравитация? Я положил другие силы вTotalForces (сейчас у меня только гравитация). Чтобы компенсировать это, когда я определяю, что сфера в настоящее время не перекрывает плоскость, я делаю

    Vector3 forces = (sphereTotalForces + sphereVelocity);
    Vector3 forcesDT = forces * fElapsedTime;
    float denom = Vec3Dot(&plane->GetNormal(), &forces);

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

denom * dist == 0.0f

кудаdist является

float dist = Vec3Dot(&plane->GetNormal(), &spherePosition) - plane->d;

(Для справки очевидноеdenom * dist > 0.0f это означает, что сфера удаляется от плоскости)

Однако это никогда не может быть правдой. Даже когда, по-видимому, существует «покоящийся контакт». Это связано с моимforces расчет выше всегда имеет, по крайней мере, .y -9,8 (моя сила тяжести). Когда при движении к плоскости с нормалью (0, 1, 0) будет получено y изdenom -9,8.

Мой вопрос

1) Правильно ли я вычисляю контакт покоя, как я упоминал в моих первых двух фрагментах кода?

Если так,

2) Как должны мои «другие силы» такие как гравитация будет использоваться? Мое использованиеTotalForces неправильно?

Для справки, мой временной шаг

  mAcceleration = mTotalForces / mMass;
  mVelocity += mAcceleration * fElapsedTime;
  Vector3 translation = (mVelocity * fElapsedTime);

EDIT

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

if(fabs(dist) <= sphereRadius)
{ // There already is a collision }
else
{
    Vector3 forces = (sphereTotalForces + sphereVelocity);
    float denom = Vec3Dot(&plane->GetNormal(), &forces);

    // Resting contact
    if(dist == 0) { }
    // Sphere is moving away from plane
    else if(denom * dist > 0.0f) { }
    // There will eventually be a collision
    else
    {
        float fIntersectionTime = (sphereRadius - dist) / denom;
        float r;
        if(dist > 0.0f)
            r = sphereRadius;
        else
            r = -sphereRadius;

        Vector3 collisionPosition = spherePosition + fIntersectionTime * sphereVelocity - r * planeNormal;
    }
}
@mmurphy: в чем смыслsphereTotalForces + sphereVelocity? Что-то не хватает в выражении? user2k5
Есть несколько элементов этого вопроса, которые заслуживают внимания, и после того, как вы также найдете решение, оно кажется сложным вопросом без большого количества ресурсов. Надеюсь, щедрость может помочь с этим. josephthomas
Что означает "покойный контакт"? значит для тебя? Значит ли это, что сфера находится в контакте с плоскостью и неподвижна? Beta
& quot; Отдыхающий контакт & quot; это состояние, в котором твердое тело (моя сфера) касается другого объекта (моей плоскости) без проникновения. Есть ли другое определение для "покоящегося контакта"? mmurphy
СфераTotalForces являетсяTotalForces (mTotalForces) Я описал, иsphereVelocity та жеmVelocity упомянуто ниже.TotalForces внешние силы, которые налагаются на текущую сферу (твердое тело) в течение этого временного шага, где какmVelocity скорость за время жизни. Если это неправильный способ справиться с этим, мне было бы интересно объяснить, как это сделать иначе. mmurphy

Ваш Ответ

6   ответов
0

тику. Если вы хотите приблизительное решение, яstrongly рекомендую разрабатывать его поэтапно.

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

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

3) Ввести статическое и кинетическое трение (независимо). Это изменит динамику скольжения. Пока не беспокойтесь о трениях при столкновениях.

4) Дайте мячу угловую скорость и момент инерции. Это большой шаг. Убедитесь, что вы можете применить к нему крутящий момент и получить реалистичные угловые ускорения. Обратите внимание, что реалистичное поведение вращающейся массы может быть нелогичным.

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

6) Попробуйте то же самое, но на наклонной поверхности. Это сравнительно небольшой шаг.

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

0

f = mg + other_f; // m = mass, g = gravity (9.8)
a = f / m; // a = acceleration
v = u + at; // v = new speed, u = old speed, t = delta time
s = 0.5 * (u + v) *t;

Когда у вас есть столкновение, вы изменяете обе скорости на 0 (или v и u = - (u * 0,7), если хотите, чтобы он отскочил).

Поскольку скорость = 0, мяч стоит на месте.

Если это 2D или 3D, то вы просто меняете скорость в направлении нормали поверхности на 0 и сохраняете параллельную скорость такой же. Это приведет к качению шара на поверхности.

Вы должны переместить шар на поверхность, если он режет поверхность. Вы можете сделать расстояние столкновения небольшим (например, 0,001), чтобы оно оставалось неподвижным.

http://www.physicsforidiots.com/dynamics.html#vuat

Редактировать:

NeHe - удивительный источник дизайна игрового движка: Вот страница по обнаружению столкновений с очень хорошими описаниями: http://nehe.gamedev.net/tutorial/collision_detection/17005/

Редактировать 2: (от NeHe)

double DotProduct=direction.dot(plane._Normal); // Dot Product Between Plane Normal And Ray Direction
Dsc=(plane._Normal.dot(plane._Position-position))/DotProduct; // Find Distance To Collision Point
Tc= Dsc*T / Dst
Collision point= Start + Velocity*Tc
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded mmurphy
-1

ш временной шаг на

mAcceleration = mTotalForces / mMass;
Vector3 translation = (mVelocity * fElapsedTime) + 0.5 * mAcceleration * pow(fElapsedTime, 2);
mVelocity += mAcceleration * fElapsedTime;

Вы упомянули, что сфера была твердым телом; Вы также моделируете самолет как жесткий? Если это так, у вас будет бесконечная точечная сила в момент контакта & amp; идеально упругое столкновение без некоторого явного рассеяния импульса.

Force & amp; скорость не суммируется (несовместимые единицы); если вы просто пытаетесь смоделировать кинематику, вы можете игнорировать массу и работать с ускорением & amp; только скорость.

Предполагая, что сфера просто сбрасывается на горизонтальную плоскость с совершенно неупругим столкновением (без отскока), вы могли бы сделать [N.B., я действительно не знаю синтаксис C, так что это будет Pythonic]

mAcceleration = if isContacting then (0, 0, 0) else (0, -9.8, 0)

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

mAcceleration = (0, -9.8, 0) + if isContacting then (0, 4.9, 0)
Error: User Rate Limit Exceededkinematics of constant acceleration
Error: User Rate Limit Exceeded mmurphy
0

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

Кроме того, большинство физических движков останавливает симуляцию на незанятых телах, и большинство игр никогда не учитывают гравитацию при движении, только при падении. Они используют «навигационные сетки» и пользовательские системы, если они уверены, что имитируемый объект придерживается своей «земли».

Я не знаю о безупречном физическом симуляторе, там всегда будет интеграционный взрыв, пропущенное столкновение (ищите «развернутое столкновение»)… это требует много эмпирических тонких настроек.

Также я предлагаю вам поискать «импульсы» Это метод, позволяющий избежать ручной настройки скорости при столкновении.

Также обратите внимание на то, «что должен знать каждый компьютерщик о числах с плавающей запятой».

удачи, вы вошли в минное поле, случайно непонятное, укусившее пальцем область числовой информатики :)

1

if(fabs(dist) < 0.0001f) { /* collided */ } This is to acocunt for floating point accuracies. You most certainly would not get an exact 0.0f at most angles or contact.

the value of dist if negative, is in fact the actual amount you need to shift the body back onto the surface of the plane in case it goes through the plane surface. sphere.position = sphere.position - plane.Normal * fabs(dist);

Once you have moved it back to the surface, you can optionally make it bounce in the opposite direction about the plane normal; or just stay on the plane.

parallel_vec = Vec3.dot(plane.normal, -sphere.velocity);

perpendicular_vec = sphere.velocity - parallel_vec;

bounce_velocity = parallel - perpendicular_vec;

you cannot blindly do totalforce = external_force + velocity unless everything has unit mass.

EDIT:

To fully define a plane in 3D space, you plane structure should store a plane normal vector and a point on the plane. http://en.wikipedia.org/wiki/Plane_(geometry) .

Vector3 planeToSphere = sphere.point - plane.point;

float dist = Vector3.dot(plane.normal, planeToSphere) - plane.radius;

if(dist < 0) { // collided. }

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

NB: Извините, форматирование испорчено ... Я не могу пометить его как блок кода.

EDIT 2: Based on my understanding on your code, either you are naming your variables badly or as I mentioned earlier, you need to revise your maths and physics theory. This line does not do anything useful.

float denom = Vec3Dot(&plane->GetNormal(), &forces);

В любой момент времени сила на сфере может быть в любом направлении, вообще не связанной с направлением движения. поэтому denom по существу вычисляет величину силы в направлении плоскости плоскости, но ничего не говорит о том, ударит ли шар по плоскости. например сила тяжести направлена вниз, но шар может иметь скорость вверх и попадать в плоскость выше. С этим вам нужноVec3Dot(plane.normal, velocity) вместо.

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

напримерs = 0.5 * (u + v) * t; дает смещение после будущего времени т. сравните это смещение с расстоянием от плоскости, и вы получите, попадет ли сфера в плоскость. Итак, еще раз, я предлагаю вам прочитатьhttp://en.wikipedia.org/wiki/Linear_motion и легкие вещи сначала тогдаhttp://en.wikipedia.org/wiki/Kinematics .

Еще один метод: если вы ожидаете или не предполагаете, что никакие другие силы не будут воздействовать на сферу, тогда вы проводите тест столкновения луча с плоскостью, чтобы найти время t, в которое она достигнет плоскости, в этом случае читайтеhttp://en.wikipedia.org/wiki/Line-plane_intersection .

Error: User Rate Limit Exceeded4Error: User Rate Limit Exceededtotalforce = external_force + velocityError: User Rate Limit Exceeded mmurphy
Error: User Rate Limit Exceededresting contactError: User Rate Limit Exceeded mmurphy
Error: User Rate Limit Exceededif(sphere.velocity.length() > 0 && dist < 0) { /* resting contact */ }Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
0

8 года. В случае подвесной сферы это приведет к ускорению вниз (чистая сила не равна нулю). В случае сферой, лежащей на плоскости, это приведет к тому, что плоскость оказывает на сферу нормальную силу. Если бы плоскость была абсолютно горизонтальной, а сфера находилась в состоянии покоя, эта нормальная сила была бы равна + 9,8 лет, что полностью нейтрализовало бы силу тяжести. Для сферы в покое на не горизонтальной плоскости нормальная сила9.8y * cos(angle) (угол между -90 и +90 градусов).

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

По вашим конкретным вопросам:

I believe contact is more specifically just when dist == 0.0f, that is the sphere and plane are making contact. I assume your collision takes into account that the sphere may move past the plane in any physics time step. Right now you don't appear to have any normal forces being put on the sphere from the plane when they are making contact. I would do this by checking for contact (dist == 0.0f) and if true adding the normal force to the sphere. In the simple case of a falling sphere onto a near horizontal plane (angle between -90 and +90 degrees) it would just be sphereTotalForces += Vector3D(0, 9.8 * cos(angle), 0).

Edit:

ОтВот ваше уравнение дляdist вычисление расстояния от края сферы до плоскости может быть неправильным в зависимости от деталей вашей задачи и кода (который не приводится). Предполагая, что ваш самолет проходит начало координат, правильное уравнение:

dist = Vec3Dot(&spherePosition, &plane->GetNormal()) - sphereRadius;

Это так же, как ваше уравнение, еслиplane->d == sphereRadius, Обратите внимание, что если плоскость не в начале координат, используйте:

D3DXVECTOR3 vecTemp(spherePosition - pointOnPlane);
dist = Vec3Dot(&vecTemp, &plane->GetNormal()) - sphereRadius;
Error: User Rate Limit Exceededdist == 0.0fError: User Rate Limit Exceeded mmurphy
Error: User Rate Limit Exceededdist == 0Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededdist == 0Error: User Rate Limit ExceededisError: User Rate Limit Exceeded
Error: User Rate Limit Exceededdist == sphereRadiusError: User Rate Limit Exceededdist == sphereRadius. mmurphy
Error: User Rate Limit Exceededdist == 0.0fError: User Rate Limit Exceeded mmurphy

Похожие вопросы