Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
DirectX. Продвинутая Анимация (2004) [rus].pdf
Скачиваний:
335
Добавлен:
16.08.2013
Размер:
8.39 Mб
Скачать

Созданиекукольнойанимации

if(vecSize->y < MINIMUM_BONE_SIZE) { vecSize->y = MINIMUM_BONE_SIZE; vecMax.y = MINIMUM_BONE_SIZE*0.5f;

}

ifvecSize->z < MINIMUM_BONE_SIZE) { vecSize->z = MINIMUM_BONE_SIZE; vecMax.z = MINIMUM_BONE_SIZE*0.5f;

}

//Установать смещение кости в центр, основываясь на половине

//размера ограничивающего параллелепипеда и максимальном

//положении

(*vecJointOffset) = ((*vecSize) * 0.5f) - vecMax;

}

В самом конце функции вы наконец то обнаружите вектор vecJointOffset о котором я говорил при создании функции GetBoundingBoxSize. Т. к. кость твердого тела может быть любого размера, а вы отслеживаете ее с помощью координат ее центра, необходимо создать дополнительную точку, которая бы представляла собой точку присоединения ограничивающего параллелепипеда к родителю. Это и есть вектор смещения соединения. Вы узнаете о нем больше при изучении усиления связей костей.

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

Установка сил

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

void cRagdoll::SetForces(DWORD BoneNum, D3DXVECTOR3 *vecGravity,

float LinearDamping, float AngularDamping)

{

//Получить указатель на кость cRagdollBone *Bone = &m_Bones[BoneNum];

//Получить указатель на текущее состояние cRagdollBoneState *BCState = &Bone->m_State;

//Установить гравитацию и очистить момент

Bone->m_vecForce = ((*vecGravity) * Bone->m_Mass);

Bone->m_vecTorque = D3DXVECTOR3(0.0f, 0.0f, 0.0f);

232

// Наложить амортизацию на силу и момент Bone->m_vecForce += (BCState->m_vecLinearVelocity * \

LinearDamping);

Bone->m_vecTorque += (BCState->m_vecAngularVelocity * \ AngularDamping);

}

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

После того как вы установили силы, вы можете находить (интегрировать) движение заданной кости.

Объединение костей

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

В разделе "Обработка движений твердого тела" вы видели, как прикладывать векторы силы и моменты к линейной скорости и угловому моменту для создания движения. В функции cRagdoll::Resolve я просто повторяю все прочитанное вами в том разделе.

Вы заметите, что значения положения, ориентации, скорости и момента хранятся в классе состояния кости cRagdollBoneState. Эти векторы используются при разрешении. Для вызова Integrate необходимо задать в качестве параметров обрабатываемую кость и время обработки (прошедшее время).

void cRagdoll::Integrate(DWORD BoneNum, float Elapsed)

{

//Получить указатель на кость cRagdollBone *Bone = &m_Bones[BoneNum];

//Получить указатели на состояния cRagdollBoneState *State = &Bone->m_State;

После того как вы получили указатель на класс кости (и указатель на объект состояния кости), вы вычисляете новое положение кости, основываясь на линейной скорости, изменение углового момента, основываясь на моменте, и изменение линейной скорости, основываясь на величине силы (масштабированной на массу объекта).

Созданиекукольнойанимации

// Сложить положения

State->m_vecPosition += (Elapsed*State->m_vecLinearVelocity);

// Сложить угловой момент

State->m_vecAngularMomentum += (Elapsed * Bone->m_vecTorque);

// Сложить линейную скорость

State->m_vecLinearVelocity += Elapsed * Bone->m_vecForce / \ Bone->m_Mass;

Теперь вычисляется новая ориентация (хранимая в кватернионе), используя угловую скорость, умноженную на прошедшее время.

// Сложить ориентацию кватернионов

D3DXVECTOR3 vecVelocity = Elapsed * State->m_vecAngularVelocity; State->m_quatOrientation.w -= 0.5f *

(State->m_quatOrientation.x * vecVelocity.x + State->m_quatOrientation.y * vecVelocity.y + State->m_quatOrientation.z * vecVelocity.z);

State->m_quatOrTentation.x += 0.5f *

(State->m_quatOrientation.w * vecVelocity.x - State->m_quatOrientation.z * vecVelocity.y + State->m_quatOrientation.y * vecVelocity.z);

State->m_quatOrientation.y += 0.5f * (State->m_quatOrientation.z * vecVelocity.x + State->m_quatOrientation.w * vecVelocity.y - State->m_quatOrientation.x * vecVelocity.z);

State->m_quatOrientation.z += 0.5f *

(State->m_quatOrientation.x * vecVelocity.y - State->m_quatOrientation.y * vecVelocity.x + State->m_quatOrientation.w * vecVelocity.z);

// Нормализовать кватернион (получая единичный кватернион) D3DXQuaternionNormalize(&State->m_quatOrientation,

&State->m_quatOrientation);

До этого момента я не рассказывал вам, как предотвратить неуправляемое искажение костей кукольного меша. Подумайте, т. к. кости являются твердыми телами, они могут вращаться в любом направлении на любой угол, так что, например, голова вашего персонажа может вращаться через грудь. Таким образом, я представляю вашему вниманию использование фактора разрешения вращения в объявлении каждого кукольного объекта.

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

234

Глава 7

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

// Заставить разрешение вращения

if(BoneNum && Bone->m_ResolutionRate != 0.0f) {

// сферическая интерполяция от текущей ориентации к начальной D3DXQUATERNION quatOrientation = \

Bone->m_ParentBone->m_State.m_quatOrientation * \ Bone->m_quatOrientation;

D3DXQuaternionSlerp(&State->m_quatOrientation, \ &State->m_quatOrientation, \ &quatOrientation, \

Bone->m_ResolutionRate);

}

Двигаемся дальше. Оставшийся код функции Integrate создает матрицу преобразования, которая потом используется для преобразования точек костей твердого тела и создания угловой скорости. Т. к. мы работаем с левосторонней системой координат, после создания матрицы преобразования необходимо ее транспонировать при помощи функции D3DXMatrixRotationQuaternion. Этот шаг обсуждался ранее.

//Вычислить новую ориентацию при помощи матрицы преобразования

//полученной из только что посчитанного кватерниона D3DXMatrixRotationQuaternion(&State->m_matOrientation,

&State->m_quatOrientation); D3DXMatrixTranspose(&State->m_matOrientation,

&State->m_matOrientation);

// Вычислить суммарный тензор мировой инерции D3DXMATRIX matTransposedOrientation; D3DXMatrixTransposw(&matTransposedOrientation, &State- >m_matOrientation);

State->m_matInvWorldInertiaTensor = State->m_matOrientation * Bone->m_matInvInertiaTensor * matTransposedOrientation;

Соседние файлы в предмете Программирование на C++