- •Введение
- •Глава 1. Подготовка к изучению книги
- •Установка DirectX SDK
- •Выбор отладочных или рабочих версий библиотек
- •Настройка вашего компилятора
- •Установка директорий DirectX SDK
- •Привязывание к библиотекам DirectX
- •Установка используемого по умолчанию состояния символа
- •Использование вспомогательного кода книги
- •Использование вспомогательных объектов
- •Проверка вспомогательных функций
- •Двигаясь дальше по книге
- •Глава 2. Синхронизация анимации и движения
- •Использование движения, синхронизированного по времени
- •Считывание времени в Windows
- •Анимирование с использованием временных меток
- •Перемещение, синхронизированное со временем
- •Движение вдоль траекторий
- •Создание анализатора маршрутов .X файла
- •Создание внутриигровых кинематографических последовательностей
- •Посмотрите демонстрационные программы
- •TimedAnim
- •TimedMovement
- •Route
- •Cinematic
- •Глава 3. Использование формата файла .X
- •Работа с .X шаблонами и объектами данных
- •Определение шаблонов
- •Работа со стандартными шаблонами DirectX
- •Открытие .X файла
- •Перечисление объектов данных
- •Получение данных объекта
- •Создание класса .X анализатора
- •Загрузка мешей с использованием D3DX
- •Загрузка мешей, используя анализатор .X
- •Загрузка скелетных мешей
- •Загрузка анимации из .X
- •Загрузка специализированных данных из .X
- •Посмотрите демонстрационные программы
- •ParseFrame
- •Глава 4. Работа со скелетной анимацией
- •Начало скелетной анимации
- •Использование структур скелетов и иерархий костей
- •Использование скелетной структуры и скелетного меша
- •Загрузка иерархий из .X
- •Изменение положения костей
- •Обновление иерархии
- •Работа со скелетными мешами
- •Загрузка скелетных мешей из .X
- •Создание контейнера вторичного меша
- •Сопоставление костей фреймам
- •Обновление скелетного меша
- •Визуализация скелетных мешей
- •Глава 5. Использование скелетной анимации, основанной на ключевых кадрах
- •Использование наборов скелетных анимаций, основанных на ключевых кадрах
- •Использование ключей при анимации
- •Работа с четырьмя типами ключей
- •Считывание данных анимации из .X файлов
- •Прикрепление анимации к костям
- •Обновление анимации
- •Посмотрите демонстрационные программы
- •Глава 6. Комбинирование скелетных анимаций
- •Комбинирование скелетных анимаций
- •Соединение преобразований
- •Улучшение объектов скелетной анимации
- •Посмотрите демонстрационные программы
- •Глава 7. Создание кукольной анимации
- •Работа с физикой твердого тела
- •Создание твердого тела
- •Расположение и ориентирование твердых тел
- •Обработка движения твердых тел
- •Использование сил для создания движения
- •Соединение твердых тел с помощью пружин
- •Обеспечение обнаружения столкновений и ответной реакции
- •Создание систем кукольной анимации
- •Определение состояния твердого тела
- •Хранение костей
- •Создание класса управления куклой
- •Создание данных костей
- •Вычисление ограничивающего параллелепипеда кости
- •Установка сил
- •Объединение костей
- •Обработка столкновений
- •Восстановление соединений костей
- •Перестроение иерархии
- •Посмотрите демонстрационные программы
- •Глава 8. Работа с морфирующей анимацией
- •Морфинг в действии
- •Определение исходного и целевого меша
- •Морфинг мешей
- •Создание морфированного меша при помощи обработки
- •Визуализация морфированных мешей
- •Расчленение наборов
- •Создание морфирующего вершинного шейдера
- •Посмотрите демонстрационные программы
- •Глава 9. Использование морфирующей анимации, основанной на ключевых кадрах
- •Использование наборов морфируемой анимации
- •Создание шаблонов .X для морфируемой анимации
- •Загрузка данных морфируемой анимации
- •Визуализации морфированного меша
- •Получение данных морфируемого меша из альтернативных источников
- •Посмотрите демонстрационные программы
- •Глава 10. Комбинирование морфированных анимаций
- •Комбинирование морфированных анимаций
- •Использование базового меша в комбинированных морфированных анимациях
- •Вычисление разностей
- •Комбинирование разностей
- •Создание вершинных шейдеров комбинированного морфирования
- •Использование вершинного шейдера морфируемого комбинирования
- •Посмотрите демонстрационные программы
- •Глава 11. Морфируемая лицевая анимация
- •Основы лицевой анимации
- •Использование комбинированного морфирования
- •Использования фонем для речи
- •Создание лицевых мешей
- •Создание базового меша
- •Создание выражений лица
- •Создание мешей визем
- •Создание анимационных последовательностей
- •Создание последовательностей фонем
- •Использование анализатора файлов .X для последовательностей
- •Проигрывание лицевых последовательностей со звуком
- •Использование DirectShow для звука
- •Синхронизация анимации со звуком
- •Зацикливание воспроизведения звуков
- •Посмотрите демонстрационные программы
- •Глава 12. Использование частиц в анимации
- •Работа с частицами
- •Основы
- •Рисование частиц с помощью квадратных полигонов
- •Работа с точечными спрайтами
- •Улучшения визуализации частиц при помощи вершинных шейдеров
- •Оживление частиц
- •Передвижение частиц при помощи скорости
- •Использование интеллекта при обработке
- •Создание и уничтожение частиц
- •Управление частицами с помощью класса
- •Использование излучателей в проектах
- •Создание движков частиц в вершинных шейдерах
- •Посмотрите демонстрационные программы
- •Глава 13. Имитирование одежды и анимация мешей мягких тел
- •Имитация одежды в ваших проектах
- •Получение данных одежды из мешей
- •Приложение сил для создания движения
- •Воссоздание и визуализация меша одежды
- •Восстановление исходного меша
- •Добавление дополнительных пружин
- •Загрузка данных масс и пружин из .X файла
- •Создание анализатора .X данных одежды
- •Работа с обнаружением столкновений и реакцией на них
- •Определение объектов столкновений
- •Обнаружение и реакция на столкновения
- •Создание класса меша одежды
- •Использование мешей мягких тел
- •Восстановление мешей мягких тел
- •Посмотрите демонстрационные программы
- •Глава 14. Использование анимированных текстур
- •Использование анимации текстур в ваших проектах
- •Работа с преобразованиями текстур
- •Создание преобразования текстур
- •Установка матриц преобразования текстуры
- •Использование преобразования текстур в проектах
- •Использование файлов видео в качестве текстур
- •Импорт видео при помощи DirectShow
- •Создание специализированного фильтра
- •Работа со специализированным фильтром
- •Создание менеджера анимированных текстур
- •Окончание современной анимации
- •Веб-сайты
- •Рекомендуемые книги
- •DirectX 9.0 SDK
- •GoldWave Demo
- •Paint Shop Pro Trial Version
- •TrueSpace Demo
- •Microsoft Agent and LISET
- •Предметный указатель
248 |
Глава 8 |
После выполнения последнего кусочка кода вектор будет содержать координаты, используемые для расположения вершины в сморфированной анимации. Конечно же, эти вычисления повторяются для каждой вершины в исходном меше. В следующем разделе вы увидите, как выполнять эти вычисления для создания собственных морфируемых мешей. Однако перед этим я хочу заметить кое-что о синхронизации морфирующей анимации.
До этого момента я игнорировал фактор времени: как продолжительность анимации (количество времени, требуемого морфирующей анимации для перемещения из исходного в целевое положение), так и точный момент времени из последовательности анимации, в который вычисляются координаты. Полагая, что вы измеряете время в миллисекундах и продолжительность анимации хранится в Length (вещественное значение), а текущее время, в которое вы вычисляете координаты, хранится в Time (также вещественное значение), вы можете вычислить соответствующее значение скаляра, используемого в расчетах, так:
Scalar = Time / Length;
Используя вычисления, виденные вами в этом разделе, вы можете применить этот скаляр для расчета координат вершин, образующих морфируемый меш.
Уже второй раз я говорю о создании морфируемого меша, так что я больше не буду тянуть. Читайте далее, чтобы узнать, как создавать морфируемый меш, который вы можете использовать для визуализации. Хотя ранее я и замечал об использовании вершинных шейдеров, сначала я покажу вам самый простой путь создания морфируемых мешей - непосредственной обработкой буфера вершин меша.
Создание морфированного меша при помощи обработки
Непосредственная обработка буфера вершин меша является, наверное, самым простым способом работы с морфингом. Для этого метода вам потребуется третий меш, который будет содержать результирующие координаты каждой вершины после морфирования, и именно этот меш вы визуализируете.
Для создания третьего меша, который я назвал результирующим морфированным мешем, вам необходимо скопировать исходный меш и изменять его.
//Объявить третий меш, используемый для результирующего
//морфированного меша
ID3DXMesh *pResultMesh = NULL;
Работасморфирующейанимацией
// скопировать меш, используя исходный меш pSourceMesh pSourceMesh->CloneMeshFVF(0, pSourceMesh->GetFVF(), \
pDevice, &pResultMesh);
После создания результирующего морфированного меша (pResultMesh) вы можете начинать обрабатывать морфируемую анимацию, заблокировав буферы вершин исходного, целевого и результирующего морфированного мешей. Однако прежде чем это сделать вам необходимо объявить общую структуру вершин, которая будет содержать только их координаты, к которым вы получаете доступ при блокировке каждого буфера вершин.
typedef struct { D3DXVECTOR3 vecPos;
} sGenericVertex;
Также вам необходимо вычислить размер каждой структуры вершин, используемых вершинами меша, потому что каждый буфер вершин содержит вершины различных размеров (например, у исходного могут быть нормали, в то время как у целевого нет). Вы можете сделать это, используя функцию D3DXGetFVFVertexSize.
//pSourceMesh = объект исходного меша
//pTargetMesh = объект целевого меша
//pResultMesh = объект результирующего морфированного меша
DWORD SourceSize = D3DXGetFVFVertexSize(pSourceMesh->GetFVF());
DWORD TargetSize = D3DXGetFVFVertexSize(pTargetMesh->GetFVF());
DWORD ResultSize = D3DXGetFVFVertexSize(pResultMesh->GetFVF());
Теперь вы можете заблокировать буферы вершин и присвоить им указатели.
// Объявить указатели вершин
char *pSourcePtr, *pTargetPtr, *pResultPtr; pSourceMesh->LockVertexBuffer(D3DLOCK_READONLY, \
(void**)&pSourcePtr); pTargetMesh->LockVertexBuffer(D3DLOCK_READONLY, \
(void**)&pTargetPtr); pResultMesh->LockVertexBuffer(0, (void**)&pResultPtr);
Заметили, как я присваиваю буферам вершин указатели char* вместо использования определенной структуры вершин? Вам необходимо поступать таким же бразом, потому что буферы вершин могут быть любого размера, помните? Как только вам необходимо получить доступ к вершине, вы приводите указатель к определенной структуре вершин и получаете доступ к данным. Для того чтобы перейти к следующей вершине, просто добавьте размер структуры вершин к указателю. Поняли? Если нет, не волнуйтесь, следующий ниже код поможет вам сделать это.
250 |
Глава 8 |
После того как вы заблокировали буферы, вы можете просматривать все вершины, получать их координаты и, используя вычисления из предыдущего раздела, рассчитывать положения морфированных вершин. Полагая, что продолжительность анимации хранится в Length, а текущее время в Time, следующий код иллюстрирует выполнение этих вычислений.
//Length = вещественное значение, содержащее длительность
//анимации в миллисекундах
//Time = вещественное значение, содержащее текущее время в анимации
//Вычислить скаляр, используемый в вычислениях
float Scalar = Time / Length;
// Перебрать все вершины
for(DWORD i=0;i<pSourceMesh->GetNumVertices();i++) {
//Привести указатели буферов вершин к общей структуре вершин sGenericVertex *pSourceVertex = (sGenericVertex*)pSourcePtr; sGenericVertex *pTargetVertex = (sGenericVertex*)pTargetPtr; sGenericVertex *pResultVertex = (sGenericVertex*)pResultPtr;
//Получить исходные координаты и масштабировать их D3DXVECTOR3 vecSource = pSourceVertex->vecPos; vecSource *= (1.0f - Scalar);
//Получить целевые координаты и масштабировать их D3DXVECTOR3 vecTarget = pTargetVertex->vecPos; vecTarget *= Scalar;
//Сохранить сумму координат в результирующем морфированном меше pResultVertex->vecPos = vecSource + vecTarget;
//Перейти к следующей вершине в каждом буфере
pSourcePtr += SourceSize; pTargetPtr += TargetSize; pResultPtr += ResultSize;
}
До этого момента я пропускал тему нормалей вершин, потому что используемые для морфирования нормалей значения скаляра и обратного скаляра применяются таким же образом, как и для вершин.
В предыдущем коде вы можете вычислить морфируемые нормали, сначала проверив, существуют ли они у меша. Если да, то при обработке всех вершин возьмите нормали исходной и целевой вершин, умножьте их на скаляр и обратный скаляр и сохраните результат. Посмотрите на код, выполняющий эти действия.
//Length = вещественное значение, содержащее длительность
//анимации в миллисекундах
//Time = вещественное значение, содержащее текущее время в анимации
Работа сморфирующейанимацией
//Вычислить скаляр, используемый в вычислениях float Scalar = Time / Length;
//Установить флаг, если используются нормали BOOL UseNormals = FALSE; if(pSourceMesh->GetFVF() & D3DFVF_NORMAL && \
pTargetMesh->GetFVF() & D3DFVF_NORMAL) UseNormals = TRUE;
//Перебрать все вершины
for(DWORD i=0;i<pSourceMesh->GetNumVertices();i++) {
// Привести указатель на буфер вершин к общей структуре вершин sGenericVertex *pSourceVertex = (sGenericVertex*)pSourcePtr; sGenericVertex *pTargetVertex = (sGenericVertex*)pTargetPtr; sGenericVertex *pResultVertex = (sGenericVertex*)pResultPtr;
//Получить исходные координаты и масштабировать их D3DXVECTOR3 vecSource = pSourceVertex->vecPos; vecSource *= (1.0f - Scalar);
//Получить целевые координаты и масштабировать их D3DXVECTOR3 vecTarget = pTargetVertex->vecPos; vecTarget *= Scalar;
//Сохранить сумму координат в результирующем морфированном меше pResultVertex->vecPos = vecSource + vecTarget;
//Обработать нормали, если флаг установлен
if(UseNormals == TRUE) {
//Настроить соответствующие указатели структур вершин, для
//получения доступа к нормалям, которые следуют за координатами pSourceVertex++; pTargetVertex++; pResultVertex++;
//Получить нормали и применить скаляр и обратный скаляр D3DXVECTOR3 vecSource = pSourceVertex->vecPos;
vecSource *= (1.0f - Scalar);
D3DXVECTOR3 vecTarget = pTargetVertex->vecPos; vecTarget *= Scalar;
pResultVertex->vecPos = vecSource + vecTarget;
}
// Перейти к следующей вершине в каждом буфере и продолжить pSourcePtr += SourceSize;
pTargetPtr += TargetSize; pResultPtr += ResultSize;
}
Все выглядит замечательно! Все, что вам остается сделать, - это разблокировать буферы вершин и визуализировать результирующий меш! Я пропущу код, разблокирующий буферы, и сразу перейду к визуализации мешей.