До сих пор для того, чтобы создать какой-либо геометрический объект, мы выполняли некоторые стандартные действия, занимающие достаточно объемный код.

В первую очередь мы создавали флаговое описание вертекса, новый тип, соответствующий формату вертекса и сам вертексный буфер. Для более сложных моделей так же создавался индексный буфер.

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

А, между прочим, создавать, отображать и уничтожать геометрические объекты можно одной командой. В Direct3D существует класс D3DXMesh, предназначенный для хранения таких объектов. Объект (экземпляр класса) можно загружать из файла, так же некоторые простые формы, такие как куб, сфера и т. п. можно генерировать.

Создадим новый проект, как обычно на основе предыдущего. Модуль modMain перепишем полностью. В разделе Declarations оставим только две общих переменных Running и FPS и добавим один объект класса D3DXMesh:

код на языке vb
 
Public Running As Boolean
Public FPS As Long
Dim Mesh As D3DXMesh
 

Добавим процедуры для инициализации света и материала:

код на языке vb
 
Private Sub InitLight()
Dim Light As D3DLIGHT8
  Light.Type = D3DLIGHT_DIRECTIONAL
  Light.Direction = vec3(-1, -1, 1)
  Light.diffuse.r = 1
  Light.diffuse.g = 1
  Light.diffuse.b = 1
  d3dDevice.SetLight 0, Light
  d3dDevice.LightEnable 0, 1
End Sub
 
Private Sub InitMaterial()
Dim Mat As D3DMATERIAL8
  Mat.diffuse.r = 1
  Mat.diffuse.g = 1
  Mat.diffuse.b = 1
  Mat.Ambient = Mat.diffuse
  d3dDevice.SetMaterial Mat
End Sub
 

Уже привычная инициализация трансформаций:

код на языке vb
 
Private Sub InitMatrix()
Dim Mtrx As D3DMATRIX
  D3DXMatrixIdentity Mtrx
  d3dDevice.SetTransform D3DTS_WORLD, Mtrx
 
  D3DXMatrixPerspectiveFovLH Mtrx, Pi / 4, frmD3D.ScaleHeight / frmD3D.ScaleWidth, 0.5, 10
  d3dDevice.SetTransform D3DTS_PROJECTION, Mtrx
 
  D3DXMatrixLookAtLH Mtrx, vec3(0, 1, -3), vec3(0, 0, 0), vec3(0, 1, 0)
  d3dDevice.SetTransform D3DTS_VIEW, Mtrx
End Sub
 

Процедура ClearAll будет содержать только уничтожение Mesh и D3DTerminate:

код на языке vb
 
Private Sub ClearAll()
  Set Mesh = Nothing
  D3DTerminate
End Sub
 

Создадим новую процедуру InitMesh для инициализации модели, она выполняет те же функции, которые раньше выполняла процедура InitGeometry:

код на языке vb
 
Private Sub InitMesh()
  Set Mesh = d3dx.CreateBox(d3dDevice, 1, 1, 1, Nothing)
End Sub
 

В этой процедуре из одной строки генерируется Box (прямоугольный параллелепипед) с размерами «1, 1, 1», то есть куб.

В процедуре Render между BeginScene и EndScene так же будет всего одна строка:

код на языке vb
 
Private Sub Render()
  d3dDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET Or D3DCLEAR_ZBUFFER, &H346666, 1, 0
  d3dDevice.BeginScene
 
  Mesh.DrawSubset 0
 
  d3dDevice.EndScene
  d3dDevice.Present ByVal 0, ByVal 0, 0, ByVal 0
End Sub
 

И, наконец, Sub Main:

код на языке vb
 
Public Sub Main()
Dim Mtrx As D3DMATRIX
  frmD3D.Show
  QFreqIni
  D3DInit frmD3D.hWnd
  InitMatrix
  InitMesh
  InitLight
  InitMaterial
  d3dDevice.SetRenderState D3DRS_CULLMODE, D3DCULL_CCW
  d3dDevice.SetRenderState D3DRS_ZENABLE, D3DZB_TRUE
  d3dDevice.SetRenderState D3DRS_LIGHTING, 1
  Running = True
  Do While Running
    DoEvents
    D3DXMatrixRotationY Mtrx, QTime * 0.5
    d3dDevice.SetTransform D3DTS_WORLD, Mtrx
    Render
    FPS = FPS + 1
  Loop
  Unload frmD3D
  ClearAll
End Sub
 

Здесь все привычно, добавился только вызов InitMesh – инициализации модели, в нашем случае куба.
Запускаем программу и видим вращающийся куб. Модель, генерируемая D3DX, содержит в формате вертекса координаты и нормаль, поэтому мы можем наблюдать эффект освещения. Обратите внимание, команда для непосредственного отображения модели Mesh.DrawSubset имеет параметр. Дело в том, что сложные модели могут состоять из нескольких частей, называемых Subset, которые можно отображать независимо друг от друга. Это сделано для того, чтобы между отображением частей можно было поменять параметры рендеринга, например, сменить материал или текстуру. Или, представьте, что наша модель – автомобиль. Если ее колеса будут отдельными частями, их можно будет вращать, меняя трансформацию мира непосредственно перед их отображением.

Познакомимся с другими примитивными формами, которые можно генерировать средствами D3DX. Заменим единственную строку в InitMesh на такую:

код на языке vb
 
Set Mesh = d3dx.CreateSphere(d3dDevice, 0.6, 32, 32, Nothing)
 

Теперь у нас не куб, а сфера. Параметры «0.6, 32, 32» – это радиус, число «меридианов» и число «параллелей». Так же можно сгенерировать цилиндр (а мы мучались!):

код на языке vb
 
Set Mesh = d3dx.CreateCylinder(d3dDevice, 0.7, 0.7, 1, 64, 1, Nothing)
 
Тор:
 
Set Mesh = d3dx.CreateTorus(d3dDevice, 0.2, 0.7, 32, 32, Nothing)
 

И, ставшую уже классической, модель чайника:

код на языке vb
 
Set Mesh = d3dx.CreateTeapot(d3dDevice, Nothing)
 

Несколько другой синтаксис у процедуры генерации объемного текста:

код на языке vb
 
d3dx.CreateText d3dDevice, frmD3D.hDC, "Test", 0.002, 0.1, Mesh, Nothing, ByVal 0
 

Для того, чтобы это сработало, необходимо присвоить свойству Font формы frmD3D какой-нибудь шрифт, обязательно TrueType! Этим требованиям удовлетворяет, например, шрифт Courier New, но не Courier.