ГЛАВА 6. Введение в Direct3D
Главным плюсом версии семь DirectX является наличие в ней выделенного интерфейса для работы с графикой 2D (DirectDraw) и относительно высокоуровнего интерфейса для работы с графикой 3D (Direct3DRM). Поэтому не спишите расставаться с DirectX семь, особенно если вам нужна только графика 2D и устраивает старая видео карта с хорошим качеством 2D. Версия DirectX восемь объединила 3D и 2D графику в одном флаконе. Теперь составляющая, отвечающая за всю графику называется DirectX Graphics, она включает библиотеку Direct3DX, содержащую большое количество сервисных функций и структур, что несколько облегчает программирования графики 3D.
В программировании трехмерной графики вопросы связанные с изменением геометрии, света или других параметров сцены являются самыми сложными. Руководство на русском языке по созданию простого графического движка Андре Ламота имеет в толщину порядка шести с половиной сантиметра. При этом используется язык С без всяких там MFC и ATL, по сути не используется даже Direct3D, а написание графического движка начинается с максимально быстрого вывода одной точки на экран монитора через DirectDraw, потом алгоритм Брезенхама, создание трехмерной системы координат на плоском мониторе, вывод треугольников на конвейер, а это только самое начало. Тут и проходит грань между разработчиками на VB и VC++, которую мы уже обсуждали при рассмотрении битовой графики. На VC++ создаются графические движки, а на VB они используются. Библиотека Direct3D создает всю необходимую инфраструктуру за вас. Трехмерная графика основана на треугольниках, а двухмерная на основе линий. Увеличивая число линий в 2D и треугольников в3D можно получить сложные криволинейные поверхности (Рис.
1)
Рис. 1
Непосредственную работа с треугольниками в седьмой версии DirectX осуществлял интерфейс Direct3D Immediate Mode. Работать с интерфейсом Direct3D Immediate Mode по сравнению с высокоуровневым Direct3D Retained Mode было тяжело, это и обусловило появление Direct3D восемь. Работать стало сложнее чем с Direct3D Retained Mode, но проще чем с Direct3D Immediate Mode, а самое главное появился легкий доступ к треугольнику. Треугольники группируются в буфер и выводятся в контейнере визуализации. Несмотря на поддержку файлов формата X (запихнул в него всю сцену и все) работа на уровне треугольников необходима для моделирования объектов, изменяющих геометрическую конфигурацию во времени.
Инициализация DirectX8 для работы с трехмерной графикой требует ряда поэтапных стандартных действий. Создайте проект Standard EXE(см. проект папка N13/). В этом примере создается простейшее приложение DirectX8, естественно это будет треугольник. Треугольник будет трехмерным, то есть у него будет координата Z. Подключите к проекту библиотеку типов DirectX:
Project/References/DirectX8 for VB Type Library(Рис. 2)
Рис. 2
Введите в раздел General после Option Explicit следующий код:
Option Explicit
Dim g_DX As New DirectX8
Dim g_D3D As Direct3D8
Dim g_D3DDevice As Direct3DDevice8
Dim g_VB As Direct3DVertexBuffer8
Private Type CUSTOMVERTEX
postion As D3DVECTOR
normal As D3DVECTOR
End Type
Const D3DFVF_CUSTOMVERTEX = (D3DFVF_XYZ Or D3DFVF_NORMAL)
Dim Alfa As Single
Dim Proverka As Single
В переменной g_DX хранится ссылка на “верхний” объект – собственно на всю библиотеку DirectX8. Объектная переменная D3D нужна для получения доступа к сервисам предоставляемым интерфейсом Direct3D8, а в переменной g_D3Ddevice будет хранится ссылка на интерфейс Direct3DDevice8. Интерфейс Direct3DDevice8 рабочая лошадка, которая выводит в окно графику, созданную графическим адаптером, установленным в системе. Трехмерная графика основана на размещении в пространстве (трехмерной системе координат) треугольников. Для описания одной из трех вершин треугольника вводится структура CUSTOMVERTEX. Структура состоит из двух структур D3DVECTOR, которые в свою очередь состоят из координат x, y и z. Первая структура postion - это координаты вершины треугольника, а вторая структура normal - это нормаль к плоскости в которой лежит треугольник. Нормаль нужна для правильного расчета освещения (в данном примере нормали не используются, см. пример ниже). Размещенные в пространстве треугольники превратятся в трехмерную фигуру если их разместить в буфере, ссылка на который будет храниться в переменной Direct3DVertexBuffer8. Определяя на уровне формы константу Const D3DFVF_CUSTOMVERTEX = (D3DFVF_XYZ Or D3DFVF_NORMAL), мы сигнализируем DirectX о том, что каждая вершина треугольника имеет координату X,Y,Z и имеет в этой точке нормаль к плоскости в которой лежит треугольник (Рис.
3).
Рис. 3
Вообще структура CUSTOMVERTEX может иметь и больше членов, а константа D3DFVF_CUSTOMVERTEX принимать и такие значения:
(D3DFVF_XYZ Or D3DFVF_DIFFUSE);
(D3DFVF_XYZRHW Or D3DFVF_DIFFUSE);
(D3DFVF_XYZ Or D3DFVF_NORMAL).
Private Type CUSTOMVERTEX
x As Single
y As Single
z As Single
rhw As Single
color As Long
tu As Single
tv As Single
End Type
В большинстве примеров будет использоваться структура с координатами и нормалью , а также будет показано применение членов структуры tu и tv для наложения текстуры.
Введите следующий код в событие формы Private Sub Form_Load():
Private Sub Form_Load()
Alfa = 0#
Proverka = 0#
Set g_D3D = g_DX.Direct3DCreate()
Dim mode As D3DDISPLAYMODE
g_D3D.GetAdapterDisplayMode D3DADAPTER_DEFAULT, mode
Dim d3dpp As D3DPRESENT_PARAMETERS
d3dpp.Windowed = 1
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC d3dpp.BackBufferFormat = mode.Format
d3dpp.BackBufferCount = 1
d3dpp.EnableAutoDepthStencil = 1
d3dpp.AutoDepthStencilFormat = D3DFMT_D16
Set g_D3DDevice = g_D3D.CreateDevice(
D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Picture1.hWnd, _
D3DCREATE_SOFTWARE_VERTEXPROCESSING, d3dpp)
g_D3DDevice.SetRenderState D3DRS_CULLMODE, D3DCULL_NONE
Dim Vertices(2) As CUSTOMVERTEX '0,1,2 массив из трех вершин
Vertices(0).postion.x = -0.2
Vertices(0).postion.y = 0#
Vertices(0).postion.z = 0#
Vertices(1).postion.x = 0.2
Vertices(1).postion.y = 0#
Vertices(1).postion.z = 0#
Vertices(2).postion.x = 0#
Vertices(2).postion.y = 0.2
Vertices(2).postion.z = 0.2
Dim VertexSizeInBytes As Long
VertexSizeInBytes = Len(Vertices(0))
Set g_VB = g_D3DDevice.CreateVertexBuffer(VertexSizeInBytes * 3, _
0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT)
D3DVertexBuffer8SetData g_VB, 0, VertexSizeInBytes * 3, 0, Vertices(0)
End Sub
При загрузке формы записываем в указатель g_D3D адрес на объект, отвечающий в DirectX8 за трехмерную графику - Set g_D3D = g_DX.Direct3DCreate(). Почему при установки точки после переменной g_DX появляется список с функциями. (Рис.
4).
Рис. 4
Потому что в блоке кода после Option Explicit переменная g_DX была объявлена с ключевым словом New. Был автоматически получен объект из внутрипроцесного сервера физически, расположенного в dx8vb.dll. Переменная g_DX это самый верхний указатель DirectX с помощью которого можно гуляться по всей иерархии объектов. В DirectX заложена поддержка работы не только с графикой, но и с устройствами ввода DirectInput(клавиатура, мышь, джойстик), работа со звуком DirectMusic-Sound , работа с сетью DirectPlay итп. В нашем случае мы получили доступ к графическим возможностям DirectX. Инициализировав переменную g_D3D мы спустились на один уровень иерархии ниже. Эта переменная создана с использованием команды Set, а это значит что доступ к интерфейсам, отвечающим за графику был получен через таблицу указателей на интерфейсы, благодаря этому и возможна прогулка по иерархии DirectX. Доступ к музыкальным или сетевым возможностям DirectX также осуществляется подобным образом (Рис.
5).
Рис. 5
Аппаратно в системе за вывод графики на монитор естественно отвечает видеоадаптер (которых может быть и несколько). Имея доступ к графическим интерфейсам библиотеки DirectX (через переменную g_D3D) выбираем видеоадаптер по умолчанию о чем говорит флаг D3DADAPTER_DEFAULT. Затем идет структура mode в которую входят следующие переменные:
Type D3DDISPLAYMODE
Format As CONST_D3DFORMAT
Height As Long
RefreshRate As Long
Width As Long
End Type
Наибольший интерес из полей структуры представляет константа, заполняемая из перечисления CONST_D3DFORMAT. Описать все флаги и структуры, приведенные в коде не имеет смысла, так как они прекрасно описаны в файле справки, прилагаемом к SDK. Все эти структуры, перечисления и флаги кочуют из приложения в приложение без изменений и если необходимо узнать подробности - воспользуйтесь файлом справки. Использовать файл справки очень просто. В коде, после выбора адаптера объявлена структура D3DPRESENT_PARAMETERS, а ее поля заполнены информацией
Dim d3dpp As D3DPRESENT_PARAMETERS
d3dpp.Windowed = 1
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC
d3dpp.BackBufferFormat = mode.Format
d3dpp.BackBufferCount = 1
d3dpp.EnableAutoDepthStencil = 1
d3dpp.AutoDepthStencilFormat = D3DFMT_D16
В файле справки в поле “Введите ключевое поле для поиска” – вставьте D3DPRESENT_PARAMETERS. Файл справки выдаст исчерпывающее описание этой структуры (Рис.
6).
Рис. 6
Структура состоит из шести полей, а если описывать каждое ее поле в отдельности получится книжка размером с небольшую брошюру – и это только для одной структуры. Первое поле имеет значение d3dpp.Windowed = 1. Из перевода можно понять, что приложение оконное, если бы значение было равно нулю приложение не имеет окна. Второе поле d3dpp.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC. Из перевода следует что, необходимо иметь буфер в видеопамяти в котором будет строится трехмерная сцена перед выводом на экран. Поле d3dpp.BackBufferFormat = mode.Format как следует из перевода (…”должен быть установлен, чтобы соответствовать формату текущего способа показа…”) должно соответствовать текущему видеорежиму. Этот режим устанавливается в настройках “Свойства: Экрана”. Теперь самая страшная и сокровенная тайна про DirectX. Введите в поле справки следующий текст D3DFMT_D16. Файл справки выдал:
Dim d3dpp As D3DPRESENT_PARAMETERS
d3dpp.Windowed = 1
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC
d3dpp.EnableAutoDepthStencil = 1
d3dpp.AutoDepthStencilFormat = D3DFMT_D16
By setting the EnableAutoDepthStencil member to a nonzero value (True),
you instruct Direct3D to manage depth buffers for the application.
Note that AutoDepthStencilFormat must be set to a valid depth buffer format.
The D3DFMT_D16 flag specifies a 16-bit depth buffer, if one is available.
The following call to the Direct3D8.CreateDevice method creates a device
that then creates a depth buffer.
Set d3dDevice = g_D3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, _
D3DCREATE_SOFTWARE_VERTEXPROCESSING, d3dpp)
If d3dDevice Is Nothing Then Exit Function
Это практически один в один блок кода из вводного примера который отвечает за подготовку поверхностей для вывода графики. Тайна программирования DirectX заключается в том, что, описание большинства структур и определений кочует из приложения в приложение. Определение их пред основной работой (собственно чем мы сейчас и занимаемся) называют созданием каркаса приложения. Проще говоря не запоминайте все подряд, а когда понадобится читайте файл справки.
Для вывода графики нам нужно назначить (создать) устройство способное выводить трехмерную графику в обычное окно Windows. Создаем устройство с помощью команды Set и получаем указатель для “прогулки” еще на один уровень ниже: Set g_D3DDevice = g_D3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,Picture1.hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, d3dpp). Это уровень который непосредственно выводит в наше окно графику. Поставьте после переменной g_D3Ddevice точку и посмотрите на методы этого уровня иерархии. Названия говорят сами за себя – это уже непосредственная работа по выводу с помощью, описанного и созданного выше устройства. Теперь нам нужно определиться, что мы будем выводить.
В трехмерной графике применяют понятие Rendering на русском языке значит – представление. Функция g_D3DDevice.SetRenderState устанавливает в каком виде представлены треугольники. Первый член этой функции указывает о наличии у треугольника двух сторон. Это нужно для определения передней и задней стороны. В реальной жизни вы можете зайти за спину объекта. Для графики на плоском экране программа должна знать когда вы смотрите на фронтальную, а когда на тыльную часть и надо ли отображать обе части во время представления (Rendering) треугольника. Комбинация флагов D3DRS_CULLMODE и D3DCULL_NONE указывает на наличие у треугольника двух сторон и их надо отображать. Повторюсь, что в фирменном файле справки SDK для VisualBasic и VisualC++ описанию возможных комбинаций флагов из функции SetRenderState отведено место размером с небольшую книжку размером страниц двадцать. В моей книге описание этой функции из каркаса приложения больше меняться не будет. Я стараюсь дать примеры реальных программных задач в области представления технологических процессов, которые можно воплотить на самом легком языке программирования, вместо машинального описания фирменной документации. Кстати если вы посмотрите файлы справок для VB и VC++ флаги, структуры и переменные совпадут процентов на 80/90%. К примеру функция g_D3DDevice.SetRenderState на VB выглядит так - g_D3DDevice.SetRenderState D3DRS_CULLMODE, D3DCULL_NONE, а если писали бы на VC++ так – g_D3Ddevic->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);. Когда вы пишите каркас приложения DirectX на любом языке, вы являетесь клиентом технологии COM, которая предоставляет доступ к своим интерфейсам. Язык VisualBasic главным образом создавался для того, что бы быть самым лучшим клиентом на платформе Windows. Среда VB отлично подходит для профессий где кроме программирования надо владеть еще какими то профессиональными знаниями. Главное назначение языка VC++ писать серверные приложения (конечно VC++ клиентом тоже является), графические библиотеки и вообще создавать инфраструктуру.
Когда программа знает, как отображать треугольник надо указать его расположение в пространстве. Заполним массив Dim Vertices(2) As CUSTOMVERTEX, состоящий из трех вершин, координатами. Передадим его в качестве параметра функции CreateVertexBuffer. Параметрами этой функции являются размер одной структуры в байтах умноженной на суммарное число вершин . Так как структура CUSTOMVERTEX состоит из двух структур типа D3DVECTOR, а те в свою очередь состоят из трех координат типа Single (размером по четыре байта) размер сцены будет семьдесят два байта (тип Double = 4; тип D3DVECTOR = 4 * 3; тип CUSTOMVERTEX = 12 * 2; три вершины = 24 * 3). Остальные параметры этой функции бут кочевать из приложения в приложение без изменений. Будет меняться только размер структуры и число вершин. Заметьте, что мы создали буфер вершин (состоящий пока из одного треугольника) с ключевым словом Set, так что при желании можно спустится еще на уровень иерархии ниже. Фиксирует буфер в памяти функция D3DVertexBuffer8SetData. К стати только в этой последней строчке вы не найдете прямого аналога с кодом из начального примера из SDK для VC++, в котором вместо этой функции (D3DVertexBuffer8SetData предназначена только для VB) вызывается блок Lock/Unlosk. На этом подготовительная работа в событии формы Load завершена.
Переходим к функции Render. Первой вызывается функция g_D3DDevice.Clear – название говорит само за себя “Устройство.Очистка”. Трехмерная сцена (треугольники) очищается при каждом вызове этой функции. Это нужно делать при каждом изменении геометрии иначе старые изменения будут наслаиваться на новые . Флаги D3DCLEAR_TARGET Or D3DCLEAR_ZBUFFER сигнализируют о том, что очищаются поверхности имеющие глубину. Комбинация &HFFFFFFFF представляет цвет задника в формате RGBA (красный, зеленый, синий, прозрачный). Каждый цвет имеет максимальное значение 255 = FF. В данном случае белый, так как смешивая максимальные значения трех основных цветов получим белый, хотите черный укажите вместо шестнадцатеричных пятнашек нули. Если хотите менять цвет - меняйте значения в этом диапазоне. Следующие за цветом значение лежит в диапазоне от 0,0 до 1,0. Всегда ставьте единицу - это глубина цветного задника. Между вызовами g_D3DDevice.BeginScene и g_D3DDevice.EndScene в функции Render, описываются элементы которые могут изменится - в основном геометрия, материал и освещение. Займемся материалом из которого состоит треугольник. Следующий блок кода полностью описывает и присоединяет к сцене цвет (правильнее сказать материал) треугольника:
Dim col As D3DCOLORVALUE
With col: .r = 1: .g = 0.5: .b = 0: .a = 0: End With
Dim mtrl As D3DMATERIAL8
mtrl.Ambient = col
g_D3DDevice.SetMaterial mtrl
g_D3DDevice.SetRenderState D3DRS_AMBIENT, &HFFFFFFFF
Структура D3DCOLORVALUE, так же имеет значение RGBA (только ее значения записаны не в шестнадцатеричной, а десятичной форме) и меняет их от 0,0 до 1,0. Цвет треугольника примерно получится кирпичным. Далее объявлена структура D3DMATERIAL8. В ней мы присваиваем кирпичный цвет материалу, а после вызова функции SetMateria этом материал становится достоянием сцены. Слово AMBIENT переводится на русский язык как – окружающий. Окружающий свет с максимальным значением &HFFFFFFFF становится достоянием сцены в функции g_D3DDevice.SetRenderState. Свет в сцене не будет бликовать на поверхности треугольника , так как неописаны нормали .
Теперь перейдем к геометрии. За геометрию отвечает следующий блок из функции Render:
Dim matWorld As D3DMATRIX
D3DXMatrixRotationY matWorld, Alfa
g_D3DDevice.SetTransform D3DTS_WORLD, matWorld
Dim matView As D3DMATRIX
Dim vec1 As D3DVECTOR
vec1.x = 0#: vec1.y = 1: vec1.z = -2#
Dim vec2 As D3DVECTOR
vec2.x = 0#: vec2.y = 0#: vec2.z = 0#
Dim vec3 As D3DVECTOR
vec3.x = 0#: vec3.y = 1#: vec3.z = 0#
D3DXMatrixLookAtLH matView, vec1, vec2, vec3
g_D3DDevice.SetTransform D3DTS_VIEW, matView
Dim matProj As D3DMATRIX
D3DXMatrixPerspectiveFovLH matProj, 3.1415 / 4, 1, 1, 1000
g_D3DDevice.SetTransform D3DTS_PROJECTION, matProj
Перед описанием кода представим трехмерное пространство в воображении (Рис. 7).
Рис. 7
Координаты треугольника (из массива вершин Dim Vertices(2) As CUSTOMVERTEX) имеют значение:
X = -0.2;Y = 0; Z= 0:
X = 0.2;Y = 0; Z= 0:
X = 0;Y = 0.2; Z= 0.2.
Эти координаты называются – координаты трехмерного мира. Центр мира находится в координате X = 0;Y = 0; Z= 0. Бывает, что миров в программе нужно представить несколько. Предположим вы пишите компьютерную игру где главный мир это планета. Координаты космического корабля задаются относительно планеты. В космическом корабле сидят космонавты их координаты задаются от центра корабля, а не от планеты (принцип матрешки). Изменились координаты самого большого “мира”, относительно него изменятся и координаты других “миров” поменьше, но то что творится внутри маленьких ”миров” будет происходить только внутри них. В нашем случае только один мир и в нем один треугольник. Переменная для хранения координат мира находится в матрице Dim matWorld As D3DMATRIX (представьте матрицу как “черный ящик” умеющий правильно хранить положение объектов). Земля наш главный мир который вращается вокруг своей оси, а мы летаем вокруг на управляемом космическом корабле. Корабль летает куда хочет, одновременно земля вращается. Значит картина мира меняется и мы смотрим на нее с разных углов зрения. Нужна еще одна матрица просмотра, которая будет определять наш угол зрения. Переменная для хранения координат точки просмотра находится в матрице Dim matView As D3DMATRIX. Все координаты в трехмерном мире задаются векторами – представляйте вектор как структуру состоящую из трех координат X, Y и Z. Координаты точки просмотра относительно центра мира задаются вектором vec1:
Dim vec1 As D3DVECTOR
vec1.x = 0#: vec1.y = 1: vec1.z = -2#
Направление взгляда определяется вектором vec2 (смотрим в центр мира) :
Dim vec2 As D3DVECTOR
vec2.x = 0#: vec2.y = 0#: vec2.z = 0#
Ориентация в пространстве вектором vec3 :
Dim vec3 As D3DVECTOR
vec3.x = 0#: vec3.y = 1#: vec3.z = 0#
Ориентация в пространстве в DirectX задается в левой системе координат при которой координата Y смотрит вверх, координата X увеличивается в право, координата Z в направлении от точки зрения. Если изменить значения векторов на vec3.x = 1#: vec3.y = 0#: vec3.z = 0#, то треугольник повернется на девяносто градусов, а если vec3.x = 1#: vec3.y = 1#: vec3.z = 0#, то на сорок пять.
Панорамным зрением возможно обладают только насекомые. Угол зрения, смотрящего на трехмерную сцену ограничен его оптическим аппаратом. У разных существ он разный. Представляя трехмерную графику на плоском пространстве окна вывода удобно представить, что мы смотрим через видеокамеру. В сцене видны только те объекты которые попадут в ее поле зрения. (Рис.
8).
Рис. 8
Матрица для проекции трехмерного мира на экран монитора находится в переменной Dim matProj As D3DMATRIX.
Найдите в блоке кода, отвечающем за геометрию функции:
D3DXMatrixRotationY matWorld, Alfa
D3DXMatrixLookAtLH matView, vec1, vec2, vec3
D3DXMatrixPerspectiveFovLH matProj, 3.1415 / 4, 1, 1, 100
Это глобальные функции вспомогательной библиотеки Direct3DX. В первом случае после выхода из функции матрица мира изменит координата мира на угол Alfa. Во втором случае изменение коснется не мира а положения смотрящего на этот мир. В третьем случае укажем как смотреть (под каким углом) на наш мир. В функции которая указывает как смотреть первый параметр это угол (450), второй отношение ширины и высоты (см. размеры элемента Picture1 из примера), третий и четвертый расстояние до ближней и дальней плоскостей отсечения сцены (задается произвольно). В сцене буду отображаться только объекты координаты которых попадут между этих плоскостей. После каждой из трех функций библиотеки Direct3DX сразу идет функция g_D3DDevice.SetTransform с соответствующим флагами:
D3DTS_WORLD, D3DTS_VIEW, D3DTS_PROJECTION. Эта функция относится не к глобальной библиотеки Direct3DX, а только к нашей трехмерной сцене. Понятно, что трансформации, проделанные с матрицами должны изменять картину трехмерного “мира”. Осталось только вывести построенное в буфере изображение в окно программы.
В завершающем блоке кода представлены, следующие функции:
g_D3DDevice.SetStreamSource, g_D3DDevice.SetVertexShader, g_D3DDevice.DrawPrimitive. Эти функции связывают вершины треугольника с конвейером вывода. Первой функции передается в качестве параметров указатель на буфер вершин и размер единичной структуры, представляющей буфер. В последней функции параметр ноль говорит, что вывод начнется с вершины под индексом ноль. Последний параметр указывает на число треугольников. Завершают функцию Render функции EndScene и Present. Последняя функция Present – презентует содержимое буфера с видеопамятью в окне программы. Ее параметры в файле справки в основном описывают прямоугольные области. и в нашем случае не указываются.
Запустив приложение на выполнение нажмите на кнопку. Трехмерный мир начнет вращаться. В данном случае вращается “мир”. Камера через которую мы смотрим на него неподвижна (но она тоже может перемещаться). Изменяя в событии Click переменную Alfa:
Private Sub Command1_Click()
Alfa = Alfa + 0.1
Render
End Sub
При каждом новом вызове функции Render происходит обновление матрицы мира, так как переменная Alfa зашита в функцию D3DXMatrixRotationY. Теперь функцию Render можно вставлять в любой обработчик событий, например в Paint. Если эту функцию привязать к прерыванию таймера треугольник будет вращаться постоянно.
При установке SDK DdirectX 8 вы получаете шесть примеров программирования (находятся в DX80SDK/samples/multimedia/vbsamples/direct3d/tutorials). Содержание первых четырех должно быть вам полностью понятно, если вы проработали пример, приведенный выше. Шестой пример относится к загрузке файла формата X, который будет рассмотрен ниже. Пятый примере показывает как наложить текстуру на трехмерный объект. Для первичного знакомства с методикой наложения текстур этот пример не самый легкий, поэтому в проекте из папки N13/ приводится упрощенная версия. Для наложения текстуры выберем плоскость. Плоскость можно построить из двух треугольников (Рис.
9).
Рис. 9
Вершина каждого треугольника описывается, как и раньше в структуре CUSTOMVERTEX. В структуре появились две переменные tu и tv, так же изменилась константа D3DFVF_CUSTOMVERTEX – появился флаг D3DFVF_TEX1. Переменные tu и tv это координаты, которые обычно принимают значения от 0 до 1. За единицу принимается размер плоскости, при этом tu – горизонтальная составляющая, а tv вертикальная. Текстура ляжет на плоскость один к одному если значения tu и tv равны единице, если вместо единицы подставить 4 текстура размножиться, а 0.5 сожмется. Понятно, что координаты tv и tu это отношение размеров плоскости и текстуры
(Рис. 10).
Рис. 10
Текстура храниться в файле banana.bmp. Для работы с текстурами в разделе Option Explicit объявлена интерфейсная переменная Dim g_Texture As Direct3DTexture8, инкапсулирующая в DirectX представление битовой графики. Инициализация переменной производится в функции Set g_Texture = g_D3DX.CreateTextureFromFile(g_D3DDevice, App.Path + "\banana.bmp"). Присоединение к трехмерной сцене в функции g_D3DDevice.SetTexture 0, g_Texture. Обратите внимание в этой трехмерной сцене уже два треугольника. Количество треугольников изменилось, изменились и параметры функций (по сравнению с примером описанным выше). Теперь в функции CreateVertexBuffer первый параметр равен выражению 20 * 4 (четыре структуры размером по двадцать байт). Хотя в двух треугольниках шесть вершин мы описали только четыре, так как в функции DrawPrimitive указан флаг D3DPT_TRIANGLESTRIP. Если указать флаг D3DPT_TRIANGLELIST надо описывать все шесть вершин. Все вершины надо указывать если нужен доступ к каждому треугольнику. Третий параметр функции указывает на число примитивов (треугольников) в трехмерной сцене.
Эта глава имела своей целью подготовить вас к восприятию несколько более сложных примеров, представленных в следующей главе. Примеры из следующей главы демонстрируют прикладное использование технологии DirectX для отображения технологических процессов.