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

Глава13

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

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

Я скажу, что вам нужно - анимация одежды и мешей мягких тел! Дайте вашим персонажам реалистичную одежду, которая облегает их тела и развевается на ветру, или пышные волосы, развевающиеся во время бега за новой добычей. Позвольте вашим персонажам принимать удар за ударом противника, заставляя их тела сгибаться, а потом распрямляться вновь. Правильно, вы можете использовать реалистичную одежду и меши мягких тел. Все, что вам нужно, находится в этой главе!

В этой главе вы научитесь:

Работать с имитацией одежды и мешей мягких тел;

Создавать одежду и меши мягких тел при помощи точек, масс и пружин;

Накладывать силы и столкновения;

Интегрировать движение во времени;

Деформировать и восстанавливать форму мешей мягких тел;

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

Имитация одежды в ваших проектах

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

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

Чтобы точно эмулировать реальный кусочек одежды, все точки одежды должны иметь заданную массу, которая определяет их движение в зависимости от прикладываемой силы. Точки, имеющую большую массу, требуют большей силы для сообщения ускорения, в то время как точки с меньшей массой получают большее ускорение при действии внешней силы. Это закон движения, гласящий, что сила, необходимая для перемещения объекта равна произведению массы тела на сообщаемое ему ускорение (F=ma).

Однако точкам не обязательно двигаться, они могут быть "скреплены", как если бы они были приклеены к части уровня или присоединены к мешу. Для целей этой главы я принял, что эти точки не имеют массы. (На самом деле необходимо полагать, что точки имеют бесконечную массу, потому что тогда величина силы, которую необходимо приложить для их движения, также будет бесконечно велика.)

Ребра меша одежды также играют важную роль - они соединяют точки одежды. Ну, на самом деле ребра не держат вместе точки, вместо этого, как показано на рис. 13.1, они представляют собой набор маленьких пружин, которые скрепляют точки. По мере того, как точки одежды движутся, каждая пружина пытается сохранить состояние статического равновесия, выталкивая и втягивая точки, пока не будут скомпенсированы все силы. Визуально это выражается в том, что точки как бы всегда находятся на одном и том же расстоянии между собой.

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

Нас интересует взаимодействие точек одежды, массы и пружины; при моделировании в основном вся работа происходит с ними. Давайте рассмотрим более подробно, как имитировать движение одежды, используя эти точки и пружины.

Определениеточек одежды и пружин

Точка одежды, являющаяся аналогом вершины, - это просто точка в трехмерном пространстве. Поэтому можно определить ее координаты при помощи объекта D3DXVECTOR3. Этот объект изначально содержит точно такие же координаты, как и у соответствующей вершины меша одежды, и массу точки одежды.

374

Глава13

Точки одежды

Пружины

одежды

Сжатие Растяжение

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

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

Яобъясню, зачем необходимо использовать два значения, немного позднее;

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

