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