Програмування з використанням DirectX9, Різне, Програмування, статті

Від автора.

Ця стаття присвячена основам програмування тривимірних додатків на С + + і використанню бібліотеки DirectX 9.

Введення


Причиною появи бібліотеки DirectX з’явилася повільність стандартних графічних засобів ОС Windows. Крім того, розробнику складно передбачити обладнання користувача, який буде грати в гру, тим більше що в наш час обладнання оновлюється мало не щодня. Виходом із ситуації стала розробка бібліотек для роботи з графікою. Найбільш популярні – OpenGL і DirectX. Вибору між цими бібліотеками робити не будемо. Багато фахівців віддають перевагу OpenGL, інші DirectX. На форумах і конференціях йдуть обговорення, перераховуються переваги і недоліки кожної.


OpenGL – Open Graphic Library, відкрита графічна бібліотека. Термін “відкритий” означає “незалежний від виробників”. Бібліотеку OpenGL можуть виробляти різні фірми та окремі розробники, головне, щоб вона задовольняла специфікації (стандарту) OpenGL і ряду тестів. Процедури OpenGL працюють як з растровою, так і з векторною графікою і дозволяють створювати дво-і тривимірні об’єкти довільної форми. Для об’єкта може бути заданий матеріал і накладена растрова текстура. Об’єктами сцен також є джерела світла. До того ж в бібліотеці OpenGL є засоби взаємодії графічних об’єктів, які дозволяють створювати ефекти прозорості, туману, змішування кольорів, виконувати логічні операції над об’єктами, пересувати об’єкти сцени, лампи і камери за заданими траєкторіями і т.д.


DirectX – Це мультимедійна бібліотека, що дозволяє безпосередньо працювати з апаратним забезпеченням комп’ютера в обхід традиційних засобів платформи Win32. Вся DirectX ділиться на компоненти, що відповідають за ту чи іншу частину роботи бібліотеки:


DirectX Graphics – об’єднує компоненти DirectDraw і Direct3D для роботи з двох-і тривимірною графікою. Бібліотека спроектована так, що вона може використовувати всі апаратні можливості відеокарти по обробці графіки. Якщо якісь необхідні можливості не реалізовані апаратно, то вони емулюються програмно.
DirectInput – взаємодія з пристроями введення (миша, клавіатура, джойстик, кермо, ….).
DirectAudio – об’єднує компоненти DirectMusic і DirectSound. Компонент призначений для роботи з пристроями відтворення звуку, працює значно швидше стандартних MCI-функцій Windows, дозволяє синхронізувати те, що відбувається на екрані зі звуковими ефектами, дає можливість уповільнювати і прискорювати відтворення, змішувати звуки, створювати об’ємні звукові ефекти.
DirectPlay – мережева зв’язок між комп’ютерами.
DirectShow – програмування мультимедійних додатків, забезпечує високоякісний захоплення і програвання мультимедійних потоків даних.
DirectSetup – інсталяція компонентів DirectX.

Розглянемо детальніше DirectX.


DirectX включає в себе рівень абстракції – HAL (Hardware Abstraction Layer). За допомогою HAL відбувається взаємодія програми з обладнанням комп’ютера, незалежно від виробника обладнання. Це дає можливість написаному коду працювати на будь-якому апаратному забезпеченні без внесення параметрів цього обладнання.




Вся бібліотека DirectX побудована на основі СОМ (Component Object Model). Вам не доведеться заглиблюватися в суть цієї технології, так як вся робота з СОМ заснована на виклики відповідних функцій. У складі СОМ є API, звана СОМ-бібліотекою; з її допомогою досягається управління всіма компонентами. Кожен з програмних компонентів реалізує певну кількість СОМ-об’єктів, доступ до яких здійснюється за допомогою інтерфейсів, які, в свою чергу складаються з функцій. За допомогою цих функцій і відбувається взаємодія з СОМ-об’єктом.


Побудова сцени


