netlib.narod.ru< Назад | Оглавление | Далее >

Начинаем работать с DirectX Graphics

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

В данном разделе я познакомлю вас с компонентами DirectX Graphics, которые будут использоваться в этой книге и покажу как запустить графическую систему и подготовить ее к рисованию.

ПРИМЕЧАНИЕ
Хотя в последних версиях графические компоненты и называются DirectX Graphics, я буду ссылаться как на Direct3D, поскольку его используют все трехмерные графические объекты.

 

ПРИМЕЧАНИЕ
Чтобы в вашем проекте использовать Direct3D надо добавить в него заголовочный файл D3D9.H и библиотеку D3D9.LIB

Компоненты Direct3D

Direct3D разделяет графический функционал по нескольким COM-объектам. У каждого объекта есть собственное назначение, например объект IDirect3D9 используется для управления всей графической системой в целом, а объект IDirect3DDevice9 применяется для управления процессом визуализации графики на экране.

В этой книге я покажу вам только те объекты, которые перечислены в таблице 2.1; именно эти объекты вы скорее всего будете использовать в вашем проекте игры.


Таблица 2.1. Основные компоненты Direct3D



Компонент Описание

IDirect3D9 Используйте этот объект для сбора информации об установленном графическом оборудовании и инициализации интерфейсов устройств
IDirect3D9Device9 Имеет дело непосредственно с аппаратурой трехмерной графики. С ним вы визуализируете графику, управляете ресурсами изображений, создаете и устанавливаете режимы визуализации, фильтры затенения и т.д.
IDirect3DVertexBuffer9 Содержит массив данных вершин, используемый для рисования полигонов
IDirect3DTexture9 Используйте этот объект для хранения всех изображений, применяемых для рисования граней в трехмерных (и двухмерных) изображениях

 

ПРИМЕЧАНИЕ
Хотя есть еще несколько компонентов Direct3D, которые можно использовать, они выходят за рамки данной книги. Чтобы больше узнать об этих дополнительных объектах, обратитесь к документации DirectX SDK.

Инициализация системы

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

  1. Получение интерфейса Direct3D.

  2. Выбор видеорежима.

  3. Установка метода показа.

  4. Создание интерфейса устройства и инициализация дисплея.

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

Получение интерфейса Direct3D

Первый шаг к использованию графики — инициализация объекта IDirect3D9. Выполняется она с помощью функции Direct3DCreate9.

IDirect3D9 *Direct3DCreate9(
    UINT SDKVersion); // D3D_SDK_VERSION

 

ПРИМЕЧАНИЕ
Большинство функций DirectX (также как все COM-объекты) возвращают значение типа HRESULT. Время от времени вы будете встречать функции (такие, как Direct3DCreate9), которые возвращают значение типа отличного от HRESULT, так что будьте начеку.

Единственным аргументом этой функции должна быть константа D3D_SDK_VERSION, указывающая используемую версию SDK. Возвращаемая переменная — это указатель на созданный для вас объект IDirect3D9, или, если при создании объекта Direct3D произошла ошибка, будет возвращен NULL.

Для использования этой функции достаточно объявить экземпляр объекта IDirect3D9 и вызвать саму функцию:

IDirect3D9 g_D3D; // глобальный объект IDirect3D9

