Если в предыдущих программах нам надо было создать треугольник или циллиндр мы создавали его из трёхмерных вершин по определённому алгоритму. Теперь представим, что Вы пишите 3d игру, для которой нужен, например, трёхмерный самолёт. Он будет сосотоять из десятков и сотен трёхмерных вершин и написать в программе порцедуру, по вершине создающей его, будет практически невозможно. Как же поступить? В таких случаях используются файлы, в котрых сохраняются сложные трёхмерные объекты. Существует множество форматов таких файлов и, соответственно, редакторов, с ними работающих. В одном из таких редакторов, например, 3d Studio Max, Вы создаёте некий 3d объект, сохраняете его в файле *.3ds, конвертируете его с помощью специальной утилиты в файл *.x, который затем загружаете в своей программе с помощью методов класса D3DX8 . Формат файлов .x Microsoft создала специально для Direct3d. Более подробное описание формата .x Вы можете найти в DX SDK.
Утилиту, конвертирующую файлы .3ds в файлы формата .x Вы можете скачать с этого сайта.
Программа, которую мы напишем в этой части довольно сильно отличается от программы из предыдущей части. В коде модуля формы будут следующие объявления:
Dim g_DX As New DirectX8
Dim g_D3DX As New D3DX8
Dim g_D3D As Direct3D8
Dim g_D3DDevice As Direct3DDevice8
Dim g_Mesh As D3DXMesh ' Наш 3d объект
Dim g_MeshMaterials() As D3DMATERIAL8 ' Данные о материалах 3d объекта
Dim g_MeshTextures() As Direct3DTexture8 ' Текстуры 3d объекта
Dim g_NumMaterials As Long
Const g_pi = 3.1415
Как видите здесь нет объявления буффера трёхмерных вершин и пользовательского типа трёхмерных вершин, потому что мы их не используем. Зато здесь есть объявления 3d объекта g_Mesh; массивов g_MeshMaterials и g_MeshTextures, в которых будет содержаться информация, нужная при рендеринге 3d объекта; а также переменной g_NumMaterials, в которой будет сохраняться количество материалов 3d объекта.
Сильные изменения произошли также и в функции InitGeometry, код котрой приведён ниже:
Function InitGeometry() As Boolean
On Local Error Resume Next
Dim MtrlBuffer As D3DXBuffer
Dim i As Long
Set g_Mesh = g_D3DX.LoadMeshFromX(App.Path + "\Tiger.x", D3DXMESH_MANAGED, _
g_D3DDevice, Nothing, MtrlBuffer, g_NumMaterials)
If g_Mesh Is Nothing Then Exit Function
ReDim g_MeshMaterials(g_NumMaterials)
ReDim g_MeshTextures(g_NumMaterials)
Dim strTexName As String
For i = 0 To g_NumMaterials - 1
' Копирование материала из буффера MtrlBuffer в массив g_MeshMaterials
g_D3DX.BufferGetMaterial MtrlBuffer, i, g_MeshMaterials(i)
' Установка окружающего цвета материала (D3DX этого не делает)
g_MeshMaterials(i).Ambient = g_MeshMaterials(i).diffuse
' Создание текстуры
strTexName =
g_D3DX.BufferGetTextureName(MtrlBuffer, i) If
strTexName <> "" Then
Set g_MeshTextures(i) = g_D3DX.CreateTextureFromFile(g_D3DDevice, App.Path + "\" + strTexName)
End If
Next
Set MtrlBuffer = Nothing
InitGeometry = True
End Function
Загрузка 3d объекта, или по-английски Mesh, происходит с помощью метода LoadMeshFromX объекта g_D3DX. Первый параметр метода - имя .x файла для загрузки; второй - комбинация флагов, задающих опции создания 3d объекта; третий параметр - устройство, использующуеся для рендеринга этого 3d объекта; четвёртый параметр - буффер, заполняемый данными о соседях поверхостей в 3d объекте (нами не используется); пятый параметр - буффер, заполняемый данными о текстурах и материалах 3d объекта; шестой параметр - количество частей 3d объекта (каждая часть - это набор примитивов, для которых используется один и тот же материал и одна и та же текстура).
В этом примере используется файл tiger.x, в котром сохранена модель тигра, а также файл tiger.jpg с тектурой для этой модели. Вы же можете использовать любой другой .x файл.
Далее в цикле для каждой части 3d объекта происходит копирование материала из буффера MtrlBuffer в массив g_MeshMaterials с помощью метода BufferGetMaterial объекта g_D3DX. Кроме того происходит заполнение массива g_MeshTextures текстурами, созданными из файлов, имена которых извлекаются из буффера MtrlBuffer с помощью метода BufferGetTextureName.
В конце функции InitGeometry происходит уничтожение объекта MtrlBuffer, так как он нам больше не потребуется.
Теперь, когда 3d объект загружен вместе с материалами и тектурами осталось его только отрендерить. Это и делает изменившаяся процедура Render.
Public Sub Render()
Dim i As Long
g_D3DDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET Or D3DCLEAR_ZBUFFER, &HFF&, 1, 0
' Начало сцены
g_D3DDevice.BeginScene
SetupMatrices
' 3d объекты разделены на части (subsets).
' У каждой части свой материал и текстура.
' Рендеринг 3d объекта по частям в цикле:
For i = 0 To g_NumMaterials - 1
' Установка материала и текстуры для каждой части
g_D3DDevice.SetMaterial g_MeshMaterials(i)
g_D3DDevice.SetTexture 0, g_MeshTextures(i)
' Прорисовка части 3d объекта
g_Mesh.DrawSubset i
Next
' Конец сцены
g_D3DDevice.EndScene
g_D3DDevice.Present ByVal 0, ByVal 0, 0, ByVal 0
End Sub
Думаю, всё должно быть ясно, так как процедура прокомментирована.
В процедуру SetupMatrices внесём следующие изменения:
1. Чтобы объекты сцены вращались вокруг оси OY замените строку, вращавшую объекты сцены вокруг вектора (1;1;1) , этой строкой:
D3DXMatrixRotationY matWorld, Timer / 4
2. Чтобы камера была ближе к 3d объекту замените код, изменявший матрицу обзора, этим кодом:
D3DXMatrixLookAtLH matView, vec3(0, 3, -3), _
vec3(0, 0, 0), _
vec3(0, 1, 0)
Осталось только заменить код процедуры CleanUp, которая теперь также очищает массивы g_MeshTextures и g_MeshMaterials, новым кодом:
Sub Cleanup()
Erase g_MeshTextures
Erase g_MeshMaterials
Set g_Mesh = Nothing
Set g_D3DDevice = Nothing
Set g_D3D = Nothing
End Sub
Программа готова! Запустив её на выполнение, Вы можете видеть вращающегося тигра, загруженного из файла tiger.x.
Вы можете скачать архив RAR с готовым проектом (21 Кб). В архиве есть также файлы tiger.x и tiger.jpg.
Цикл статей "Учебник DirectX Graphics" закончен, но раздел "Статьи" сайта DirectX & Visual Basic будет обновляться и в дальнейшем.