- •Введение
- •Глава 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
- •Предметный указатель
342 |
Глава 12 |
После того как вы установили соответствующие альфа состояния, вы можете установить FVF, потоки, текстуры и визуализировать сцену!
//Установить вершинный шейдер и источники потоков pDevice->SetVertexShader(NULL); pDevice->SetFVF(PARTICLEFVF);
pDevice->SetStreamSource(0, pBuffer, 0, sizeof(sVertex));
//Установить текстуру
pDevice->SetTexture(0, &pTexture);
// Нарисовать частицу pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
Хорошо, уже что-то получается! Вы нарисовали частицу! Т. к. обычно одновременно визуализируется более одной частицы, нет нужды повторять весь этот код для каждой частицы. После того как вы установили поток и текстуру, вы можете периодически блокировать буфер вершин, устанавливать данные, разблокировать буфер и визуализировать частицу. Если размер частицы не меняется, вы можете избежать блокировки и разблокировки буфера вершин, а просто хранить координаты частицы в обратной матрице преобразования, установив соответствующую текстуру, после чего визуализировать частицу.
После того как вы ознакомитесь с кодом визуализации частицы, заметьте несколько вещей. Во-первых, существует множество обрабатываемых данных вершин. Во-вторых, постоянное блокирование, заполнение, разблокирование буфера вершин может сильно снизить производительность. Вам необходимо визуализировать частицы таким образом, чтобы использовать меньше памяти и делать это более быстро. Вам необходимы точечные спрайты!
Замечание.Демонстрационная программа Particles, расположенная на компакт-диске, иллюстрирует визуализацию большого количества частиц, используя только-чторас- смотренную технологию. Смотрите конец этой главы для получения дополнительной информации о программе Particles.
Работа с точечными спрайтами
Как вы можете видеть, частицы являются важной частью игр — многие игры используют их для создания разнообразных спецэффектов. Корпорация Microsoft прекрасно об этом знала и добавила возможность визуализации биллбордных квадратных полигонов в Direct3D при использовании точечных спрайтов. Точечный спрайт является простым биллдным квадратным полигоном, содержащим минимальный набор данных. Каждая частица представлена одной трехмерной точкой
Использованиечастицванимации
(соответствующей ее центру) и размером (как он вводился в предыдущей части, за исключением того, что он одинаков для обоих осей х и у). Это позволяет сэкономить огромное количество памяти по сравнению с использованием квадратов.
Помните, ранее в этой главе упоминалось, что квадратная частица требует четырех вершин. В предыдущей структуре sVertex использовалось двадцать вещественных значений и четыре значения DWORD на одну частицу. Итого: 96 байт данных для визуализации одной частицы! А как насчет точечных спрайтов?
Точечные спрайты используют следующую структуру вершин:
typedef struct {
D3DXVECTOR3 vecPos; // Координаты центра частицы float Size; // Размер частицы
D3DCOLOR Diffuse; // Рассеянный цвет } sPointSprite;
Выглядит очень похоже, разве нет?
Большим отличием является то, что для одной частицы необходима только одна структура sPointSprite. Так и есть, структура sPointSprite использует только 20 байт данных, что меньше чем sVertex на 76 байт. Какая экономия!
Так в чем же хитрость точечных спрайтов? Вы же знаете, что должны быть какие-нибудь недостатки, не так ли? Недостатком точечных спрайтов является ограниченность их размера. При использовании квадратов вы можете создавать частицы любого размера, точечные спрайты ограничены в максимальном размере, определяемом переменной D3DCAPS9::MaxPointSize. Это означает, что максимальный размер точечных спрайтов зависит от видео карты конечного пользователя.
Другим недостатком является то, что драйвер видео карты должен поддерживать точечные спрайты. Часто я встречал плохие драйверы, при использовании которых точечные спрайты при визуализации моргали либо имели неправильный размер. Вам остается только надеяться, что конечный пользователь обновит свои драйверы, что гарантирует корректное использование точечных спрайтов.
Замечание. Для того чтобы убедиться, что вы можете аппаратно визуализировать точечные спрайты, необходимо проверить возможности аппаратного драйвера при помощи функции IDirect3D9::GetDeviceCaps. Если значение D3DCAPS9::MaxPointSize, полученное после вызова этой функции, установлено в 1.0, то тогда точечные спрайты не поддерживаются аппаратно.
Не будем брать во внимание недостатки, - точечные спрайты сохраняют огромное количество памяти; для тех видео карт, которые могут их использовать, это является превосходным решением для рисования частиц. Как вы видели в структуре вершин sPointSprite, точечные спрайты используют только четыре вещественных значения и одно DWORD для хранения координат, размера и рассеянного цвета частицы соответственно.
344 |
Глава 12 |
Замечание. Точечные спрайты используют всю поверхность текстуры, на которую рисуются. Это означает, что вам необходима однатекстура на каждую используемую картинку частицы. Это также означает, что вам не надо задавать текстурные координатывструктуревершинточечногоспрайта.
Точечные спрайты используют следующее объявление FVF:
#define POINTSPRITEFVF (D3DFVF_XYZ|D3DFVF_PSIZE|D3DFVF_DIFFUSE)
При вызове функции CreateVertexBuffer необходимо указать флаг D3DUSAGE_POINTS, как показано в следующем кусочке кода:
pDevice->CreateVertexBuffer(8 * sizeof(sPointSprite), \ D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY, \ POINTSPRITEFVF, D3DPOOL_DEFAULT, \
&pBuffer, 0);
После того как вы создали буфер вершин (не забыв указать количество содержащихся в буфере вершин), вы можете начать заполнять его данными частиц, которые вы хотите визуализировать. Предположим, вы хотите визуализировать восемь частиц, каждая из которых имеет размер 10 единиц (занимая по 5 единиц в направлениях осей х и у) и использует белый рассеянный цвет. Используя только что созданный буфер вершин, вы можете заблокировать, заполнить и разблокировать его, используя следующий код:
float Size = 10.0f; // Сделать размер частиц равным 10 единицам
sPointSprite PointSprites[8] = { // Частица #0
{ D3DXVECTOR3(0.0f,0.0f,0.0f), Size, D3DCOLOR_RGBA(255,255,255,255) },
// Частица #1
{ D3DXVECTOR3(10.0f,0.0f,0.0f), Size, D3DCOLOR_RGBA(255,255,255,255) },
// Частица #2
{ D3DXVECTOR3(22.0f,0.0f,0.0f), Size,
D3DCOLOR_RGBA(255,255,255,255) }, // Частица #3
{D3DXVECTOR3(30.0f,0.0f,0.0f), Size, D3DCOLOR_RGBA(255,255,255,255) },
// Частица #4
{ D3DXVECTOR3(-10.0f,0.0f,0.0f), Size,
D3DCOLOR_RGBA(255,255,255,255) }, // Частица #5
{ D3DXVECTOR3(-20.0f,0.0f,0.0f), Size, D3DCOLOR_RGBA(255,255,255,255) },
// Частица #6
{D3DXVECTOR3(-30.0f,0.0f,0.0f), Size, D3DCOLOR_RGBA(255,255,255,255) },
Использованиечастицванимации
// Частица #7
{D3DXVECTOR3(-40.0f,0.0f,0.0f), Size, D3DCOLOR_RGBA(255,255,255,255) },
};
//Заблокировать буфер вершин sPointSprite *Ptr; pBuffer->Lock(0,0,(void**)&Ptr,0);
//Скопировать данные вершин в буфер memcpy(Ptr, PointSprites, sizeof(PointSprites));
//Разблокировать буфер вершин
pBuffer->Unlock();
После того как вы создали и заполнили буфер вершин данными точечного спрайта, можно визуализировать его. Подождите! Я забыл упомянуть об установке важных состояний визуализации. Direct3D должно знать, что вы используете точечные спрайты, расположенные в трехмерном пространстве (в противоположность экранному пространству). Для этого вы должны установить соответствующие состояния визуализации, как показано тут:
// Использовать всю текстуру для визуализации точечного спрайта pDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
// Масштабировать в пространстве камеры pDevice->SetRenderState(D3DRS_POINTSCALEENABLE, TRUE);
Также необходимо установить минимальный размер точечного спрайта и насколько большим его делать, если в объявлении вершин отсутствует размер. На данный момент я установлю, чтобы точечные спрайты использовали размер 1, если в объявлении вершин отсутствуют необходимые данные, и чтобы минимальный размер был 0.
// Установить минимальный и определяемый по умолчанию размер точечного спрайта
pDevice->SetRenderState(D3DRS_POINTSIZE, FLOAT2DWORD(1.0f)); pDevice->SetRenderState(D3DRS_POINTSIZE_MIN, FLOAT2DWORD(0.0f));
Наконец необходимо установить несколько масштабируемых коэффициентов затухания, основанных на расстоянии. Direct3D сможет изменять размер частиц в зависимости от их удаленности от смотрящего. Здесь не нужно ничего необычного, так что значения, установленные по умолчанию (заданные в документации DirectX SDK) подойдут. Эти коэффициенты (которые фактически являются состояниями визуализации) устанавливаются при помощи следующего кода:
// Определить функцию, преобразующую float в DWORD
inline DWORD FLOAT2DWORD(FLOAT f) { return *((DWORD*)&f); }
346
// Установить значения затухания для масштабирования pDevice->SetRenderState(D3DRS_POINTSCALE_A, FLOAT2DWORD(1.0f)); pDevice->SetRenderState(D3DRS_POINTSCALE_B, FLOAT2DWORD(0.0f)); pDevice->SetRenderState(D3DRS_POINTSCALE_C, FLOAT2DWORD(0.0f));
Вы заметите кое-что забавное в последнем кусочке кодаиспользование функции FLOAT2DWORD. Как вы знаете, функция SetRenderState принимает только DWORD в качестве второго параметра. Значения коэффициентов затухания являются вещественными, так что приходится приводить их к типу DWORD. Вот здесь то и появляется FLOAT2DWORD. Используя эту функцию, вы можете указывать любое вещественное значения в качестве параметра функции SetRenderState и быть уверенным, что оно правильно преобразуется в DWORD.
Наконец можно визуализировать точечные спрайты! Помните, точечные спрайты являются обычными буферами вершин, использующими примитив типа точечный спрайт, указываемый флагомD3DPT_POINTLISTпри вызове функции DrawPrimitive. Не отвлекаясь, вот код, позволяющий включить альфа-тестирование и смешивание, установить FVF и источники потоков и вызвать функцию DrawPrimitive.
// Включить альфа-тестирование
pDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); pDevice->SetRenderState(D3DRS_ALPHAREF, 0x08); pDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
//Включить альфа-комбинирование (простого добавочного типа) pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCCOLOR); pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_DESTCOLOR);
//Установить вершинный шейдер и источник потока
pDevice->SetVertexShader(NULL); pDevice->SetFVF(POINTSPRITEFVF);
pDevice->SetStreamSource(0, pBuffer, 0, sizeof(sPointSprite));
// Визуализировать точечный спрайт (восемь спрайтов) pDevice->DrawPrimitive(D3DPT_POINTLIST, 0, 8);
Как вы можете видеть, работать с точечными спрайтами очень легко. По крайней мере намного проще, чем иметь дело с биллбордными квадратными полигонами, в спрайтах используется меньше данных. Единственной проблемой является то, что точечные спрайты ограничены в размерах и не полностью поддерживаются всеми видео-картами. Было бы очень хорошо, если бы была возможность использовать большие частицы и скорость визуализации точечных спрайтов, не правда ли? Замечательные новости - вы можете получить и то и другое при использовании вершинных шейдеров!