if((g_D3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL) {
     // Произошла ошибка
}

Выбор видеорежима

После того, как объект IDirect3D9 создан, можно использовать его для получения информации о графической системе, которая включает список видеорежимов, которые может поддерживать Direct3D. Фактически, если вы не хотите менять формат, то можете запросить у объекта IDirect3D9 информацию о текущем видеорежиме.

Видеорежимы различаются по разрешению экрана (высоте и ширине в пикселях), глубине цвета (количеству отображаемых цветов) и частоте кадров. Например, вы можете установить разрешение 640 × 480 точек с 16-разрядной глубиной цвета и предлагаемой видеокартой по умолчанию частотой кадров.

Информация о видеорежиме хранится в структуре D3DDISPLAYMODE.

typedef struct _D3DDISPLAYMODE {
    UINT      Width;       // Ширина экрана в пикселях
    UINT      Height;      // Высота экрана в пикселях
    UINT      RefreshRate; // Частота кадров (0 = по умолчанию)
    D3DFORMAT Format;      // Формат цвета
} D3DDISPLAYMODE;

Относительно высоты, ширины и частоты кадров все ясно, но что насчет формата цвета? В графике вы обычно выбираете сколько бит будет использоваться в одном пикселе (16, 24 или 32) для хранения информации о цвете. Чем больше битов используется, тем больше цветов можно отобразить (и тем больше потребуется памяти).

Цветовые режимы обычно различаются по количеству битов, отводимых для каждого компонента цвета (красного, зеленого, синего и, возможно, альфа). Возьмем к примеру 16-разрядный цветовой режим — 5 бит для красного, 5 бит для зеленого, 5 бит для синего и один бит для альфа-канала. 5 бит для хранения позволяют использовать 32 оттенка каждого компонента. Для альфа-канала используется один бит, который может быть либо установлен, либо сброшен.

Когда вы ссылаетесь на цветовой режим, вам недостаточно только сказать, что он 16-разрядный, а надо указать количество битов для компонентов цвета, например 1555 (1 для альфа, 5 для красного, 5 для зеленого и 5 для синего). Стандартными цветовыми режимами являются 555 (5 для красного, 5 для зеленого, 5 для синего без альфа-канала), 565 (5 для красного, 6 для зеленого и 5 для синего) и 888 (по 8 бит для каждого компонента). Заметьте, что значение альфа нужно не всегда.

В Direct3D цветовые режимы определены как члены перечисления, представленные в таблице 2.2. На данном этапе предположим, что вы хотите установить видеорежим 640 × 480 и использовать формат цвета D3DFMT_R5G6B5. Вот как в этом случае должна выглядеть инициализация структуры D3DDISPLAYMODE:

D3DDISPLAYMODE d3ddm;

d3ddm.Width       = 640;
d3ddm.Height      = 480;
d3ddm.RefreshRate = 0; // по умолчанию
d3ddm.Format      = D3DFMT_R5G6B5;

Таблица 2.2. Константы цветовых режимов в Direct3D



Значение Формат Описание

D3DFMT_R8G8B8 24 разряда 8 красный, 8 зеленый, 8 синий
D3DFMT_A8R8G8B8 32 разряда 8 альфа, 8 красный, 8 зеленый, 8 синий
D3DFMT_X8R8G8B8 32 разряда 8 не используется, 8 красный, 8 зеленый, 8 синий
D3DFMT_R5G6B5 16 разрядов 5 красный, 6 зеленый, 5 синий
D3DFMT_X1R5G5B5 16 разрядов 1 не используется, 5 красный, 5 зеленый, 5 синий
D3DFMT_A1R5G5B5 16 разрядов 1 альфа, 5 красный, 5 зеленый, 5 синий

Чтобы проверить поддерживает ли видеокарта необходимый вам формат цвета, заполните структуру D3DDISPLAYFORMAT информацией о видео режиме и выполните вызов функции:

// g_pD3D = ранее инициализированный объект Direct3D
// d3df   = ранее инициализированная структура D3DFORMAT
// Проверка наличия видеорежима
if(FAILED(g_pD3D->CheckDeviceType(D3DADAPTER_DEFAULT,
                      D3DDEVTYPE_HAL, &d3df, &d3df, FALSE))) {
    // Ошибка - цветовой режим не поддерживается
}

Задание видеорежима подразумевает, что вы работаете в полноэкранном режиме. Если же вы хотите использовать оконный режим (также, как и обычные приложения Windows), Direct3D может предоставить вам информацию об установленном видеорежиме. Для этого предназначен следующий вызов функции:

// g_pD3D = ранее инициализированный объект Direct3D
D3DDISPLAYMODE d3ddm;

if(FAILED(g_pD3D->GetDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))) {
    // Произошла ошибка
}

 

ПРИМЕЧАНИЕ
Так же как и все COM-интерфейсы, Direct3D возвращает значение типа HRESULT. Значение D3D_OK сообщает, что работа функции завершена успешно; любое другое значение свидетельствует об ошибке. Для простой проверки возвращаемых кодов вы можете использовать стандартные макросы FAILED или SUCCEEDED.

