Войти
ПрограммированиеСтатьиГрафика

Direct3D: Первая программа под DirectX9.

Автор:

Введение. Основы работы с Direct3D
Вывод 3D объекта.

Введение. Основы работы с Direct3D

Для того чтобы составить свою первую программу под DirectX9, необходимо установить DirectX9 SDK (Software Development Kit) на своём компьютере. DirectX9 SDK можно взять с сайта Microsoft c этой страницы:
Microsoft DirectX 9.0 Downloads.

SDK представляет собой набор необходимых компонент для работы с DirectX. В него входят заголовочные файлы, статические библиотеки, документация, примеры, а так же сам DirectX (runtime). DirectX представляет собой набор COM объектов. Каждый объект отвечает за свою работу. Это может быть: работа с графикой, со звуком, с сетью и т.д. Нас интересует работа с 3D графикой. За это отвечает Direct3D.

В этом уроке мы попробуем создать несложное windows приложение на С++, использующее Direct3D.

Некоторые понятия о работе 3D приложения.

Обычные приложения, осуществляющие вывод 3D графики имеют такую структуру:

Вначале происходит инициализация. Сюда входит создание главного окна приложения, инициализация Direct3D, инициализация неких данных, нужных приложению и т.п. Инициализация Direct3D у нас будет в функции InitD3D().

Далее осуществляется вывод самой графики (render). Рендер 3D приложения обычно повторяется в цикле. Например, у нас будет функция DrawScene(), которая будет постоянно вызываться, в ней и будет происходить вывод 3D объектов.

В конце, необходимо освободить (уничтожить) все задействованные нами ресурсы и закончить работу приложения. Перед выходом также нужно освободить объекты, относящиеся к Direct3D. Это мы сделаем в функции ReleaseD3D();

Объявление этих трёх функций мы поместим в заголовочный файл firstD3D.h

// firstD3D9.h

bool InitD3D(HWND hWnd);
long DrawScene();
void ReleaseD3D();

Построение windows приложения для нашего примера, то есть то, что относится не к Direct3D, а к созданию главного окна приложения и обработке windows сообщений, возьмём из этого урока: Работаем с MS Visual Studio.

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

Direct3D представляет собой несколько интерфейсов. Каждый интерфейс также отвечает за отдельные части в Direct3D. Например, есть интерфейс для работы с текстурами, интерфейс для работы с вершинными буферами, вершинными шейдерами и т.д. Работа осуществляется через методы (функции), предоставляемые интерфейсами.

Чтобы работать с Direct3D, необходимо включить заголовочный файл d3d9.h:

#include <d3d9.h>

Кроме того, подключите статическую библиотеку d3d9.lib

Самый основной интерфейс называется IDirect3D9.

Вообще в DirectX-е принято все названия интерфейсов начинать с "I", далее следует название COM объекта, в нашем случае - Direct3D. Девятка в конце означает номер версии DirectX-а. Все интерфейсы Direct3D достаются из этого основного IDirect3D9. Только сам IDirect3D9 создаётся обычной функцией:

IDirect3D9  * pD3D;

pD3D = Direct3DCreate9( D3D_SDK_VERSION);

Здесь D3D_SDK_VERSION - обычный макрос, определённый в d3d9.h, указывающий на текущую версию SDK.

Приведённая функция возвращает указатель на интерфейс IDirect3D9. Если функция вернула NULL, значит, скорее всего, Direct3D 9-й версии  не установлен на компьютер пользователя вашего приложения. Если же она вернула значение отличное от нуля  - это значение и есть указатель на интерфейс IDirect3D9.

Второй по значимости интерфейс является интерфейсом устройства, называется он IDirect3DDevice9. Этот интерфейс всегда создаётся вторым после IDirect3D9. Отвечает он за вывод изображения, за создание ресурсов, создание шейдеров и т.п. Неудивительно, что этот интерфейс предоставляет самое большое количество методов.

IDirect3DDevice9 создаётся методом IDirect3D9::CreateDevice(). Вот описание параметров этого метода:

HRESULT CreateDevice(

    UINT Adapter,
    D3DDEVTYPE DeviceType,
    HWND hFocusWindow,
    DWORD BehaviorFlags,
    D3DPRESENT_PARAMETERS *pPresentationParameters,
    IDirect3DDevice9** ppReturnedDeviceInterface
);
Парметры:
Adapter - выставляйте в D3DADAPTER_DEFAULT.
DeviceType - тип устройства. От установки этого параметра будет зависеть, используете ли вы акселерацию видео карты - или нет. Значение D3DDEVTYPE_HAL, означает, что мы будем пользоваться возможностями видеокарты для вывода геометрии, что ускорит работу графического приложения.
hFocusWindow -выставляется handle окна. В нашем случае - это главное окно приложения.
BehaviorFlags - здесь можно указать, как обрабатываются вершины: видеокартой или программно. Если ваша карта поддерживает акселерацию для обработки вершин - используйте D3DCREATE_HARDWARE_VERTEXPROCESSING, если нет - попробуйте D3DCREATE_SOFTWARE_VERTEXPROCESSING или D3DCREATE_MIXED_VERTEXPROCESSING.

