Создаваемая функция проверки столкновений должна просмотреть все точки одежды и для каждой точки проверить, происходит ли ее столкновение с каким-либо объектом столкновений, содержащимся в связанном списке объектов. Вызовете функцию CheckCollision; в качестве параметров задайте указатель на объект cCollision для проверки столкновений точки и объекта и матрицу преобразования, которая используется для расположения и ориентирования объектов столкновений в трехмерном мире.
void CheckCollisions(cCollision *pCollision, \ D3DXMATRIX *matTransform)
{
// Просмотреть все точки for(DWORD i=0;i<NumPoints;i++) {
// He обрабатывать точки с нулевой массой if(ClothPoints[i].m_Mass != 0.0f) {
В предыдущем кусочке кода вы начали просматривать все точки одежды. Я полагаю, что количество точек определяется переменной NumPoints, а данные самих точек определены в массиве ClothPoints. При просмотре необходимо сначала убедится, что точка имеет ненулевую массу, т. е. что она может перемещаться. Если точка может перемещаться, тогда необходимо просмотреть все объекты столкновений и определить, сталкивается ли точка с ними.
11 Просмотреть каждый объект столкновений cCollisionObject *pObject = pCollision->m_Objects; while(pObject) {
// Проверить, сталкивается ли точка с объектом сферой if(pObject->m_Type == COLLISION_SPHERE) {
Первый тип объекта, который проверяется на столкновение, - это сфера. Помните, что сфера располагается при помощи трехмерного вектора, а ее радиус определяется вещественным значением, которое вы установили при вызове AddSphere. Как показано на рис. 13.7, точка сталкивается со сферой, если расстояние от центра сферы до просматриваемой точки меньше ее радиуса.

Рис. 13.7. Точка сталкивается со сферой, если расстояние от центра сферы до точки меньше, чем радиус сферы
Т. к. для расположения объекта столкновения используется преобразование, необходимо применить часть преобразования, ответственного за перемещение, к вектору положения сферы, прежде чем проверять столкновения.
// Сохранить координаты сферы в локальный вектор D3DXVECTOR3 vecSphere = pObject->m_vecPos;
// Переместить сферу, если необходимо
if(matTransform) { vecSphere.x += matTransform->_41; // Translate x vecSphere.y += matTransform->_42; // Translate у vecSphere.z += matTransform->_43; // Translate z }
После того как вы получили вектор, представляющий положение сферы, вычислите вектор, который равняется длине от точки до центра сферы.
// Вычислить вектор расстояния
vecDist = vecSphere - ClothPoints[i].m_vecPos;
Теперь вы можете сравнить длину этого вектора с радиусом сферы. Чтобы избежать использования sqrt при вычислении расстояний, просто сравните квадраты значений.
// Получить квадрат расстояния разности float Length = vecDist.x * vecDist.x + \
vecDist.y * vecDist.y + \
vecDist.z * vecDist.z;
// Проверить, меньше ли длина разницы радиуса if(Length<= (pObject->m_Radius*pObject->m_Radius)) {
// Произошло столкновение!
После того как вы определили, что произошло столкновение (расстояние между точкой и сферой меньше или равно радиусу сферы), вы можете обрабатывать столкновение. Для упрощения, я собираюсь отбросить физику и просто вытолкнуть точку из сферы. Также полагаем, что такая мягкая вещь, как кусочек одежды, не отскочит определенным образом от объекта столкновения, поэтому я также пропущу все вычисления коэффициентов возврата.
Чтобы вытолкнуть точку из сферы, необходимо масштабировать нормализованный вектор расстояния (вектор, представляющий расстояние от точки до центра сферы) на разность расстояний между точкой и краем сферы, а потом вычесть этот вектор из положения точки (и скорости, чтобы замедлить точку).
// Нормализовать значение расстояние и вектор Length = (float)sqrt(Length); vecDist /= Length;
// Вычислить разность расстояний точки и границы сферы float Diff = pObject->m_Radius - Length;
// масштабировать вектор на эту разность vecDist *= Diff;
// Вытолкнуть точку и скорректировать скорость ClothPoints[i].m_Pos -= vecDist; ClothPoints[i].m_Velocity -= vecDist;
}
}
Вот и все, что касается проверки столкновений точки и сферы! Далее следует проверка столкновения точки и плоскости.
// Проверить, сталкивается ли точка с объектом плоскостью if(pObject->m_Type == COLLISION_PLANE) {
Чтобы проверить пересекается ли точка с плоскостью, необходимо сначала преобразовать плоскость, после чего взять скалярное произведение ее нормали и положения точки. Это скалярное произведение, скомбинированное с компонентой смещения плоскости, определяет, расположена ли точка перед плоскостью (столкновения нет) или за плоскостью (столкновение есть). Точки, находящиеся за плоскостью должны быть вытолкнуты из нее.
Чтобы преобразовать плоскость, необходимо сначала обратить и транспонировать матрицу преобразования. Это необходимо сделать только один раз в функции, потому что вы можете использовать эту матрицу для всех плоскостей. В демонстрационной программе этой главы показано, как создать преобразование только однажды. А пока, я буду вычислять его каждый раз. Используя обратную транспонированную матрицу, вы можете вызвать D3DXPlaneTransform для преобразования плоскости.
// Сохранить плоскость в локальной переменной D3DXPLANE Plane = pObject->m_Plane;
// Преобразовать плоскость, если необходимо if(matTransform) {
// Обратить и транспонировать матрицу преобразования
D3DXMATRIX matITTransform;
D3DXMatrixInverse(&matITTransform, NULL, matTransform); D3DXMatrixTranspose(&matITTransform, &matITTransform) ;
// Преобразовать плоскость
D3DXPlaneTransform(&Plane, &Plane, &matITTransform) ;
}
После того как вы преобразовали плоскость, необходимо взять ее нормаль и использовать ее для вычисления скалярного произведения с вектором положения точки.
// Получить вектор нормали
D3DXVECTOR3 vecNormal = D3DXVECTOR3(Plane.a, \ Plane.b, \ Plane.c);
// Посчитать скалярное произведение нормали плоскости и // положения точки
float Dot = D3DXVec3Dot(&ClothPoints[i].m_vecPos, \ &vecNormal) + Plane.d;
Вы заметите, что я добавил компоненту смещения плоскости (d) к результату скалярного произведения. Это гарантирует корректное вычисление расстояния от точки до плоскости. Если результирующее значение векторного произведения меньше 0, то точка сталкивается с плоскостью и должна быть вытолкнута. Чтобы вычислить вектор, который необходимо прибавить к векторам положения и скорости точки, необходимо просто умножить нормаль плоскости на значение скалярного произведения и прибавить результат к векторам положения и скорости.
// Проверить, находится ли точка за плоскостью if(Dot < 0.0f) {
// Масштабировать нормаль плоскости на модуль скалярного произведения vecNormal *= (-Dot);
// Переместить точку и скорректировать скорость на вектор нормали ClothPoints[i].m_vecPos += vecNormal; ClothPoints[i].m_vecVelocity += vecNormal;
}
}
После этого вы можете переходить к обработке следующего объекта столкновения и закончить цикл, который бы просматривал все остальные точки одежды.
// Перейти к следующему объекту столкновения pObject = pObject->m_Next;
}
} } }
Чтобы использовать функцию CheckCollisions, загрузите меш одежды и начните имитацию. После того как вы обработали силы одежды и обновили ее точки, вызовите CheckCollisions. В качестве примера приведем небольшой кусочек кода:
// Создать экземпляры объекта столкновений и матрицы преобразования cCollision Collision; D3DXMATRIX matCollision;
// Добавить в список столкновений сферу и установить матрицу в единичную
Collision.AddSphere(&D3DXVECTOR3(0.0f, 0.0f, 0.0f), 4 0.0f); D3DXMatrixIdentity(&matCollision) ;
// Обработать силы меша одежды и обновить ее точки // Обработать столкновения
CheckCollisions(&Collision, &matCollision) ;
Хотя методы, которые я только что показал, и не являются самыми точными для определения столкновений объектов и реакции на них, они в целом должны подойти для использования в игровых проектах. Тем из вас, кому необходима абсолютная точность, как например, значение точного момента времени столкновения точки и объекта столкновения, следует рассмотреть такие методы, как back-stepping time or time-stepping. Я рассмотрел time-stepping в главе 7, так что вы можете использовать те же самые технологии для моделирования одежды.
А пока я хочу показать вам, как использовать полученные вами значения для создания полностью законченного класса меша одежды, который бы управлял моделированием.
⇐Определение объектов столкновений || Оглавление || Создание класса меша одежды⇒