class cClothPoint {

D3DXVECTOR3 m_vecPos; // трехмерные координаты точки float m_Mass; // Масса точки (0=прикрепленная)

float m_OneOverMass; // 1 / Массу (0=прикрепленная к месту) };

cClothPoint *ClothPoints = new cClothPoint[NumPoints];

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

Что же касается пружин, необходимо хранить два значения индексов точек (из массива точек), к которым присоединена пружина. Каждая пружина также имеет начальное расстояние между точками, называемое длиной покоя пружины. Значение длины покоя пружины является очень важным, т. к. оно используется для определения, была ли пружина растянута или сжата во время моделирования.

Наконец, необходимо определить значения жесткости и амортизации пружины. Эти значения очень важны, так как они определяют характер реакции пружины на действие внешней силы. Я скоро покажу вам, как использовать эти два значения; а пока просто определим их в виде двух вещественных переменных.

Вы можете определить класс, содержащий данные пружины и массив используемых объектов класса пружины, так:

class cClothSpring {

DWORD m_Point1; // первая точка пружины DWORD m_Point2; // вторая точка пружины

float m_RestingLength; // длина покоя пружины float m_Ks; // жесткость пружины

float m_Kd; // значение амортизации пружины

};

cClothSpring *ClothSprings = new cClothSpring[NumSprings];

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

Получение данных одежды из мешей

Предположим, что вы уже загрузили меш в объект ID3DXMesh, и из него вы собираетесь создавать объект одежды. В предыдущем разделе я определили две переменные, определяющие размеры массивов точек и пружин - NumPoints и NumSprings. В том разделе эти переменные были не определены, но теперь, имея корректный объект меша (предположим, что он называется pClothMesh), вы можете получить из него информацию, необходимую для вычисления этих переменных так:

// pClothMesh = предварительно загруженный объект ID3DXMesh NumPoints = pClothMesh->GetNumVertices();

NumSprings = pClothMesh->GetNumFaces() * 3;

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

376

DWORDVertexStide=D3DXGetFVFVertexSize(pClothMesh->GetFVF());

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

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

Замечание. На самом деле использование количества граней для определения количества создаваемых пружин одежды является не очень хорошей идеей. Т. к. каждая грань меша может разделять любое количество вершин, то получается множество повторяющихся пружин. Далее в этой главе я покажу вам способ создания пружин, который позволяет избежать повторений.

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

//Создать универсальную структуру вершин для получения координат typedef struct {

D3DXVECTOR3vecPos; } sVertex;

//Заблокировать буфер вершин

BYTE *pVertices; pClothMesh->LockVertexBuffer(D3DLOCK_READONLY, \

(BYTE**)&pVertices);

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

//Преобразовать к структуре универсальной вершины sVertex *pVertex = (sVertex*)pVertices;

//Сохранить координаты точки одежды ClothPoints[i].m_vecPos=pVertex->vecPos;

Также необходимо определить массу точки. Т. к. нет никакого источника этого значения (т. к. меш не содержит значений массы), можно просто установить какоенибудь значение по умолчанию, скажем 1. То же самое относится и к другим значениям массы (m_OneOverMass) - установите их в 1, деленную на массу.

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

// Присвоить массу, равную единице, и 1/масса ClothPoints[i].m_Mass = 1.0f;

ClothPoints[i].m_OneOverMass = 1.0f / ClothPoints[i].m_Mass;

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

// Перейти к следующей вершине в списке pVertices += VertexStride;

}

// Разблокировать буфер вершин pClothMesh->UnlockVertexBuffer();

Замечательно, мы уже на полпути к получению необходимых данных одежды, используемых при симуляции! Далее необходимо преобразовать ребра меша в пружины, которые бы скрепляли одежду. На этот раз необходимо заблокировать буфер индексов меша и получить три индекса, образующих каждую грань. Три точки соединяются, образуя грани, при этом каждая грань является пружиной.

Получить доступ к буферу индексов намного проще, чем получить доступ к буферу вершин. Я полагаю, что используются 16-битные индексы, потому что 32-битные индексы пока не очень широко распространены. Необходимо получить следующие подряд 16-битные значения индексов для каждой грани и создать из них три пружины, используя все сочетания соединений каждых двух имеющихся индексов.

Можно начать, заблокировав буфер индексов.

unsigned short *pIndices; pClothMesh->LockIndexBuffer(D3DLOCK_READONLY, \ (BYTE**)&pIndices);

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

DWORD SpringNum = 0; for(i=0;i<pClothMesh->GetNumFaces();i++) {

unsigned short Index1 = *pIndices++; unsigned short Index2 = *pIndices++; unsigned short Index3 = *pIndices++;

Используя эти три индекса, создайте три пружины, представляющие собой грани.

// Создать пружину от 1->2 ClothSprings[SpringNum].m_Point1 = Index1; ClothSprings[SpringNum].m_Point2 = Index2; SpringNum++; // Увеличить число пружин

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