Основное место в методе CreateDevice() занимает объект структуры D3DPRESENT_PARAMETERS. Рассмотрим нужные нам элементы этой структуры:
Windowed - выставляем здесь TRUE, если наше приложение оконное, а не на весь экран.
BackBufferFormat - Формат для back буфера. Это специальный буфер, в котором формируется изображение, после того как изображение готово, этот буфер показывается в окне приложения. Здесь выставляем D3DFMT_UNKNOWN, поскольку наше приложение оконное, то формат возьмётся автоматически в соответствии с текущими настройками экрана.
SwapEffect - Здесь D3DSWAPEFFECT_DISCARD. Это значение полезно выставлять, пока вы только начинаете разрабатывать свою программу. Буфер заполняется шумом, если вы забудете сделать нужные операции по работе с выводом объектов, то вы увидите этот шум, что укажет вам на ошибку, то есть это полезно для режима debug.

Последний параметр ppReturnedDeviceInterface в методе CreateDevice() - есть результат этого метода, собственно здесь вы получаете указатель на интерфейс IDirect3DDevice9.

В итоге имеем функцию инициализирующую Direct3D:

IDirect3D9 * pD3D;
IDirect3DDevice9 * pDevice;

bool InitD3D(HWND hWnd)
{
  // Создание объекта Direct3D
  pD3D = Direct3DCreate9( D3D_SDK_VERSION);
  if( !pD3D)
    return false;
  
  // Создание устройства рендера.
  D3DPRESENT_PARAMETERS d3dpp = {0};
  d3dpp.Windowed = TRUE;
  d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
  d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
  HRESULT hr;
  hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                           D3DCREATE_HARDWARE_VERTEXPROCESSING,
                           &d3dpp, &pDevice );
  if( FAILED(hr) || !pDevice)
    return false;

  return true;
}

Рендер.

Поскольку каждый кадр строится заново, вам необходимо вначале очистить экран функцией

pDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,128), 1.0f, 0);
Из всех параметров, сейчас нас интересуют только следующие:
D3DCLEAR_TARGET - говорит о том, что мы будем очищать буфер цвета, то есть содержащий саму картинку.
D3DCOLOR_XRGB(0,0,128) - это макрос для синего цвета, то есть фактически мы будем не очищать буфер цвета, а заполнять его указанным синим цветом.

В Direct3D есть такое понятие как Сцена (scene). В сцену входят со своими свойствами все 3D объекты, которые вы собираетесь отобразить в окне приложения. Перед началом вывода сцены, необходимо вызвать специальный метод:

pDevice->BeginScene();
соответственно, после того, как вы отобразили сцену, вызвать метод:
pDevice->EndScene();
То есть, вывод всех объектов, должен происходить между этими двумя функциями.

Поскольку всё изображение формируется в невидимом буфере (backbuffer), необходимо после формирования изображения показать этот буфер. Для этого, нужно вызвать метод:

pDevice->Present( NULL, NULL, NULL, NULL );

Итак, мы получили функцию DrawScene(), которая отвечает за рендер сцены:

long DrawScene()
{
  pDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,128), 1.0f, 0 );
  pDevice->BeginScene();
  
  DrawObject();
  
  pDevice->EndScene();
  pDevice->Present( NULL, NULL, NULL, NULL );
  return 0;
}

Здесь функция DrawObject(); отвечает за вывод некоторого объекта (рассмотрим ниже).

Завершение работы с Direct3D.

Освобождение объектов Direct3D происходит перед выходом из вашей программы. Осуществляется это методом Release(), предоставленным каждым интерфейсом объектов Direct3D. Заметьте, что освобождение объектов происходит в обратной последовательности по отношению к последовательности, в которой они создавались. То есть, если вы попытаетесь освободить объект Direct3D раньше, чем объект Direct3DDevice, то это будет неверно.

Получаем функцию, которую вызываем перед завершением программы:

void ReleaseD3D()
{
  if(pDevice)
    pDevice->Release();
  if(pD3D)
    pD3D->Release();
}
Страницы: 1 2 Следующая »

#Direct3D, #DirectX, #DirectX9

30 мая 2002 (Обновление: 13 июня 2009)

Комментарии [33]