В случае успешного завершения показанный выше вызов IDirect3D9::GetDisplayMode возвращает заполненную данными структуру D3DDISPLAYMODE.

ВНИМАНИЕ!
Некоторые видеокарты не позволяют использовать определенные видеорежимы. Вы должны сами определить, какие видеорежимы поддерживаются видеокартой. Если ваша программа будет работать в оконном режиме, это не является проблемой, поскольку Direct3D обрабатывает параметры цветового режима за вас.

Установка метода показа

Следующий этап подготовки Direct3D — определение того, как графика будет показываться пользователю. Вы хотите использовать окно, полный экран или вторичный буфер (о вторичном буфере вы можете прочитать в приведенном ниже примечании)? Какую частоту кадров вы хотите использовать? Вся эта информация (и, как вы увидите, еще и некоторая другая) хранится в структуре D3DPRESENT_PARAMETERS:

typedef struct _D3DPRESENT_PARAMETERS
{
    UINT      BackBufferWidth;  // Ширина вторичного буфера
    UINT      BackBufferHeight; // Высота вторичного буфера
    D3DFORMAT BackBufferFormat; // Формат экрана
    UINT      BackBufferCount;  // 1

    D3DMULTISAMPLE_TYPE MultiSampleType; // 0
    D3DSWAPEFFECT SwapEffect;            // способ показа
                                         // вторичного буфера

    HWND hDeviceWindow; // NULL
    BOOL Windowed;      // TRUE для оконного режима
                        // FALSE для полноэкранного режима

    BOOL      EnableAutoDepthStencil;     // FALSE
    D3DFORMAT AutoDepthStencilFormat;     // 0

    DWORD     Flags;                      // 0

    UINT      FullScreen_RefreshRateInHz; // 0
    UINT      PresentationInterval;       // 0
} D3DPRESENT_PARAMETERS;

 

ПРИМЕЧАНИЕ
Вторичный буфер (back buffer) — это внеэкранная графическая поверхность (того же размера, что и окно или экран), которая получает все результаты операций рисования. Чтобы увидеть графику, помещенную во вторичный буфер, вы используете операцию, называемую переключение (flip), которая отображает содержимое вторичного буфера на экране или в окне. Эта операция обеспечивает плавное обновление — пользователь никогда не видит, что рисует программа, пока изображение не будет полностью готово для вывода на экран.
Эта концепция иллюстрируется на рис. 2.9, где показаны первичный буфер (экран) и вторичный буфер (внеэкранная поверхность). Вы рисуете во вторичном буфере и, когда закончите рисование, выполняете переключение, чтобы вторичный буфер был отображен на экране.

Рис. 2.9. Рисование во вторичном буфере скрывает от вас объекты, пока вы не выполните переключение экранов

Рис. 2.9. Рисование во вторичном буфере скрывает от вас объекты, пока вы не выполните переключение экранов


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

Вот два варианта инициализации, которые вы можете использовать в зависимости от того, в полноэкранном или в оконном режиме вы собираетесь работать (с небольшим фрагментом, который используется в обоих вариантах):

// d3ddm = ранее инициализированная структура D3DDISPLAYMODE
D3DPRESENT_PARAMETERS d3dpp;

// Очищаем структуру
ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));

// Для оконного режима используйте:
d3dpp.Windowed         = TRUE;
d3dpp.SwapEffect       = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format; // используем то же цветовой режим

// Для полноэкранного режима используйте:
d3dpp.Windowed                   = FALSE;
d3dpp.SwapEffect                 = D3DSWAPEFFECT_FLIP;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_DEFAULT;
d3dpp.BackBufferFormat           = d3ddm.Format; // используем тот же
                                                 // цветовой режим

// И для оконного и для полноэкранного режима указываем ширину и высоту
d3dpp.BackBufferWidth  = Width;  // Укажите ваше значение ширины
d3dpp.BackBufferHeight = Height; // Укажите ваше значение высоты

Создание интерфейса устройства и инициализация дисплея

