Neuroware
@Neuroware
Программист в свободное от работы время

Как реализовать скелетную модель?

Для одной задумки потребовалось реализовать скелетную модель (не столько графически, сколько алгоритмически).
Вопрос в том как хранить такие структуры. В идеале должно быть чтото вроде "точек-суставов" и "костей", которые соответственно соеденены с "суставами", с этим вроде как проблем нет, проблема в том, как отражать изменения во всей моделе, к примеру одна из точек сдигается на N влево и вперед, соответственно остальное должно за ней подтянуться, кости не должны отваливаться и растягиваться, но как это описать не могу понять.
В идеале нужно иметь возможность в любой момент времени получить полную информацию о всех костях (угол относительно x или y, высота над некой абстрактной плоскостью для каждой из точек суставов кости) и иметь возможность смещать каждую из точек суставов в том или ином направлении. Если кто знаейт пните в каком направлении можно копать?
skeletal-animation-5.gif
  • Вопрос задан
  • 673 просмотра
Решения вопроса 5
AMar4enko
@AMar4enko
Задача в целом чуть сложней, искать по фразе "Инверсная кинематика".
Вот есть статья на хабре habrahabr.ru/post/222689
Ответ написан
Комментировать
vvovas
@vvovas
Не специалист, но в голову пришла следующая мысль: храните дерево костей, каждая кость имеет длину и направление.
Двигаете кость А, кости наследники автоматом будут двигаться, так как не привязаны к конкретным координатам, а привязаны только к родительской кости.
Отрисовывать пробегом по костям и просчетом положения.
Ответ написан
Writerim
@Writerim
Заполнить позже...
--- children ---
id | id_parent | x2 | y2 |

--- parent ---
id | x1 | y1 |

Таким образом вы сможете получать все длины и все вершины и строить скелет не отходя от кассы.
В parent будет скорее всего у вас всего одна точка.
Ответ написан
Комментировать
DmitryITWorksMakarov
@DmitryITWorksMakarov
Мне кажется, такого интерфейса для базового элемента достаточно:

interface IBone 
{
    float angle; // in radians
    float length;

    IEnumerable<IBone> children;
}


Из соображений оптимизации и исключения всяких тригонометрий можно хранить не угол и длину, а смещение по Х и смещение по Y, хотя в полярной системе координат по мне так наглядней.

При необходимости рисования скелета делаем так:

void DrawBone(Graphics inGraphics, PointF inPosition, IBone inBone)
{
    var boneEnd = inPosition + new SizeF((float)(inBone.length * Math.Cos(inBone.angle)), 
                                         (float)(inBone.length * Math.Sin(inBone.angle)));

    inGraphics.DrawLine(Pens.Black, inPosition, boneEnd);

    foreach (var next in inBone.children)
    {
        DrawBone(inGraphics, boneEnd, next);
    }
}
Ответ написан
Nipheris
@Nipheris Куратор тега C#
Сергей Иванов дал хорошую идею, только не раскрыл до конца. В общем вам действительно будет полезна иерархия - если какая-то кость связана с другой, то эта другая будет для первой точкой отсчета - своей системой координат. Даже ваш рисунок подсказывает, что каждая кость - это вектор, а точка привязки - это начало кости. Т.о. вам достаточно для каждой кости хранить "родительскую" кость (к которой мы привязаны) - для пальцев это будет кисть или локтевой сустав, и вектор - направление кости. Тогда для перемещения группы костей вам достаточно будет переместить ТОЛЬКО родительскую для этой группы (модифицировать ее вектор). А алгоритм определения положения дочерних костей должен будет идти по дереву костей и складывать родительские и дочерние вектора, пока не дойдет до листьев костяного дерева.
update: собственно, у Дмитрий Макаров то же самое)
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

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