Перед тем как начать использовать основные компоненты Direct3D необходимо провести инициализацию интерфейса Direct3D.

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

Компоненты Direct3D

После прохождения объектом всех трех стадий готовая модель помещается в буфер кадра и выводится на экран.


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

Наиболее часто используемые компоненты Direct3D приведены в табл. 2.1.

 

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

 

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


Инициализация Direct3D

Процесс инициализации Direct3D может быть разбит на следующие этапы:

1. Запрос указателя на интерфейс IDirect3D9.Этот интерфейс применяется для получения информации об установленных в компьютере устройствах и создания интерфейса IDirect3DDevice9, являющимся нашим объектом C++, представляющим аппаратные устройства, используемые для вывода трехмерной графики.

2. Проверка возможностей устройства (D3DCAPS9), чтобы узнать поддерживает ли первичный видеоадаптер (основная видеокарта) аппаратную обработку вершин или нет. Мы должны знать это, чтобы создать интерфейс IDirect3DDevice9.

3. Инициализация экземпляра структуры D3DPRESENT_PARAMETERS. Эта структура содержит ряд параметров, позволяющих нам задать характеристики интерфейса IDirect3DDevice9, который необходимо создать.

4. Создание объекта IDirect3DDevice9, основываясь на инициализированной структуре D3DPRESENT_PARAMETERS. Как говорилось ранее, объект IDirect3DDevice9 — это наш объект C++, представляющий аппаратные устройства, используемые для отображения трехмерной графики.


Идеальное место для инициализации Direct3D – сразу после создания и отображения окна в функции InitInstance (создание окна и вывод окна на экран).

Cоздадим модуль, в котором будет находиться наша функция инициализации Direct3D. Пусть файл для исходного кода будет иметь имя dxfunc.cpp, а заголовочный файл будет иметь имя dxfunc.h.

Тогда содержимое заголовочного файла dxfunc.h с функцией инициализации имеет вид:

#ifndef _DXFUNC_H_#define _DXFUNC_H_ #include "d3d9.h"#include "d3dx9.h" // Функция инициализации Direct3DHRESULT DX3DInit ( IDirect3D9 **ppiD3D9, IDirect3DDevice9 **ppiD3DDevice9, HWND hWnd, DWORD iWidth, DWORD iHeight, BOOL bFullScreen ); #endif

Функция DX3DInit имеет следующие параметры:

· ppiD3D9 типа IDirect3D9 – указатель на указатель для хранения интерфейса IDirect3D 9-й версии;

· ppDi3DDevice9 типа IDirect3DDevice9 – указатель на указатель для хранения интерфейса устройства IDirect3DDevice 9-й версии;

· hWnd – окно, в котором будет происходить отображение Direct3D сцены;

· iWidth и iHeight – желаемая ширина и высота окна;

· bFullScreen – нужно ли выводить программу в полноэкранном режиме.Если да, то сразу будет происходить переключение на весь экран, иначе пользователь увидит запрос на выбор нужного режима. Чаще всего, создаются именно полноэкранные приложения, без поддержки оконного режима. Дело в том, что работа в этих двух режимах происходит по-разному, поэтому если этот параметр уже равен bFullScreen, то оконный режим предлагаться не будет.

Через параметры **ppiD3D9 и **ppDi3DDevice9 будут передаваться переменные, которые должны инициализироваться в функции. Если через параметры *ppiD3D9 и *ppDi3DDevice9 будут переданы значения в функцию инициализации, то после выхода из функции значение этих параметров восстановиться на исходное. Это связано с тем, что переменные копируются в стек, и внутри функции изменения будут происходить с копией.

Эффективное решение проблемы – использовать указатель, на указатель (**Переменная). Если изменить значение параметра **Переменная, то это значение на выходе восстановиться. Но если изменить значение, на которое указывает указатель (*Переменная), то оно не будет сохранено.

 

Пример: Допустим, что в основном модуле мы объявляем переменную *pD3D для хранения указателя на интерфейс IDirect3D9, который в изначальном состоянии равен нулю. Если передать эту переменную напрямую в функцию, то там, в переменную будет записан адрес интерфейса Direct3D, но после выхода адрес будет снова равен нулю.

Если передать указатель на *pD3D, то сам указатель **pD3D изменяться не будет и не нужно. Зато измениться *pD3D, и это значение не может сброситься.


Тип HRESULT - это 32-разрядное значение, разделенное на три различных поля: код серьезности ошибки, код устройства и код ошибки. Для работы со значением HRESULT служат специальные константы, такие как S_OK, E_FAIL, E_ABORT и так далее. А для проверки значений тип HRESULT предназначены такие макросы как SUCCEEDED, FAILED. Эти макросы возвращают значение типа BOOL, указывающее, соответствует ли переданное значение корректному завершению функции или ошибке.

Предупреждение V545 выдается в том случае, если переменная типа HRESULT используется в операторе 'if' как переменная типа bool.

Пример:

HRESULT hr;
Пример некорректен
...if (hr){}

HRESULT и тип bool это совершенно разные по смыслу типы.

 

Тип HRESULT имеет множество состояний. Это может быть 0L (S_OK), 0x80000002L (Ran out of memory), 0x80004005L (unspecified failure), и так далее. Состояние S_OK кодируется как 0.

Для проверки значения HRESULT необходимо использовать макрос SUCCEEDED или FAILED. Корректные варианты кода:

if (FAILED(hr)){}if (SUCCEEDED(hr)){}

Напишем в Windows-приложении инициализацию Direct3D. Для этого в основном модуле программы объявим две переменные для хранения создаваемых интерфейсов на IDirect3D9 и устройство IDirect3DDevice9:

IDirect3D9 *pD3D = NULL;IDirect3DDevice9 *pD3DDevice = NULL;

 

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

// Вызов функции инициализации // Если результат работы функции не равен S_OK,// то произошла ошибкаif (DX3DInit(&pD3D, &pD3DDevice, hWnd, 800, 600, FALSE)!=S_OK){ MessageBox(hWnd, _T("Ошибка инициализации DirectX"), _T("Error"), MB_OK); return FALSE;} // Отображение и обновление окна ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);

 

Функция инициализации DX3DInit, будет запрашивать с помощью окна диалога, необходимо ли инициализироваться в полноэкранном режиме или нет. Так как все окна диалога после инициализации Direct3Dбудут отображаться неверно, если вообще покажутся на экране, то нужно вывести эти окна диалога до каких-либо инициализаций.