Перш ніж почати програмувати, потрібно чітко уявляти схему побудови сцени.


  1. Створення віконного програми. Частина програми взаємодіє з Windows.
  2. Ініціалізація Direct3D. Створення інтерфейсів, ініціалізація 3D пристроїв, настройка програмної та апаратної частини комп’ютера.
  3. Створення об’єкта. Введення координат вершин трикутників з яких складається об’єкт, призначення формату вершин для подальшої трансформації.
  4. Освітлення, призначення матеріалу, накладення текстур. Створення джерел освітлення і накладення текстур на об’єкти сцени.
  5. Рендер сцени. Отрісовка всіх об’єктів з урахуванням освітлення, кута огляду, видимості об’єктів, падаючих тіней … До цього ми тільки вводили параметри всіх складових, а тепер відеокарта проводить розрахунок і виведення на екран всієї сцени.

Звичайно, на ці етапи ділити створення тривимірного програми можна тільки умовно, але все ж таке розкладання допомагає зрозуміти в загальних рисах створення програми.

Створення віконного програми


Перш ніж приступити до програмування графіки за допомогою DirectX, необхідно створити каркас програми. Каркас додатка це найпростіше Windows додаток, його опис пропустимо через те, що воно розглянуто у всіх книгах програмування під Windows, і опис можна знайти на багатьох сайтах в Інтернеті. Головна відмінність – це виведення на екран, ми не використовуємо повідомлення WM_PAINT, А обробка повідомлень виглядає наступним чином:

while(msg.message!=WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}else
RenderScene();
}

Створюємо цикл, вихід з якого можливий при отриманні повідомлення WM_QUIT.
Замість звичної функції GetMessage використовуємо PeekMessage, Яка призначена для роботи в режимі реального часу. Тобто постійно сканується чергу повідомлень, якщо такі є, вони обробляються, інакше викликається функція RenderScene() в якій відбувається створення і виведення сцени на екран.


Ініціалізація DirectX


Для початку необхідно підключити заголовний файл.
Тепер необхідно підключити бібліотеку d3d9.lib, її можна підключити у властивостях проекту або явно підключити з використанням команди препроцесора # pragma. Різниці ніякої немає, використовуємо другий спосіб:

#pragma comment(lib, “d3d9.lib”)

Створимо функцію, в якій будуть инициализироваться інтерфейси DirectX:

bool InitDirectX(void).

Створюємо глобальні змінні:
LPDIRECT3D9 pDirect3D – покажчик на головний інтерфейс. Це перший об’єкт, який необхідно створити, тільки після цього можна отримати доступ до всіх інших інтерфейсів.
LPDIRECT3DDEVICE9 pDirectDevice – інтерфейс пристрою Direct3D.


Для зручності створимо функцію InitDirectX(), В якій будемо ініціалізувати пристрої 3D.

bool InitDirectX(void)
{
if((pDirect3D=Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
return(false);
D3DDISPLAYMODE stDisplay;
if(FAILED(pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &stDisplay)))
return(false);
D3DPRESENT_PARAMETERS Direct3DParametr;
ZeroMemory(&Direct3DParametr, sizeof(Direct3DParametr));
Direct3DParametr.Windowed=TRUE;
Direct3DParametr.SwapEffect=D3DSWAPEFFECT_DISCARD;
Direct3DParametr.BackBufferFormat=stDisplay.Format;
if(FAILED(pDirect3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &Direct3DParametr, &pDirectDevice)))
return(false);
return(true);
}

pDirect3D=Direct3DCreate9(D3D_SDK_VERSION) – Створюється основний покажчик на інтерфейс IDirect3D9. Завжди використовується один макрос D3D_SDK_VERSION, Що вказує на поточну версію SDK.

Для перевірки результату виконання функції використовується макрос FAILED(), Який перевіряє код на наявність збою. Працює за схемою:

if(FAILED(…)) {Збій}
else {Функція виконана успішно} також можна використовувати макрос SUCCEEDED, за такою схемою
if(SUCCEEDED(…)) {Функція виконана успішно}
else {Збій}

