Инверсная кинематика (2 сегмента, один эффектор и узел)

Инверсная кинематика (2 сегмента, один эффектор и узел) Кинематика, Gamedev, Программирование, Длиннопост, Abandonedlands

Здорово, народ!

Судя по тому, сколько людей ждёт этот пост, деваться особо некуда.
Как и обещал, рассказываю о том, каким образом проводилось вычисление положения частей рук относительно их крепления к туловищу.

Для начала вообще нужно уяснить, какие данные мы хотим дать игре, чтобы она произвела расчет. У нас всегда есть (по крайней мере, должна быть) х- и y-координата точки крепления руки к телу и длина частей руки. А вот дальше интереснее: если нам дан угол сочленения - то эта прямая кинематика и задача состоит в том, чтобы найти х- и y-координаты кисти воображаемой руки; ну а если даны эти самые координаты - то мы работаем с обратной (инверсной) кинематикой и найти нужно как раз углы, задающие положения сегментов в пространстве.


Как решать?
Для начала d - это расстояние от XY0 до XY1, но с небольшой оговоркой. Нельзя допустить, чтобы d было больше суммы длин наших сегментов, потому что при d равном этой величине мы получим максимально возможный угол - развернутый (180 градусов). Также резонно указать нижнюю границу, модуль разности длин сегментов вполне подойдет.

Инверсная кинематика (2 сегмента, один эффектор и узел) Кинематика, Gamedev, Программирование, Длиннопост, Abandonedlands

Получив а и b, работаем с прямоугольными треугольниками и получаем значения углов в радианах. Для того, чтобы их применить на ручках, остается только перевести их в градусную меру и прибавить к ним отклонение от оси ОХ (расчет углов ведется против часовой стрелки, поэтому чтобы направить ручки вниз, отнимаем их от дефолтных 0 градусов).
Важно: здесь мы никак не задаем ограничение на поворот вокруг XY0.


Для удобства можно вогнать это всё в скрипт:

GML: script get_angle

var x1=argument0, y1=argument1, x2=argument2, y2=argument3, r0=argument4, r1=argument5,
d=median(point_distance(x1, y1, x2, y2), r0+r1, max(r0, r1)-min(r0, r1);
var a, b, dir, angle;
a=(sqr(r0)-sqr(r1)+sqr(d))/(2*d)
b=d-a
dir=point_direction(x1, y1, x2, y2)
angle[0]=-radtodeg(arccos(a/r0)+dir
angle[1]=-radtodeg(arcsin(b/r1))+dir+90;
return angle

GML: вызов скрипта get_angle (пример):

langle=get_angle(xl,yl,xr+lengthdir_x(38, arms_angle),yr+7+lengthdir_y(38, arms_angle)-8,r0,r1);

Возникает вопрос, а какие точки можно использовать в качестве XY1?

Инверсная кинематика (2 сегмента, один эффектор и узел) Кинематика, Gamedev, Программирование, Длиннопост, Abandonedlands

Такой скрипт можно использовать для разных целей.
Вот, допустим, нам нужно, чтобы игрок держал автомат с упором к плечу. В таком случае естественно, что он будет держаться руками на рукоятку и цевье/магазин.
Если упором является плечо, то резонно будет осью считать саму точку упора. Оружие будет вращаться вслед за мышью по этой оси.
Например, для правой руки с координатами крепления rx1,ry1, вызов скрипта будет выглядеть так:

GML: get_angle для правой руки, отрисовка:

rangle=get_angle(xr,yr,xr+lengthdir_x(30, arms_angle),yr+lengthdir_y(30, arms_angle),r0,r1)
Xright=xr+lengthdir_x(r0, rangle[0])*player_xscale;
Yright=yr+lengthdir_y(r0, rangle[0]);
draw_sprite_ext(kombineson[4], 1, Xright, yr+lengthdir_y(l1, rangle[0])+sinready, 1, 1, rangle[1], c_white, 1)
draw_sprite_ext(kombineson[4], 0, xr, yr+sinready, 1, 1, rangle[0], c_white, 1)

Где 30 - это длина в пикселях от плечевого упора до рукоятки, за которую держится кисть.
Что примечательно, левая рука при прибавлении к координатам lx1,ly1 поправки будет ориентироваться на место крепления правой руки, так как ось вращения автомата с самой левой рукой никакой связи, кроме как точки lx2,ly2, не имеет:

GML: get_angle для левой руки, отрисовка:

langle=get_angle(xl,yl,xr+lengthdir_x(38, arms_angle),yr+7+lengthdir_y(38, arms_angle)-8,r0,r1)
Xleft=xl+lengthdir_x(r0, langle[0])*player_xscale;
Yleft=yl+lengthdir_y(r0, langle[0]);
draw_sprite_ext(kombineson[3], 0, xl, yl+sinready, 1, 1, langle[0], c_white, 1)
draw_sprite_ext(kombineson[3], 1, Xleft, Yleft+sinready, 1, 1, langle[1], c_white, 1)

Где 38 - это расстояние от плечевого упора до передней части магазина, к которой и крепится lx2,ly2.


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

Всем добра и до скорого!

Лига Разработчиков Видеоигр

6.8K постов22.2K подписчиков

Добавить пост

Правила сообщества

ОБЩИЕ ПРАВИЛА:

- Уважайте чужой труд и используйте конструктивную критику

- Не занимайтесь саморекламой, пишите качественные и интересные посты

- Никакой политики


СТОИТ ПУБЛИКОВАТЬ:

- Посты о Вашей игре с историей её разработки и описанием полученного опыта

- Обучающие материалы, туториалы

- Интервью с опытными разработчиками

- Анонсы бесплатных мероприятий для разработчиков и истории их посещения;
- Ваши работы, если Вы художник/композитор и хотите поделиться ими на безвозмездной основе

НЕ СТОИТ ПУБЛИКОВАТЬ:

- Посты, содержащие только вопрос или просьбу помочь
- Посты, содержащие только идею игры

- Посты, единственная цель которых - набор команды для разработки игры

- Посты, не относящиеся к тематике сообщества

Подобные посты по решению администрации могут быть перемещены из сообщества в общую ленту.

ЗАПРЕЩЕНО:

- Публиковать бессодержательные посты с рекламой Вашего проекта (см. следующий пункт), а также все прочие посты, содержащие рекламу/рекламные интеграции

- Выдавать чужой труд за свой

Подобные посты будут перемещены из сообщества в общую ленту, а их авторы по решению администрации могут быть внесены в игнор-лист сообщества.


О РАЗМЕЩЕНИИ ССЫЛОК:

Ссылка на сторонний ресурс, связанный с игрой, допускается только при следующих условиях:

- Пост должен быть содержательным и интересным для пользователей, нести пользу для сообщества

- Ссылка должна размещаться непосредственно в начале или конце поста и только один раз

- Cсылка размещается в формате: "Страница игры в Steam: URL"