Пока делал игру, написал библиотеку для геометрической алгебры
На язык программирования не смотрите, математический код типа (a.x + b.x) везде одинаково выглядит, можете его переиспользовать где угодно.
Зачем это надо
Мне кажется, за геометрической алгеброй - будущее, и хочется его максимально приблизить :)
Если вы занимались 3д графикой, то навернаяка кроме матриц встречали кватернионы для описания вращений. Кватернионы могут показаться какими-то обособленными штуками из другой вселенной со своими правилами умножения и преобразования.
Так вот, эта вселенная - геометрическая алгебра, в которой кроме кватернионов так же есть точки, вектора, плоскости, линии, кватернионы и прочие объекты. И оно всё очень красиво и логично сочетается. Например, кватернион может вращать всё вышеперечисленное. А ещё есть объект, называемый мотором, и он вместе с вращением может задавать перемещение.
И что самое важное, это не какая-то принципиально новая непонятная фигня, а обычное расширение нам привычной линейной алгебры + проективной геометрии. Просто кроме векторов, в ней есть ещё другие объекты. И можно спокойно смешивать подходы - например, производить вычисления для кватерниона, а потом сконвертировать его в матрицу и продолжить что-то делать.
Для меня самым важным моментом является то, что в геометрической алгебре можно записывать физические законы типа F = ma и оно работает даже для сложных случаев с вращением!
- сила это "линия" (точнее, бивектор), описывается 6 числами, хранит линейную силу и момент, можно складывать несколько сил вместе.
- скорость движения - тоже бивектор из 6 чисел, хранит и скорость и угловую скорость.
- Инерция - хранит сразу и массу и момент инерции тела
Как это всё получилось
Примерно как Евклидова геометрия держится на аксиомах типа "через любые две точки можно провести прямую" и дальше из этого получается что-то полезное, так из геометрической алгеброй. В её основе лежит какая-то математика со взятыми с потолка правилами умножения, а дальше как-то так получается, что для объектов алгебры и правил умножения можно найти физический смысл.
Я использую plane-based геометрическую алгебру для 3д - в ней есть скаляры, векторы, бивекторы, тривекторы и анти-скаляр. Куча страшных слов, но можно внимательно посмотреть на получившиеся сущности и дать им нормальные имена "по смыслу" - окажется, что там есть плоскости, точки, линии и прочие привычные нам элементы. Я в своей библиотеке постарался дать понятные имена.
Например (вот код, он сгенерирован по описанию алгберы):
- Pga3dPoint - точка в пространстве, (x, y, z, 1). Последняя координата не хранится, так что в рантайме точка это просто три числа
- Pga3dVector - похож на точку, только (x, y, z, 0). Его можно получить как разность двух точек. Ещё интересный момент - кватернион вращает и точку и вектор, но транслятор перемещает только точки. Разница точек при переносе не изменяется, всё логично. Ещё можно использовать для задания "направления"
- Pga3dProjectivePoint - обобщённый случай с (x, y, z, w), и для превращения в точку надо будет поделить на w. Те кто работал с 3д графикой, должны увидеть много знакомого, просто обычно там это всё не разделяют и просто используют какой-нибудь vec3 и vec4
- Pga3dQuaternion - кватернион, описывает поворот. Его очень легко инвертировать или нормализовать (в отличие от матрицы), комбинировать два поворота можно с помощью геометрического произведения. Для вращения чего-то он домножается слева и справа, это домножение называется "сендвич" произведением (в коде - sandwich)
- Pga3dTranslator - транслятор, описывает перемещение
- Pga3dMotor - мотор, описывает и вращение и перемещение. Как и кватернион, чуток избыточный - хранит 8 чисел, хотя степеней свободы 6. Как и кватернион, очень легко нормализовать или инвертировать.
- Pga3dPlane - плоскость. Что забавно, кватернион вращает объекты, а плоскость - отражает. И кватернион/мотор - это просто комбинация двух отражений от двух плоскостей.
- Pga3dPlaneIdeal - плоскость, проходящая через центр координат
- Pga3dBivector - 6 компонент. Смысл в него можно вкладывать разный, так что оставил название как есть. Может описывать силу, скорость, линию. Логарифм от мотора - бивектор, экспонента от бивектора - мотор. С их помощью можно интерполировать или экстраполировать движение.
- Pga3dBivectorBulk - только 3 компоненты от бивектора, описывает чисто вращательное движение, экспонента от него - кватернион.
- Pga3dBivectorWeight - другие три компоненты, описывают чисто перемещение, экспонента - транслятор.
Физика
Поверх всего этого я навернул физики: классы для инерции и солверы для симуляции движения. А так же вспомогательные классы типа Pga3dVelocity и Pga3dForque с понятными методами типа "сделай линейную силу", потому что записть типа `point v force` конечно красивая, но плохо запоминается.
И ещё что круто - я использую метод Рунге-Кутты четвёртого порядка, и точность действительно четвёртого порядка. Это очень важный момент.
Фишка в том, что для метода Рунге-Кутты надо складывать несколько перемещений с разными коэффициентами, и я просто беру моторы, домножаю на коэффициенты и складываю. Всё работает!
Как такое сделать корректно, если вращение и перемещение будут отдельными сущностями, я не очень понимаю. А если сделать с ошибками - порядок точности останется вторым и выше расти не будет.
Примеры того, как использовать - в тестах рядом с кодом.
Что можно сделать дальше
- Можно переиспользовать кусочки моего кода, если хочется.
- Можно написать мне, если есть идеи как сделать библиотеку лучше (и если что-то не понятно - тоже пишите)
- Можно сделать такую же библиотеку для другого языка типа С++ или C#. Большая часть кода сгенерирована автоматически, дописать генерацию для ещё одного языка будет несложно. Я это пока не сделал, потому что не было необходимости. Может быть я когда-нибудь попробую сделать физический движок для Unreal Engine.
Ссылки
Сайт на английском с кучей инфы: bivector.net