Тепер потрібно отримати поточні параметри дисплея за допомогою функції GetAdapterDisplayMode().
Створюємо структуру параметрів подання D3DPRESENT_PARAMETERS Direct3DParametr і задаємо значення:


Direct3DParametr.Windowed=TRUE; – Віконний режим роботи додатку.
Direct3DParametr.SwapEffect=D3DSWAPEFFECT_DISCARD; – Не використовувати буфера обміну.
Direct3DParametr.BackBufferFormat=stDisplay.Format; – Формат відеорежиму заднього буфера встановлюємо рівним поточному відеорежимі.

Створюємо об’єкт інтерфейсу CreateDevice. Всі подальші дії будуть спиратися на даний інтерфейс пристрою і його параметри.


D3DADAPTER_DEFAULT – Поточна відеокарта (зазвичай в системі встановлена ​​1 відеокарта).
D3DDEVTYPE_HAL – Вибір способу обробки інформації, за допомогою відеокарти.
hWnd – Дескриптор головного вікна.
D3DCREATE_HARDWARE_VERTEXPROCESSING – Спосіб обробки вершин (в даному випадку апаратно). Можна використовувати значення D3DCREATE_SOFTWARE_VERTEXPROCESSING – Програмна обробка вершин (при використанні старих відеокарт).
&Direct3DParametr – Параметри відеорежиму.
&pDirectDevice – Результат операції, покажчик на щойно створений об’єкт.

Функція для рендеринга сцени


У цій частині коду відбувається виведення зображення на екран

void RenderScene(void)
{
if(pDirectDevice==NULL)
return;
pDirectDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 192, 0), 1.0f, 0);
pDirectDevice->BeginScene();
pDirectDevice->EndScene();
pDirectDevice->Present(NULL, NULL, NULL, NULL);
}

Спочатку необхідно очистити задній буфер і заповнити весь простір одним кольором:

Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 192, 0), 1.0f, 0)

Створення сцени відбувається між рядками:

	pDirectDevice->BeginScene();
pDirectDevice->EndScene();

Все що в цьому блоці, прорисовується в задньому буфері.
Тепер залишилося вивести вміст заднього буфера на екран:

pDirectDevice->Present(NULL, NULL, NULL, NULL)

На даний момент у нас є повністю працездатна оболонка для створення 3D додатки. Створити новий проект Win32, Empty і додати цей файл (window1.cpp). Можна компілювати і запускати (для виходу потрібно натиснути будь-яку клавішу). Так як ми нічого не малювали, то на екрані немає жодного об’єкту. Все що було зроблено це ініціалізація пристроїв та очищення екрану в темно-зелений колір. Насолодившись результатами роботи, натискаємо будь-яку кнопку для виходу з програми і приступаємо до малювання об’єктів.


Створення об’єкта


Якщо подивитися на схему створення 3D сцени, вийде що пропущені кроки – створення об’єкта та застосування матеріалів з освітленням. Освітлення та матеріали прібережем на наступну статтю, а об’єкт створити потрібно!
Спочатку визначимося, що ж малювати? – Сердечко.
Всі об’єкти при програмуванні в 3D складаються з частин. Найпростіша фігура з якої можна скласти будь-яку іншу – це трикутник. Яка б не була у Вас потужна відеокарта, але всі об’єкти в іграх вона будує з трикутників!
Розіб’ємо наше сердечко на трикутники, намагаючись максимально зберегти форми серця, при цьому використовувати мінімальну кількість трикутників. У цьому завданні потрібно знати міру і пам’ятати: “Чим більше трикутників – Тим красивіше виглядає об’єкт, і ДОВШЕ його обробляє комп’ютер “. Відразу хочу Вас заспокоїти, при створенні дуже складних об’єктів складаються з сотень або тисяч трикутників, вручну вам їх розбивати не доведеться, для цього є спеціалізовані програми 3DMax, Maya та ін
Ось що вийшло у мене




