forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   C++ (http://forum.boolean.name/forumdisplay.php?f=22)
-   -   Как я осилил скелетную анимацию. (http://forum.boolean.name/showthread.php?t=18637)

pozitiffcat 17.10.2013 23:52

Как я осилил скелетную анимацию.
 
Для своего движка (Indie engine), понадобилось использовать ms3d модели со скелетной анимацией, причем что бы это все работало на мобильных устройствах. Мучился с этим я долго, я не понимал вообще ничего, и наконец-то получилось. Я хочу поделиться опытом.

Стоит запомнить несколько правил.
- Создайте отдельный класс скелета
- Класс скелета хранит структуры костей
- Кость знает про своего родителя, имеет позицию и поворот в локальной системе координат, так же кость знает про ключевые кадры анимации
- Кадр знает про СМЕЩЕНИЕ позиции и поворота (это важно), и время кадра
- вершина должна знать про порядковый номер кости из скелета (несколько костей и вес для каждой)

пример структуры вершины:
Код:

struct Vertex
{
    Vertex(float x = 0, float y = 0, float z = 0, float nx = 0, float ny = 0, float nz = 1, float u = 0, float v = 0,
          int joint1 = 0, float weight1 = 0, int joint2 = 0, float weight2 = 0, int joint3 = 0, float weight3 = 0, int joint4 = 0, float weight4 = 0)
        : x(x), y(y), z(z), nx(nx), ny(ny), nz(nz), u(u), v(v)
    {
        if (joint1 < 0) joint1 = 0;
        if (joint2 < 0) joint2 = 0;
        if (joint3 < 0) joint3 = 0;
        if (joint4 < 0) joint4 = 0;

        joint[0] = joint1;
        weight[0] = joint1 >=0 ? weight1 : 0;

        joint[1] = joint2;
        weight[1] = joint2 >=0 ? weight2 : 0;

        joint[2] = joint3;
        weight[2] = joint3 >=0 ? weight3 : 0;

        joint[3] = joint4;
        weight[3] = joint4 >=0 ? weight4 : 0;
    }

    float x, y, z;
    float nx, ny, nz;
    float u, v;
    float joint[4];
    float weight[4];
};

Со структурой разобрались. Можно заполнять скелет данными.

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

Ребята кому не понятно и кто тоже страдает от скелетной анимации я постараюсь помочь чем смогу. Не буду отвечать на вопросы как заполнить шейдер матрицами костей, только по теме. Тема скелетная анимация а не учимся программировать шейдеры :crazy:

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

Ах да забыл про шейдер. Приведу его код:

Код:

const std::string texturedAnimShaderVs = ""
        "attribute vec4 position;\n"
        "attribute vec2 texcoord;\n"
        "attribute vec4 jointId;\n"
        "attribute vec4 weight;\n"
        "uniform mat4 mvp;\n"
        "uniform mat4 joints[64];\n"
        "varying vec2 vTexcoord;\n"
        "void main(){\n"
        "  vec4 newVertex;\n"
        "  mat4 newMat = joints[int(jointId.x)] * weight.x;\n"
        "  newMat += joints[int(jointId.y)] * weight.y;\n"
        "  newMat += joints[int(jointId.z)] * weight.z;\n"
        "  newMat += joints[int(jointId.w)] * weight.w;\n"
        "  newVertex = newMat * position;\n"
        "  gl_Position = mvp * newVertex;\n"
        "  vTexcoord = texcoord;\n"
        "}\n";

const std::string texturedAnimShaderFs = ""
        "uniform sampler2D texture0;\n"
        "varying vec2 vTexcoord;\n"
        "void main(){\n"
        "  gl_FragColor = texture2D(texture0, vTexcoord);\n"
        "}\n";


pozitiffcat 20.10.2013 03:27

Ответ: Как я осилил скелетную анимацию.
 
Сейчас заметил такую важную вещь. Я использовал для вращения углы эйлера (обычные XYZ), оказывается в некоторых сложных ситуациях они ведут себя неадекватно, поэтому нужно использовать кватернионы. Учтите это.

jimon 25.10.2013 00:01

Ответ: Как я осилил скелетную анимацию.
 
в общую солянку

скелет на дуал кватернионах, скелет и все анимации располагаются в сплошном куске памяти (можно за один fread читать)
https://github.com/tatemgames/tateng...r/teSkeleton.h

шейдер скининга на дуал кватернионах
https://github.com/tatemgames/tateng....cpp#L186-L220

Mr_F_ 25.10.2013 00:41

Ответ: Как я осилил скелетную анимацию.
 
говорят, под дуалы надо чтобы артисты скинили заранее.
говорят, далеко не все так умеют и вообще мало принято.
в существующих играх (например, red dead redemption) наблюдается создание множества промежуточных костей между основными, чтобы фиксить всякие скрючивания.

jimon 25.10.2013 23:20

Ответ: Как я осилил скелетную анимацию.
 
Mr_F_
я так понял что дуалы нормально только в последних maya можно делать, там надо скининг режим сразу выставить в dual quaternion и тогда maya будет корректно их рендерить и никаких проблем

из заюзали в cryengine и кроме нормала на стыках проблем не имели (TBN привет говорит на дуал кватах)

они куда дешевле матриц, и в принципе хороши, можно даже дерево сцены на дуал кватах писать если без скейлинга обойтись, что достаточно сильно ускорило бы работу на большом количестве объектов


Часовой пояс GMT +4, время: 12:06.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot