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

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

// Вычислить новую угловую скорость State->m_vecAngularVelocity = Transform(&State- >m_vecAngularMomentum,

&State->m_matInvWorldInertiaTensor);

}

На данный момент мы рассчитали движение твердого тела, а теперь пришло время обрабатывать столкновения.

Обработка столкновений

Как вы помните из предыдущего материала этой главы, столкновения обрабатываются проверкой точек каждого твердого тела на попадание в объекты списка столкновений. Если точка находится внутри пространства сталкиваемого объекта, то тогда она выталкивается из него, а вектор импульса усредняется между всеми объектами таким образом, что тело отскакивает реалистично. Этой цели служит функция ProcessCollisions.

Яне буду приводить здесь полный код функции ProcessCollisions; вместо этого

япокажу отдельные фрагменты. Функция ProcessCollisions начинается с прототипа, который принимает в качестве параметров номер проверяемой кости и указатель на корневой объект столкновений.

BOOL cRagdoll::ProcessCollisions(DWORD BoneNum, \ cCollision *pCollision)

{

// Проверка на ошибки

if(!pCollision || !pCollision->m_NumObjects || \

!pCollision->m_Objects) return TRUE;

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

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

//Сохранять количество столкновений

DWORD CollisionCount = 0;

// Сохранять количество сил столкновений

D3DXVECTOR3 vecLinearVelocity = D3DXVECTOR3(0.0f,0.0f,0.0f) ; D3DXVECTOR3 vecAngularMomentum = D3DXVECTOR3(0.0f,0.0f,0.0f);

236

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

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

// Просмотреть все вершины кости в поисках столкновений for(DWORD i=0;i<8;i++) {

//Просмотреть все объекты столкновений cCollisionObject *pObj = pCollision->m_Objects; while(pObj) {

//Установить флаг, если обнаружено столкновение BOOL Collision = FALSE;

//Нормаль объекта столкновений D3DXVECTOR3 vecCollisionNormal;

//Расстояние, на которое необходимо вытолкнуть точку из объекта float CollisionDistance = 0.0f;

//Обработать сферический объект столкновения

if(pObj->m_Type == COLLISION_SPHERE) {

Я собираюсь вырезать кусочек кода, потому что вы уже видели, как определять столкновения, вычислять нормаль и расстояние, на которое точка проникает в объект. Если вы посмотрите полный исходный код, вы увидите, что я проверяю столкновение точки и сферы и точки и плоскости.

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

// Обработать столкновение, если обнаружено if (Collision == TRUE) {

// Вытолкнуть объект на поверхность объекта столкновения State->m_vecPosition += (vecCollisionNormal * \

CollisionDistance);

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

// Получить положение и скорость точки D3DXVECTOR3 vecPtoP = State->m_vecPosition - \

State->m_vecPoints[i]; D3DXVECTOR3 vecPtoPVelocity = \

State->m_vecLinearVelocity + \ CrossProduct(&State->m_vecAngularVelocity, \

&vecPtoP); \

// Получить скорость точки относительно поверхности float PointSpeed = D3DXVec3Dot(&vecCollisionNormal, \

&vecPtoPVelocity);

//Увеличить количество столкновений CollisionCount++;

//Вычислить силу импульса, основываясь на коэффициенте

//restitution, скорости точки и нормали сталкиваемого объекта float ImpulseForce = PointSpeed * \

(-(1.0f + Bone->m_Coefficient));

float ImpulseDamping = (1.0f / Bone->m_Mass) + \ D3DXVec3Dot(&CrossProduct( \ &Transform(&CrossProduct(&vecPtoP, \

&vecCollisionNormal), \ &State->m_matInvWorldInertiaTensor), \

&vecPtoP), &vecCollisionNormal); D3DXVECTOR3 vecImpulse = vecCollisionNormal * \

(ImpulseForce/ImpulseDamping);

// Добавить силы vecLinearVelocity += vecImpulse;

vecAngularMomentum += CrossProduct(&vecPtoP, &vecImpulse);

}

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

// Были ли столкновения if(CollisionCount) {

//Добавить усредненные силы к интегрированному состоянию State->m_vecLinearVelocity += ((vecLinearVelocity / \

Bone->m_Mass) / (float)CollisionCount); State->m_vecAngularMomentum += (vecAngularMomentum / \

(float)CollisionCount);

//Вычислить угловую скорость

State->m_vecAngularVelocity = Transform( \ &State->m_vecAngularMomentum, \

&State->m_matInvWorldInertiaTensor);

}

238

Глава 7

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

Восстановление соединений костей

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

Вспомните, в разделе "Соединение твердых тел с помощью пружин" вы научились создавать пружины между костями и использовать их для вычисления вектора силы, который немедленно перемещает и вращает тело в корректное положение. Это как раз и выполняет функция ProcessConnections - использует координаты преобразованной точки, представляющей смещение соединения (смещение от центра кости до точки ее присоединения к родителю) и координаты присоединения к родителю (хранящиеся в другой точке) для создания пружины.

void cRagdoll::ProcessConnections(DWORD BoneNum)

{

//Получить указатель на кость и родительскую кость cRagdollBone *Bone = &m_Bones[BoneNum]; cRagdollBone *ParentBone = Bone->m_ParentBone;

//Если родительской кости нет, то не продолжать if(!ParentBone)

return;

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

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

//Получить положение соединения и вектор к центру D3DXVECTOR3 vecBonePos = BState->m_vecPoints[8]; D3DXVECTOR3 vecBtoC = BState->m_vecPosition - vecBonePos;

//Получить координаты присоединения к родителю D3DXVECTOR3 vecParentPos = BState->m_vecPoints[9];

//Вычислить вектор пружины из точки к родительской точке D3DXVECTOR3 vecSpring = vecBonePos - vecParentPos;

//Переместить точку в соответствии с родительской и

//скорректировать угловую скорость и момент

BState->m_vecPosition -= vecSpring; BState->m_vecAngularMomentum -= CrossProduct(&vecBtoC, \

&vecSpring); BState->m_vecAngularVelocity = Transform( \

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