Вийшло 7 трикутників. Кожен трикутник має крім координат 3х вершин ще й параметр перетворення і колір вершини, тому створимо структуру, яка буде визначати всі характеристики вершин:

struct CUSTOMVERTEX / / формат вершин
{
FLOAT x, y, z, rhw;
DWORD color;
};

За допомогою рядка:

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW/D3DFVF_DIFFUSE)

описується формат змісту вершин в окремому потоці даних. Тут застосовується гнучкий формат вершин – FVF (Flexible Vertex Format). Всі перераховані елементи збігаються з оголошеними в структурі. D3DFVF_DIFFUSE – Вказує на те, що застосовується колірна складова з розсіяним кольором.
Всю роботу по підготовці буфера будемо робити в окремій функції:

bool InitBufferVertex(void);

Всі вершини будуть зберігатися в буфері вершин. При заповненні буфера даними його необхідно попередньо заблокувати, після заповнення даними – розблокувати.
Визначаємо покажчик на буфер вершин:

LPDIRECT3DVERTEXBUFFER9 pBufferVertex=NULL;

І введемо координати всіх вершин у форматі структури:

 








































































































координати (Х, Y, Z)

параметр перетворення

колір

перший

170, 80, 0

1

0x00ff0000

210, 60, 0

1

0x00ff0000

250, 80, 0

1

0x00ff0000

друга

170, 80, 0

1

0x00ff0000

250, 80, 0

1

0x00ff0000

275, 130, 0

1

0x00ff0000

третя

170, 80, 0

1

0x00ff0000

275, 130, 0

1

0x00ff0000

150, 130, 0

1

0x00ff0000

четвертий

300, 80, 0

1

0x00ff0000

340, 60, 0

1

0x00ff0000

380, 80, 0

1

0x00ff0000

п’ятому

300, 80, 0

1

0x00ff0000

380, 80, 0

1

0x00ff0000

275, 130, 0

1

0x00ff0000

шостий

275, 130, 0

1

0x00ff0000

380, 80, 0

1

0x00ff0000

400, 130, 0

1

0x00ff0000

сьомий

150, 130, 0

1

0x00ff0000

400, 130, 0

1

0x00ff0000

275, 360, 0

1

0x00ff0000


Створюємо буфер вершин:

CreateVertexBuffer(21*sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &pBufferVertex, NULL)

вказуємо розмір, формат і передаємо покажчик, де буде зберігатися інформація.
Як я говорив вище, перед записом даних у буфер його необхідно заблокувати, а тільки після цього копіювати дані:

if(FAILED(pBufferVertex->Lock(0, sizeof(stVertex), (void**)&pBV, 0)))
return(false);
memcpy(pBV, stVertex, sizeof(stVertex)); pBufferVertex-> Unlock (); / / розблокувати буфер для подальшої роботи

Рендеринг об’єкта


Виведення всіх об’єктів сцени на екран відбувається у функції рендеринга між рядками

	pDirectDevice->BeginScene();
pDirectDevice->EndScene();

Заповнимо цей проміжок.
Зазначимо, які дані пересилати в потік даних пристрою, також вказуємо розмір даних, що визначає одну вершину:

SetStreamSource(0, pBufferVertex, 0, sizeof(CUSTOMVERTEX)); SetFVF (D3DFVF_CUSTOMVERTEX); / / задаємо формат вершин

Виводимо об’єкт, для цього використовуємо функцію виведення примітивів (примітив – будь-яка геометрична фігура).
Передаємо в якості параметрів такі значення:

DrawPrimitive (D3DPT_TRIANGLELIST, / / ​​що малювати 0, / / ​​індекс першої вершини 7 / / кількість виведених об’єктів
);

Готово! (лістинг програми heart.cpp)
На екрані результат: сердечко.


Примітка: При написанні статті я навмисне опустив детальний опис функцій, що б не навантажувати непотрібної поки інформацією. Повний опис використаних функцій можна знайти в додатку до статті або інших джерелах, наприклад, MSDN.


 

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*