Скелетная анимация и экспорт из Maya 4.0. (4 стр)
Автор: Aidan
Использование в игре
Теперь задача обратная. Есть список 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).
Автор: Гаркавец Николай - "НВП" Динамические Системы.
#Maya, #анимация, #скелетная анимация, #экспорт
6 марта 2003 (Обновление: 23 сен 2009)
Комментарии [1]