Как вы помните из предьщущего материала этой главы, столкновения обрабатываются проверкой точек каждого твердого тела на попадание в объекты списка столкновений. Если точка находится внутри пространства сталкиваемого объекта, то тогда она выталкивается из него, а вектор импульса усредняется между всеми объектами таким образом, что тело отскакивает реалистично. Этой цели служит функция 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);

Итак, функция 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);

}

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

Объединение костей || Оглавление || Восстановление соединений костей