9 января 2010 в 13:08
Уроки Direct3D - 1.3. Плоские фигуры
Пора, наконец, нарисовать что-то существенное. В Direct3D, за редким исключением, вывод графики основан на выводе примитивов – серий треугольников. Треугольники выбраны потому, что на них можно разбить любой многоугольник или, как его еще называют, полигон.
Для однозначного задания положения треугольника в пространстве достаточно задать координаты трех его вершин. В Direct3D существует понятие «вертекс» – особая структура, содержащая координаты и некоторые другие характеристики точки (например, вершины треугольника) в пространстве.
Определение
Вертекс – особая структура, содержащая координаты и некоторые другие характеристики точки в пространстве.
Возьмем за основу наш предыдущий проект. Добавим такую структуру:
Private Type vFormat PosX As Single PosY As Single PosZ As Single RHW As Single Color As Long End Type
Эта структура задает формат вертекса, то есть перечень характеристик точки, описанных в вертексе. Поля PosX, PosY и PosZ соответствуют трем координатам точки в 3D пространстве. Поле RHW задает особую характеристику, значение которой мы рассмотрим чуть позже, и поле Color задает цвет точки. Кроме структуры вертекса мы должны также задать способ его обработки, то есть мы указываем Direct3D, каким образом нужно обрабатывать вертекс. Для этого служат специальные константы, заданные в Enum CONST_D3DFVFFLAGS, их имена начинаются с «D3DFVF_»:
Private Const vFlag = D3DFVF_XYZRHW Or D3DFVF_DIFFUSE
Такая комбинация констант «поясняет» Direct3D структуру нашего вертекса.
Добавим новые общие переменные:
Dim vBuffer As Direct3DVertexBuffer8 Dim Vert(0 To 2) As vFormat Dim vSize As Long
Массив Vert() для трех вертексов, переменная vSize содержащая размер вертекса в байтах и vBuffer, переменная нового для нас типа Direct3DVertexBuffer8. Напишем специальную процедуру для задания значений вертексов:
Private Sub InitGeometry() vSize = Len(Vert(0)) Set vBuffer = d3dDevice.CreateVertexBuffer(3 * vSize, 0, vFlag, D3DPOOL_DEFAULT) Vert(0).PosX = 10 Vert(0).PosY = 10 Vert(0).PosZ = 0 Vert(0).RHW = 1 Vert(0).Color = &HFF Vert(1).PosX = 210 Vert(1).PosY = 10 Vert(1).PosZ = 0 Vert(1).RHW = 1 Vert(1).Color = &HFF00& Vert(2).PosX = 10 Vert(2).PosY = 210 Vert(2).PosZ = 0 Vert(2).RHW = 1 Vert(2).Color = &HFF0000 D3DVertexBuffer8SetData vBuffer, 0, vSize * 3, 0, Vert(0) End Sub
Используя d3dDevice.CreateVertexBuffer инициализируем объектную переменную vBuffer, не забываем сразу добавить в процедуру ClearAll строку для ее уничтожения:
Set vBuffer = Nothing
Функция D3DVertexBuffer8SetData переносит данные в вертексный буфер, откуда и будет происходить вывод вертексов при растеризации.
И, наконец, внесем изменения в процедуру Render:
Private Sub Render() d3dDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET, &H346666, 1, 0 d3dDevice.BeginScene d3dDevice.SetStreamSource 0, vBuffer, vSize d3dDevice.SetVertexShader vFlag d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, 0, 1 d3dDevice.EndScene d3dDevice.Present ByVal 0, ByVal 0, 0, ByVal 0 End Sub
Весь вывод графики в Direct3D должен начинаться с d3dDevice.BeginScene и заканчиваться d3dDevice.EndScene. С помощью d3dDevice.SetStreamSource 0, vBuffer, vSize указываем нашему устройству рендера (d3dDevice) на вертексный буфер, а d3dDevice.SetVertexShader vFlag конкретизирует формат его содержимого.
И само рисование - d3dDevice.DrawPrimitive D3DPT_TRIANGLELIST, 0, 1. Это указание вывести список треугольников (TRIANGLELIST), начинающийся с адреса 0 и содержащий 1 треугольник.
Жмем <F5> – и видим градиентно раскрашенный треугольник.
Для пояснения смысла поля RHW в структуре vFormat проведем эксперимент. В процедуре InitGeometry заменим строку Vert(2).RHW = 1 на Vert(2).RHW = 3. В результате цвет от красной вершины (№ 2) как бы расползается более сильно, чем от остальных вершин. Если немного напрячь воображение, можно представить, что красная вершина находится к нам ближе. Использование поля RHW в формате вертекса означает использование «приведенного» формата, в такой формат Direct3D неявно преобразует геометрию из других форматов перед выводом.
Проведем еще один эксперимент. Добавим процедуру обработки события MouseMove для формы:
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single) If Button = 1 Then Vert(0).PosX = X Vert(0).PosY = Y D3DVertexBuffer8SetData vBuffer, 0, vSize, 0, Vert(0) End If End Sub
Теперь мы можем перетаскивать синюю вершину мышкой. Заметьте, что при перемещении вершины за противоположную сторону треугольника сам треугольник пропадает. Дело в том, что Direct3D отображает по умолчанию только лицевую сторону треугольника. При использовании TRIANGLELIST лицевой считается та сторона, на которой вершины расположены по часовой стрелке. Это сделано с целью повышения быстродействия при выводе объемных объектов. Они, как правило, представлены своей поверхностью, и их внутренняя сторона не бывает видна ни при каких обстоятельствах. Если нам необходимо отобразить двухстороннюю фигуру, эту оптимизацию необходимо запретить. Добавим в D3DInit такую строку:
d3dDevice.SetRenderState D3DRS_CULLMODE, D3DCULL_NONE
Теперь наш треугольник виден с двух сторон.
комментарии отсутствуют
авторизуйтесь