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

Имитирование одежды и анимация мешей мягких тел

пять функций, первые из которых конструктор и деструктор. Они используются для очистки данных класса и вызова функции Free соответственно.

Функция Free предназначена для удаления связанного списка объектов и обнуления количества загруженных в него объектов столкновений. Функции AddSphere и AddPlane используются для создания нового объекта столкновения и добавления его в связанный список, хранящийся в классе cCollision.

Чтобы добавить в связанный список сферу, вызовите AddSphere, задав в качестве параметров координаты центра сферы и ее радиус. Чтобы добавить плоскость, вызовите AddPlane и передайте в качестве параметра объект D3DXPLANE, который бы задавал нормаль плоскости и ее смещение от начала координат.

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

Обнаружение и реакция на столкновения

Создаваемая функция проверки столкновений должна просмотреть все точки одежды и для каждой точки проверить, происходит ли ее столкновение с какимлибо объектом столкновений, содержащимся в связанном списке объектов. Вызовете функцию CheckCollision; в качестве параметров задайте указатель на объект cCollision для проверки столкновений точки и объекта и матрицу преобразования, которая используется для расположения и ориентирования объектов столкновений в трехмерном мире.

void CheckCollisions(cCollision *pCollision, \ D3DXMATRIX *matTransform)

{

//Просмотреть все точки for(DWORD i=0;i<NumPoints;i++) {

//Нe обрабатывать точки с нулевой массой if(ClothPoints[i].m_Mass != 0.0f) {

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

402

Глава13

//Просмотреть каждый объект столкновений 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;

}

}

Вот и все, что касается проверки столкновений точки и сферы! Далее следует проверка столкновения точки и плоскости.

404

Глава 13

// Проверить, сталкивается ли точка с объектом плоскостью 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), 40.0f); D3DXMatrixIdentity(&matCollision);

//Обработать силы меша одежды и обновить ее точки

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

CheckCollisions(&Collision, &matCollision);

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

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