Direct X і Delphi

Азіз (JINX), "Королівство Дельфі"

Перед тим як приступити я хотів би зробити пару застережень. По-перше, для використання DirectX в Delphi необхідний файл із заголовками, де оголошено імена функцій DirectX API або який-небудь компонент, що дозволяє звертатися до інтерфейсу DirectX через свої методи. У момент написання цього опусу я використовую компонент DelphiX (автор – Hiroyuki Hori), що поширюється безкоштовно – http://www.ingjapan.ne.jp/hori/. (Якщо у вас є що-небудь трохи краще і Ви поділитеся зі мною – я буду дуже вдячний.)

І ще одна адреса, по якому можна завантажити компонент DelphiX: http://www.torry.ru/vcl/packs/hhdelphix.zip

По можливості я буду писати і назви методів DelphiX і назви відповідних інтерфейсів Directx API – щоб вам легше було орієнтуватися в DirectX SDK. По-друге при всьому своєму гіпертрофованому зарозумілості я не можу назвати себе експертом в області DirectX – так що не судіть занадто суворо. Я сподіваюся цей витвір хоч як то зможе допомогти роблять перші кроки в DirectX – якщо Ви крутіше мене – буду вдячний за допомогу і вказівка на помилки (яких на жаль, напевно, зробив немало (чесне слово не навмисне :-)) Застереження без номера – я пишу ці рядки в ті часи коли останньою версією DirectX є DirectX 6.

Ну що ж, приступимо, мабуть.

Як відомо, DirectX призначений в основному для програмування ігор під Windows 9x. Тим не менше можна придумати ще не мало йому застосувань (рано чи пізно настає таки ера повсюдного тривимірного користувальницького інтерфейсу). DirectX складається з наступних компонентів:

Дещо про Direct3DRM ®. (Reatined Mode)

Система координат

У Direct3D вона відповідає так званому правилом "лівої руки". Суть правила в тому, що якщо Ви розчепірити пальці лівої руки так, що вказівний палець буде спрямований до екрану, великий до стелі, а середній паралельно столу туди, де звичайно лежить мишачий килимок, то великому пальцю буде відповідати координата Y, середньому – X, вказівному Z. Говорячи коротше координата Z спрямована як б углиб екрана (я в усякому разі перебуваю за цю його сторону :-)), координата Y – вгору, координата X – вправо (всі малюнки з SDK).

Можливо Вам це здасться незвичним. А що Ви тоді скажіть на це – в DirectX кольору задаються трьома складовими R, G, B, кожна з яких – число з плаваючою крапкою в діапазоні [0-1]. Наприклад білий колір – (1,1,1), сіренький (0.5,0.5,0.5), червоний (1,0,0) ну і т.д.

Всі тривимірні об'єкти задаються у вигляді набору (mesh) багатокутників (граней – faces). Кожен багатокутник повинен бути опуклим. Взагалі-то краще всього використовувати трикутники – більш складні багатокутники все одно будуть розбиті на трикутники (на це піде настільки дорогоцінне процесорний час). Грані (faces) складаються з вершин (vertex).

Грань стає видимої якщо вона повернена так, що утворюють її вершини йдуть за годинниковою стрілкою з точки зору спостерігача. Звідси висновок – якщо Ваша грань чомусь не видно – переставте вершини так, щоб вони були за годинниковою стрілкою.

Крім того є інші об'єкти – джерела світла (пряме світло – directional light і розсіяне світло – ambient light), т.зв. камера, текстури, які можуть бути "натягнуті" на грані і прочая, прочая: Набори об'єктів становлять т.зв. frames (важко дати цьому російська назва). У Вашій програмі завжди буде хоч один головний frame, званий сцена (scene), не імющие фрейму-батька, інші фрейми належать йому або один одному.

Я не буду довго розмовляти про те, як ініціалізувати все це господарство, для Дельфі-програміста досить розмістити на формі компонент TDXDraw з бібліотеки DelphiX.

Перейдемо проте до справи. Запустіть-ка Дельфі і відкрийте мою (чесно кажучи не зовсім мою – велику частину коду написав Hiroyuki Hori – однак не будемо загострювати на цьому увагу :-)) навчальну програмку – Sample3D.

Знайдіть метод

TMainForm.DXDrawInitializeSurface.