Наконец вы можете создать интерфейс устройства Direct3D — рабочую лошадку системы трехмерной графики. Чтобы создать и инициализировать интерфейс дисплея вызовите функцию IDirect3D9::CreateDevice, передав ей ранее инициализированные экземпляры структур D3DDISPLAYMODE и D3DPRESENT_PARAMETERS:

HRESULT IDirect3D9::CreateDevice(
    UINT       Adapter,       // D3DADAPTER_DEFAULT
    D3DDEVTYPE DeviceType,    // D3DDEVTYPE_HAL
    HWND       hFocusWindow,  // дескриптор окна для визуализации
    DWORD      BehaviorFlags, // D3DCREATE_SOFTWARE_VERTEXPROCESSING
    D3DPRESENT_PARAMETERS *pPresentationParameters, // d3dpp
    IDirect3DDevice9 *ppReturnedDeviceInterface);   // объект устройства

У функции CreateDevice есть параметры для передачи структуры параметров показа, которую вы создали, а также дескриптора окна, принадлежащего вашему приложению (которое Direct3D будет использовать для отображения визуализированной графики). Остальные аргументы достаточно стандартны и вам редко придется менять их значения. Последний аргумент — это указатель на объект устройства Direct3D, который вы создаете. Вызов IDirect3D9::CreateDevice может выглядеть так:

// g_pD3D = ранее инициализированный объект Direct3D
// hWnd   = дескриптор используемого для визуализации окна
// d3dpp  = ранее инициализированная структура параметров показа
IDirect3DDevice9 *g_pD3DDevice;
if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,
                               D3DDEVTYPE_HAL, hWnd,
                               D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                               &d3dpp, &g_pD3DDevice))) {
    // Произошла ошибка
}

 

ПРИМЕЧАНИЕ
Direct3D работает с двумя различными типами устройств — HAL (Hardware Abstraction Layer) и REF (REFerence device). Устройство HAL — это установленная у вас видеокарта, и именно это устройство вы будете использовать в большинстве случаев при разработке игр. Устройство REF (объект программного визуализатора) используется когда вам надо отладить приложение или проверить возможность, которая не поддерживается установленной видеокартой. HAL более быстрое из устройств, поскольку позволяет Direct3D работать непосредственно с аппаратурой видеокарты, а устройство REF выполняет всю работу программно (и поэтому работает исключительно медленно).

Потеря устройства

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

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

Как узнать что контроль утерян? Проверив значение, возвращаемое любой функцией объекта устройства! Например, далее в этой главе в разделе «Показ сцены», вы увидите как отобразить графику на экране монитора. Если этот вызов возвращает значение D3DERR_DEVICELOST, вы знаете, что устройство потеряно.

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

HRESULT IDirect3DDevice9::Reset(
    D3DPRESENT_PARAMETERS *pPresentationParameters);

Единственным параметром функции является структура параметров показа, которую вы использовали при инициализации устройства:

// g_pD3DDevice = ранее инициализированный объект устройства
// d3dpp        = ранее инициализированная структура параметров показа
g_pD3DDevice->Reset(&d3dpp);

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

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

Знакомство с D3DX

Работа с Direct3D остается главной задачей. Хотя Microsoft упростила многие интерфейсы, для вас остается много различной работы. Чтобы сократить время разработки приложений Microsoft создала библиотеку D3DX. Библиотека D3DX объединяет различные относящиеся к графике полезные функции, такие как работа с сетками, текстурами, шрифтами, математикой и т.д. В этой книге вы увидите как можно использовать библиотеку D3DX чтобы облегчить процесс разработки игр.

ПРИМЕЧАНИЕ
Все функции библиотеки D3DX начинаются с префикса D3DX (например, D3DXCreateFont). Библиотека D3DX содержит не только функции, но и COM-объекты, такие как ID3DXBaseMesh.

 

ПРИМЕЧАНИЕ
Чтобы использовать библиотеку D3DX в своем проекте вы должны включить в него заголовочный файл D3DX9.H и компоновать его с библиотекой D3DX9.LIB. Кроме того, вы можете добавить ссылку на библиотеку D3DXOF.LIB, которая потребуется вам в дальнейшем.

netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz