Войти
ПрограммированиеСтатьиГрафика

Скелетная анимация и экспорт из Maya 4.0. (4 стр)

Автор:

Использование в игре

Теперь задача обратная. Есть список joint'ов с относительными преобразованиями и наборы вершин в системе координат каждого joint'а с соответствующим весом. Необходимо вывести скелет.
1.  Собрать все матрицу текущих преобразований для каждого joint'а
2.  Пересчитать вершины меша
3.  Вывести скелет с кожей

Все просто :)

Для каждого joint'а строим относительную матрицу поворота, а затем, используя ее, вектор относительного перемещения и родительскую матрицу преобразований строим текущую матрицу трансформаций. Если это корневой joint, то для него родительская матрица преобразований - единичная.

  float x = array[i].qx;
  float y = array[i].qy;
  float z = array[i].qz;
  float w = array[i].qw;

  // преобразовываем кватернион в матрицу поворота
  //
  // | 1-2*(y*y+z*z) 2*(x*y-w*z)   2*(x*z+w*z)   |
  // | 2*(x*y+w*z)   1-2*(x*x+z*z) 2*(y*z-w*x)   |
  // | 2*(x*z-w*y)   2*(y*z+w*x)   1-2*(x*x+y*y) |
  //
  array[i].relative[0][0] = 1-2*(y*y+z*z);
  array[i].relative[0][1] = 2*(x*y-w*z);
  array[i].relative[0][2] = 2*(x*z+w*y);
  array[i].relative[0][3] = 0;
  array[i].relative[1][0] = 2*(x*y+w*z);
  array[i].relative[1][1] = 1-2*(x*x+z*z);
  array[i].relative[1][2] = 2*(y*z-w*x);
  array[i].relative[1][3] = 0;
  array[i].relative[2][0] = 2*(x*z-w*y);
  array[i].relative[2][1] = 2*(y*z+w*x);
  array[i].relative[2][2] = 1-2*(x*x+y*y);
  array[i].relative[2][3] = 0;
  array[i].relative[3][0] = 0;
  array[i].relative[3][1] = 0;
  array[i].relative[3][2] = 0;
  array[i].relative[3][3] = 1;

  // применяем масштабирование
  // поскольку матрица умножается на вектор, та масштабируем строку
  for(int j = 0; j < 3; j++)
  {
    array[i].relative[0][j] *= array[i].sx;
    array[i].relative[1][j] *= array[i].sy;
    array[i].relative[2][j] *= array[i].sz;
  }

  Joint* parentJoint = array[i].parent;
  float parent[4][4];
  if(parentJoint == NULL)
  {
    // нет родительского joint'а
    parent[0][0] = 1; parent[0][1] = 0; parent[0][2] = 0; parent[0][3] = 0;
    parent[1][0] = 0; parent[1][1] = 1; parent[1][2] = 0; parent[1][3] = 0;
    parent[2][0] = 0; parent[2][1] = 0; parent[2][2] = 1; parent[2][3] = 0;
    parent[3][0] = 0; parent[3][1] = 0; parent[3][2] = 0; parent[3][3] = 1;
  }
  else
  {
    // есть родительский joint
    for(int m = 0; m < 16; m++) parent[m/4][m%4] = parentJoint->current[m/4][m%4];
  }

  // строим текущую матрицу поворота по формуле Cr = Pr * Rr
  for(int m = 0; m < 3; m++)
  {
      array[i].current[m][0] = parent[m][0]*array[i].relative[0][0] +
                               parent[m][1]*array[i].relative[1][0] +
                               parent[m][2]*array[i].relative[2][0];

      array[i].current[m][1] = parent[m][0]*array[i].relative[0][1] +
                               parent[m][1]*array[i].relative[1][1] +
                               parent[m][2]*array[i].relative[2][1];

      array[i].current[m][2] = parent[m][0]*array[i].relative[0][2] +
                               parent[m][1]*array[i].relative[1][2] +
                               parent[m][2]*array[i].relative[2][2];
  }
  array[i].current[0][3] = 0;
  array[i].current[1][3] = 0;
  array[i].current[2][3] = 0;
  array[i].current[2][3] = 1;

  // находим вектор перемещения как Ct = Pt + (Pr * Rt)
  array[i].current[3][0] = parent[3][0] + (parent[0][0]*array[i].tx +
                                           parent[0][1]*array[i].ty +
                                           parent[0][2]*array[i].tz);

  array[i].current[3][1] = parent[3][1] + (parent[1][0]*array[i].tx +
                                           parent[1][1]*array[i].ty +
                                           parent[1][2]*array[i].tz);

  array[i].current[3][2] = parent[3][2] + (parent[2][0]*array[i].tx +
                                           parent[2][1]*array[i].ty +
                                           parent[2][2]*array[i].tz);

И пересчитываем все точки в мировой системе координат, учитывая привязку к скелету.

Я использовал индексированный массив, поэтому выделил буфер для вершин, который перед пересчетом обнулил.

Для каждого joint'а проходим по массиву зависимых вершин, пересчитываем их координаты и записываем в буфер

  for(int v = 0; v < array[j].vertCount; v++)
  {
    float x0 = array[j].vertArray[4*v  ];
    float y0 = array[j].vertArray[4*v+1];
    float z0 = array[j].vertArray[4*v+2];

    // выполняем преобразование
    float x = array[j].current[0][0]*x0 + array[j].current[0][1]*y0 +
              array[j].current[0][2]*z0 + array[j].current[3][0];

    float y = array[j].current[1][0]*x0 + array[j].current[1][1]*y0 +
              array[j].current[1][2]*z0 + array[j].current[3][1];

    float z = array[j].current[2][0]*x0 + array[j].current[2][1]*y0 +
              array[j].current[2][2]*z0 + array[j].current[3][2];

    // определяем вес
    float w = array[j].influence[v];
    // и индекс в буфере
    int index = array[j].indexArray[v];

    // добавляем вершину в буфер
    buffer[4*index  ] += x*w;
    buffer[4*index+1] += y*w;
    buffer[4*index+2] += z*w;
  }

Исходный код: 20030306.zip(13k).

Автор: Гаркавец Николай - "НВП" Динамические Системы.

Страницы: 1 2 3 4

#Maya, #анимация, #скелетная анимация, #экспорт

6 марта 2003 (Обновление: 23 сен. 2009)

Комментарии [1]