MikeNew
> Используешь float или может double?
> как у тебя происходит нормализация вектора нормали
class vec3 { public: union { struct { float x, y, z; }; float Arr[ 3 ]; }; ... }; inline void vec3 :: Normalize() { float l = sqrtf( x * x + y * y + z * z ); x /= l; y /= l; z /= l; } inline vec3 vec3 :: GetNorm( ) { float l = sqrtf( x * x + y * y + z * z ); return vec3( x / l, y / l, z / l ); } inline vec3& VecMul( const vec3 &v1, const vec3 &v2 ) { vec3 v; v.x = v1.y * v2.z - v1.z * v2.y; v.y = v1.z * v2.x - v1.x * v2.z; v.z = v1.x * v2.y - v1.y * v2.x; return v; }
Проверка на 0 вынесена из функций
Конкретно при решении контакта так:
if (ContNormal.LengthSqr( ) > 0.0001f * 0.0001f ) { ContNormal.Normalize( ); }
т. е. околонулевой вектор не меняется
Проблемы с точностью возникали только когда очень большая куча лежит и долго не хочет замерзать, но решение все равно должно сходиться просто медленнее.
Всё-таки, не думаю, что дело в точности. Если нормально решаются обычные контакты нормали/трения, то это сам по себе показатель.
Ведь контакты нормали у тебя не глючат, если один кубик уронить на другой так, чтобы точка контакта лежала на одной линии с их центрами масс. А здесь всё то же самое, только направление удара другое.
Для шарового контакта не нужны нормали, в принципе. Попытка их как-то использовать, как раз, может приводить к проблемам. Альтернативно, шаровой контакт можно считать тремя обычными с нормалями вдоль X, Y и Z.
}:+()___ [Smile]
> шаровой контакт можно считать тремя обычными с нормалями вдоль X, Y и Z
Вместо
SolveContact( Normal );
использовать
SolveContact( vec3( 1, 0, 0 ) );
SolveContact( vec3( 0, 1, 0 ) );
SolveContact( vec3( 0, 0, 1 ) );
?
Чем это отличается от
SolveContact( vec3( 1, 1, 1).GetNorm() );
?
PS Хотя подумал, смысл может быть. Точки не будет болтать в перпендикулярной нормали плоскости. Этакий аналог двухосевого трения.
texture3D
> Всё-таки, не думаю, что дело в точности. Если нормально решаются обычные контакты нормали/трения, то это сам по себе показатель.
Меня вот что смущает:
в примере с палками, у которых точки контактов нулевые и которые все равно раскручиваются вокруг оси Y.. так вот раскручиваются они достаточно сильно, а значения w2_1.y и w1_1.y не более чем 0.000136, значит угловая скорость по Y должна быть настолько мала, что должна гасится уже угловым воздушным трением (которое работает, я проверил). Это странно, надо мне сначала с эти подозрительным моментом разобраться, как с самым простым.
Продолжаю искать.
PS Смотри, как ее жестко крутит вокруг оси Y при таком малом значении w1_1.y
Так определенно быть не должно.

MikeNew
> ее жестко крутит вокруг оси Y
А это её не трение о землю крутит?
> ее жестко крутит вокруг оси Y при таком малом значении w1_1.y
Так может там nImpulse большой
Obj1.AngVel += (Obj1.AxisX * ( nImpulse * wwwx1 ) ); Obj1.AngVel += ( Obj1.AxisY * ( nImpulse * wwwy1 ) ); Obj1.AngVel += ( Obj1.AxisZ * ( nImpulse * wwwz1 ) );
Ну или стоит инерцию подкрутить
Вообще, }:+()___ [Smile] интересную мысль предложил.
texture3D
> А это её не трение о землю крутит?
Она в невесомости в воздухе.
Никаких джойнтов вообще нет, кроме клеевого.
texture3D
> Ну или стоит инерцию подкрутить
С инерцией вроде все в порядке - я подвесил палку в невесомости, когда тестировал угловое воздушное торможение и потыкал ее силой - выглядит все более чем адекватно.
Попробую сделать как Смайл написал, когда соображу как.
texture3D
> PS Хотя подумал, смысл может быть. Точки не будет болтать в перпендикулярной нормали плоскости. Этакий аналог двухосевого трения.
Интересно, почему у тебя не болтает. Вопрос на миллион. Движок тоже на флоатах, все считается так же как у меня.
}:+()___ [Smile]
> Для шарового контакта не нужны нормали, в принципе.
А как якобиан считать без нормали? Что выполняет ее роль? Что-то же нужно.
}:+()___ [Smile]
> Для шарового контакта не нужны нормали, в принципе. Попытка их как-то использовать, как раз, может приводить к проблемам. Альтернативно, шаровой контакт можно считать тремя обычными с нормалями вдоль X, Y и Z.
Можно, пожалуйста, чуть подробнее, для альтернативно-одаренных типа меня?
Это как texture3D написал?:
SolveContact( vec3( 1, 0, 0 ) );
SolveContact( vec3( 0, 1, 0 ) );
SolveContact( vec3( 0, 0, 1 ) );
texture3D
> Так может там nImpulse большой
Вот только он не должен быть большим, неоткуда большим значениям взять при таких скоростях и силах.
Надо будет глянуть его значения.
texture3D
> Ну или стоит инерцию подкрутить
Полагаю, если бы проблема была в инерции, то это было бы видно и при обычных столкновениях.
Кстати, попытался сделать сустав из двух джойнтов (опять без псевдоскоростей, для упрощения, чтобы исключить их влияние на проблему):

Так что, судя по всему, предрешено мне сражаться с этим багом до последнего, либо я его либо он меня. :D
Непонятно, почему правое тело в конце видео не уезжает вслед за левым.
А если расположить так чтобы тела были как можно ближе друг к другу, только чтобы эти боксы не задевали себя при поворотах.
И при этом чтобы точки p1,p2 совпадали?

То есть не как сейчас вверху, а как внизу.
И упростим еще.
Пусть точка приложения импульса будет не
p = p1 + 0.5f * ( p2 - p1 );
а
p = p1;
И вместо вызова как сейчас
Solve( ContNormal, p );
сделать как предложил }:+()___ [Smile]
Solve( vec3( 1, 0 , 0) , p );
Solve( vec3( 0, 1 , 0) , p );
Solve( vec3( 0, 0 , 1) , p );
То что сейчас должно обнулять скорость точек p1; p2 относительно друг друга в направлении ContNormal,
а это будет последовательно по осям просто обнулять скорость точек p1; p2 относительно друг друга без конкретного направления.
MikeNew
> Можно, пожалуйста, чуть подробнее, для альтернативно-одаренных типа меня?
Для шарового контакта надо полностью погасить относительную скорость контактных точек двух тел и обнулить относительную позицию (но это уже псевдоскорости). Скорость обнуляется путем приложения к этим точкам противоположных импульсов. Изменение скорости линейно зависит от импульса, матрица этой зависимости — Якобиан — имеет три сточки (а не одну, как для обычного контакта), ибо у обменного импульса три компоненты. Каждая строчка матрицы — это изменение скорости в ответ на единичный импульс вдоль осей X, Y и Z, что суть три Якобиана для контактов с нормалями вдоль осей. Таким образом, шаровой контакт математически эквивалентен трем контактам по осям с k = 0 без трения (или одному, но с бесконечным трением и произвольной нормалью).
texture3D
> А если расположить так чтобы тела были как можно ближе друг к другу, только чтобы эти боксы не задевали себя при поворотах.
> И при этом чтобы точки p1,p2 совпадали?
> Изображение
>
> То есть не как сейчас вверху, а как внизу.
>
> И упростим еще.
>
> Пусть точка приложения импульса будет не
> p = p1 + 0.5f * ( p2 - p1 );
> а
> p = p1;
>
> И вместо вызова как сейчас
Ничего не изменилось, ровно такой же баг.
texture3D
> сделать как предложил }:+()___ [Smile]
Сначала решил разобраться с ошибкой солвера, который по любому у меня есть. А то сделаю, а проблема потом опять вылезет. У тебя же работает нормально без рецепта Смайла, что свидетельствует что у меня баг, который лучше устранить раз и навсегда.
Присмотревшись, заметил что до определенного этапа все происходит правильно, но когда нормаль и w1_1 (w2_1) начинают приближаться к тому чтобы совпасть по направлению (с 4-ой секунды видео) - происходит нездоровое нарастание угловой скорости и солвер как бы стремится сделать так, что нормаль и w1_1 (w2_1) совпали по направлению, выровнять палки так, чтобы они стали параллельны (и делает это слишком рано), чего он точно делать не должен (уверен, что у тебя ничего подобного нет):

Это очень нездоровая ситуация, полагаю при столкновениях у меня не видно ее только потому что там импульсы обнуляются в солвере при проникновении тел друг в друга. Плюс, я вспомнил что раньше заметил, что если ронять, например, палку на платформу под таким углом чтобы она упала на вершину (то есть нет контактной площадки), ее как-то немножко неправильно закручивает вдоль оси Y во время окончательного падения после касания. В свое время я забил на этот момент, потому что его почти не видно и теперь мне вылезло это боком.
texture3D
> .
Придумал хитрожопый способ отслеживания бага.
Подвешу две палки в невесомости в начальном положении где солвер работает правильно и отключу угловое воздушное трение.
Приложу силу к центру одной из палок, она полетит с постоянной линейной скоростью, солвер начнет работу, появится угловая скорость, которая тоже будет строго постоянной. Когда солвер начнет глючить и творить расколбас - угловая скорость возрастет и это будет началом неправильной работы солвера (или другой части физического движка) и вот в этот момент начну смотреть все значения от и до.
По результатам тестов сразу возник вопрос.
Есть два тела в невесомости, нет воздушного трения (то есть если мы приложим линейную силу к одному из тел, оно полетит в бесконечность с постоянной линейной скоростью, если приложим угловую силу - начнет бесконечное вращение с постоянной угловой скоростью).
Тела одинаковые, соединены клеевым контактом (красный цвет) без псевдоскоростей (расстояние между точками контактов в результате движений тел может уменьшаться, но увеличится уже не может, солвер не дает).
Прикладываем однократно к первому телу линейную силу F:

сразу начинает работать солвер и тела получают угловые скорости:

Причем эти скорости с самого начала понемногу увеличиваются, что вызвало у меня подозрение.
Это правильно с точки зрения физики при данном контакте или баг начинается уже с этого момента?
texture3D
}:+()___ [Smile]
Пожалуйста, напишите ваше мнение.
Имеешь в виду, что было однократное воздействие, линейные скорости изменились ровно 1 раз, а угловые все время растут?
Выглядит нелогично.
Вообще в солвере допустить ошибку немудрено, в своё время я где-то просто перепутал знак при сложении линейной и угловой скорости для вычисления скорости точки при выводе вот этого
Тема в архиве.