Цей метод запускається при ініціалізації компонента TDXDraw. Зверніть увагу, що DXDraw інкапсулює D3D, D3D2, D3Ddevice, D3DDevice2, D3DRM, D3DRM2, D3DRMDevice, D3DRMDevice2, DDraw – ні що інше як відповідні інтерфейси DirectX. (Тільки в назвах інтерфейсів Microsoft замість першої літери D слово IDirect). Ініціалізація компонента дуже підходяще місце, щоб вибрати дещо які режими (що й робиться в програмці). Зверніть увагу на DXDraw.D3DRMDevice2.SetRenderMode (D3DRMRENDERMODE_BLENDEDTRANSPARENCY or D3DRMRENDERMODE_SORTEDTRANSPARENCY); – Ці два прапори встановлені ось для чого – якщо у нас два трикутника знаходяться один під іншим і обидва видно (тобто вершини у них за годинниковою) потрібно їх спершу відсортувати по координаті Z щоб зрозуміти хто кого загороджує. Включає таку сортування прапор, названий скромненько сяк, за Microsots-ки: D3DRMRENDERMODE_SORTEDTRANSPARENCY.

Однак як казав К. Прутков – дивися в корінь. Коренем ж у нас є метод

TMainForm.DXDrawInitialize(Sender: TObject);

Тут спочатку створюються два фрейми – Mesh і Light, для нашого видимого об'ектіка і для лампочки, його висвітлює.

MeshFrame.SetRotation(DXDraw.Scene, 0.0, 10.0, 0.0, 0.05);

(Перші три цифри – координати вектора обертання, останній параметр – кут полворота). Тонке (не дуже правда :-)) відмінність між методами SetRotation і AddRotation в тому, що AddRotation повертає об'єкт тільки один раз, а SetRotation – змушує його повертатися на вказаний кут при кожному наступної ітерації (with every render tick)

Потім створюється т.зв. MeshBuilder – спеціальний об'єкт, що інкапсулює методи для додавання до нього граней.

Цей об'єкт може бути завантажений з файлу (і природно збережений у файл). За традицією файли мають розширення X. (Наскільки мені извесно ця традиція виникла ще до появи серіалу X-Files :-)) У самому ж – в кінці 20 століття задавати координати кожного трикутника вручну: Можна змусить зробити це когось щось ще – а потім просто завантажити готовий файл :-). Ну а якщо серйозно в DirectX SDK входить спеціальна утиліта – conv3ds.

{Conv3ds converts 3ds models produced by Autodesk 3D Studio and other modelling packages into X Files. }

Однак створимо об'єкт вручну – ну їх ці Х-файли.

Наш об'єкт буде складатися з 4-х граней (ні одного тривимірного тіла з меншою кількістю граней я не зміг придумати). Природно кожна грань – трикутник, що має свій колір.

MeshBuilder.Scale (3, 3, 3); - Збільшуємо в три рази по всіх координатах.

Нарешті MeshFrame.AddVisual (MeshBuilder); – наш MeshBuilder готовий, приєднуємо його як візуальний об'єкт до видимого об'єкту Mesh.

DXDraw.Scene.SetSceneBackgroundRGB(0,0.7,0.7); -

Як зрозуміло з назви методу колір фону. (Бачите – я не брехав RGB-колір дійсно задається числами з плаваючою точкою :-))

Цікаві справи творяться в методі TMainForm.DXTimerTimer. (Невелика тонкість – це не звичайний таймер, а DXTimer з бібліотеки DelphiX)

DXDraw.Viewport.ForceUpdate (0, 0, DXDraw.SurfaceWidth, DXDraw.SurfaceHeight);

вказуємо область, яку потрібно оновити (не мудруючи лукаво – весь DXDraw.Surface)

DXDraw.Scene.Move(1.0);

– Застосовуємо всі тривимірні перетворення, додані методами начебто AddRotation і SetRotation до нашої сцені. (Ось де собака то порилася: 🙂 обчислення нових координат точок почнуться не відразу після методу AddRotation а тільки тут)

 DXDraw.Render - Рендер (ну як же це по російськи то? :-))
DXDraw.Flip - виводимо результат рендеринга на екран (амінь :-));

(У цьому методі поміщені також кілька рядків, які виводять на екран число кадрів в секунду і інформацію про підтримку Direct3D апаратурою або програмно – стане в нагоді при налагодженні)

Метод FormKeyDown.

Тут перевіряється код клавіші, клавіші – якщо Alt + Enter – переходимо з віконного в повноекранний режим (кльово, правда? :-)) І навпаки.

Наостанок кілька слів про DXDrawClick.

Просто виводимо FileOpenDialog – Ви можете поекспериментувати з x-файлами.

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


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

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

Ваш отзыв

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

*

*