- •Введение
- •Глава 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
- •Предметный указатель
Использование формата файла ,Х
вы можете зарегистрировать шаблон, определенный в буфере "Templates", используя следующий код:
pFile->RegisterTemplates(Templates, strlen(Templates));
Вернемся к самой теме - регистрирование стандартных шаблонов. Вы видели, как работает функция RegisterTemplates. Для того чтобы зарегистрировать стандартные шаблоны, вам необходимо включить два добавочных файла в ваш проект - "rmxftmpl.h" и "rmxfguid.h". Эти два файла содержат определения и GUID стандартных шаблонов соответственно.
Внутри файла "rmxftmpl.h" вы найдете буфер данных шаблона D3DRMXTEMPLATES и макрос D3DRM_XTEMPLATE_BYTES. Они используются при вызове RegisterTemplates для регистрирования стандартных шаблонов, как вы можете видеть здесь:
pFile->RegisterTemplates(D3DRM_XTEMPLATES, \ D3DRM_XTEMPLATE_BYTES);
Правильно, просто вызвав приведенный выше кусочек кода, вы успешно зарегистрируете стандартные шаблоны, и вы готовы продолжать! Но сначала небольшой совет: как только вы начнете использовать формат .X для ваших специализированных данных и шаблонов, не забывайте, что RegisterTemplates отлично регистрирует и ваши шаблоны!
Замечание. Отметьте, что в определении шаблона "Templates" используется наклонная черта влево для обозначения новой линии, и после этого следует стандартный заголовок .X файла.
Совет. Для того, чтобы запомнить "rmxftmpl.h" и "rmxfguid.h", просто помните, что "rmxf " это .X файл сохраненного режима, "tmpl" означает шаблон и "guid" означает глобальноуникальный идентификатор.
Открытие .X файла
После того как вы создали интерфейс IDirectXFile и зарегистрировали используемые шаблоны, вам необходимо открыть .X файл и начать просмотр содержащихся в нем объектов. Процессы открытия .X файла и создания объекта просмотра объединены в один, соответствующий вызову функции IDirectXFile::CreateEnumObject.
HRESULT IDirectXfile::CreateEnumObject( LPVOID pvSource, // имя .Х файла
DXFILELOADOPTIONS dwLoadOptions, // параметры загрузки LPDIRECTXFILEENUMOBJECT* ppEnumObj}; // интерфейс перечисления
96 |
Глава3 |
Когда вы вызываете функцию CreateEnumObject, укажите ей в качестве параметра pvSource имя загружаемого .X файла, а в качестве ppEnumObj используемый интерфейс. Что же касается dwLoadOptions, вы должны задать значение DXFILELOAD_FROMFILE, которое сообщает DirectX, что файл загружается с диска. Другие возможные значения dwLoadOptions это DXFILELOAD_FROMRESOURCE, DXFILELOAD_FROMMEMORY и DXFILELOAD_FROMURL. Эти значения говорят DirectX загружать файл из ресурсов, буфера памяти или сетевого адреса соответственно. Да, так и есть - вы можете загружать .X файл прямо из Интернета.
Совет.Для загрузки .X файла из Интернета, используя адрес, задайте полный сетевой путь в "pvSource". Для загрузки из ресурса или памяти просто укажите дескриптор ресурса или указатель памяти (оба преобразуются к LPVOID) вpvSource.
Продолжим пример и создадим объект перечисления для .Х файла. Следующий код создает объект перечисления, используемый для анализа дискового файла.
// Filename = имя загружаемого файла (например "test.x") IDirectXFileEnumObject *pEnum; pFile->CreateEnumObject((LPVOID)Filename, \
DXFILELOAD_FROMFILE, &pEnum);
Из комментариев кода видно, что "Filename" указывает на правильное имя файла - в данном случае "test.x". После успешного вызова функция CreateEnumObject возвращает вам правильный объект перечисления (необходим один на один открытый файл), готовый к перечислению объектов находящихся в файле.
Перечисление объектов данных
На данный момент вы открыли .X файл и зарегистрировали используемые шаблоны (такие как стандартные шаблоны DirectX). Создали объект перечисления и теперь готовы к извлечению данных из .X файла.
На данный момент созданный вами объект IdirectXFileEnumObject указывает на первый объект данных в файле, которым обычно является "Header". Все объекты данных верхнего уровня являются родственниками объекта "Header" (или первого объекта в файле). Каждый прочитанный вами объект данных может содержать встроенные (дочерние) объекты или ссылки на другие объекты, которые вы можете получить.
Объект перечисления сам по себе не содержит объектов данных. Вместо этого вам необходимо получить интерфейс IDirectXFileData для доступа к данным. Чтобы получить интерфейс IDirectXFileData, вам необходимо вызвать функцию IDirectXFileEnumObject::GetNextDataObject.
Использование формата файла .X
HRESULT IDirectXFileEnumObject::GetNextDataObject( \
LPDIRECTXFILEDATA* ppDataObj);
Имея всего лишь один параметр, GetNextDataObject очень проста в использовании. Вам просто необходимо создать экземпляр объекта IDirectXFileData и использовать его при вызове GetNextDataObject.
IDirectXFileData *pData;
HRESULT hr = pEnum->GetNextDataObject(&pData);
Заметили, как я сохраняю значение, возвращаемое функцией GetNextDataObject? Если возвращаемый результат является ошибкой (что проверяется макросом FAILED), то это означает, что перечисление закончено. Если же вызов функции GetNextDataObject успешен, тогда вы получаете новый интерфейс для доступа к данным объекта!
Прежде чем вы начнете работать с данными объекта, давайте закончим обсуждение перечисления. Пока что вы можете получить первый объект в файле и его интерфейс данных. Что делать, если вы хотите получить остальные объекты из .X файла или встроенные объекты?
После того как вы закончили с одним объектом, вам необходимо освободить его и перейти к следующему объекту. Простой вызов IDirectXFileData::Release освободит интерфейс данных, и повторяющимися вызовами IDirectXFileEnumObject::GetNextDataObject вы можете получить следующий перечисленный объект данных родственника (высокоуровневого). Вы можете представить перечисление всех родственников (получая их интерфейсы данных) с помощью следующего кода:
while(SUCCEEDED(pEnum->GetNextDataObject(&pData))) {
//Сделать что-нибудь с объектом pData
//Освободить интерфейс данных для продолжения pData->Release();
}
Все что остается, это добавить возможность получать дочерние (нижнеуровневые) объекты, перечислить их и сделать доступными. Для получения дочернего объекта используйте сначала функцию IDirectXFileData::GetNextObject, чтобы посмотреть содержит ли объект встроенные объекты.
HRESULT IDirectXFileData::GetNextObject ( \
LPDIRECTXFILEOBJECT* ppChildObj);
Это еще одна простая функция с одним параметром - указателем на интерфейс IDirectXFileObject. Если вызов GetNextObject был успешным, тогда вам необходимо обработать дочерний объект. После того как вы завершите это, можете освободить его
98 |
Глава3 |
(вызвав Release) и продолжать вызывать GetNextObject, пока она не вернет ошибку, что означает, что больше не осталось объектов.
Вы можете реализовать циклические вызовы GetNextObject, как я сделал здесь
IDirectXFileObject *pObject;
while(SUCCEEDED(pData->GetNextObject(&pObject))) {
//Дочерний объект существует, необходимо получить его
//Освободить интерфейс объекта файла
pObject->Release();
}
После того как вы получили правильный интерфейс IDirectFileObject (после вызова GetNextObject), вы можете быстро определить, какой дочерний объект перечисляется (используя приемы описанные ниже). Однако есть небольшое препятствие. Объект может быть как ссылкой, так и экземпляром, и манера доступа к нему зависит от его типа.
Для экземпляров объектов (которые определяются обычно в .X файлах) вы можете получить IDirectXFileObject для интерфейса IDirectXFileData.
IDirectXFileData *pSubData;
//Проверить,является ли дочерний объект экземпляром(если нет,то ошибка) if(SUCCEEDED(pObject->QueryInterfaсe( \
IID_IDirectXFileData, (void**)&pSubData))) {
//Дочерний объект существует, сделать что-нибудь с ним
//Освободить объект
pSubData->Release();
}
Вы видели, как использовать объект IDirectXFileData раннее в этой главе. Используя только что приобретенные навыки, вы можете получать дочерние объекты IDirectXFileData для их собственных встроенных дочерних объектов.
Что касается ссылочных объектов, вам необходимо сначала получить объект IDirectXFileDataReference, а затем переделать ссылку в объект IDirectXFileData. Нижеследующий код преобразовывает ссылки на объекты для вас.
Совет. Если экземпляр объекта не существует, когда вы его получаете, вызов QueryInterface окончится неудачей. Это быстрый способ определения типа объекта. Таким же образом определяются ссылочные объекты — запрос окончится неудачей, если объект не ссылочный.
IDirectXFileDataReference *pRef;
IDirectXFileData *pSubData;
// Проверить является ли объект ссылочным (если нет, то неудача) if(SUCCEEDED(pSubObj->QueryInterfaсe( \
Использованиеформатафайла.X
IID_IDirectXFileDataReference, \
(void**)&pRef))) {
//Ссылочный объект существует. Преобразовать ссылку pRef->Resolve(&pSubData);
//Сделать что-нибудь с объектом
//Освободить используемый интерфейс
pRef->Release(); pSubData->Release();
}
Вы поверите мне, если я скажу, что самая сложная часть закончена? Перечисление объектов данных и дочерних объектов очень просто, и если это так же сложно, как оно понимается, тогда вам будет все просто! Чтобы облегчить вашу работу программиста, я предлагаю реализовать перечисление объектов данных в двух простых функциях.
Первая функция (названная Parse) будет открывать .X файл, создавать объект перечисления и просматривать все объекты верхнего уровня. Функция будет брать каждый перечисленный объект и передавать его второй функции (ParseObject), которая будет обрабатывать данные объектов на основе типа их шаблона и просматривать встроенные дочерние объекты. Функция ParseObject будет вызывать себя всякий раз, когда найдет дочерний объект, таким образом обрабатывая встроенные в дочерние объекты.
Вот код функции Parse.
//Need to include rmxftmpl.h and rmxfguid.h
//Необходимо подключить "rmxftmpl.h" и "rmxfguid.h" BOOL Parse(char *Filename)
{
IDirectXFile *pFile = NULL; IDirectXFileEnumObject *pEnum = NULL; IDirectXFileData *pData = NULL;
//Создать объект перечисления, вернуть ошибку if(FAILED(DirectXFileCreate(&pFile)))
return FALSE;
//Зарегистрировать стандартные шаблоны, вернуть ошибку if(FAILED(pFile->RegisterTemplates( \
(LPVOID)D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES))) return FALSE;
// Создать объект перечисления, вернуть ошибку if(FAILED(pDXFile->CreateEnumObject((LPVOID)Filename, \
DXFILELOAD_FROMFILE, \ &pEnum))) {
pFile->Release(); return FALSE;
100
// Пройтись по всем верхнеуровневым объектам while(SUCCEEDED(pEnum->GetNextDataObject(&pData))) {
//Анализировать объект, вызвав ParseObject ParseObject(pData);
//Освободить объект
pData->Release();
}
// Освободить использованные CОМ объекты pEnum->Release();
pFile->Release();
return TRUE;
}
Функция Parse не содержит ничего особенного и, конечно же, не является очень сложной. Я уже объяснил все аспекты, встречающиеся в функции, так что нет нужды повторяться. Вместо этого перейдем к функции ParseObject, которая беретобъекти просматриваетегодочерние объекты.
void ParseObject(IDirectXFileData *pData)
{
IDirectXFileObject *pObject = NULL; IDirectXFileData *pSubData = NULL; IDirectXFileDataReference *pRef = NULL;
// Просмотр встроенных объектов while(SUCCEEDED(pData->GetNextObject(&pObject))) {
// Искать ссылочные объекты if(SUCCEEDED(pObject->QueryInterface( \
IID_IDirectXFileDataReference, (void**)&pRef))) {
//Преобразовать объект pRef->Resolve(&pSubData);
//Анализировать объект, вызвав ParseObject ParseObject(pSubData);
//Освободить интерфейсы объектов
pSubData->Release(); pRef->Release();
}
// Искать экземплярные объекты if(SUCCEEDED(pObject->QueryInterfaсe( \
IID_IDirectXFileData, (void**)&pSubData))) {
// Анализировать объект, вызвав ParseObject ParseObject(pSubData);