DirectX Graphics - начнем снова
VB Edition
Часть 6 - Загружаем объекты
[Предыдущая часть]
[Следующая часть] [Приложения
к этой части]
В прошлой части мы познакомились с текстурами, теперь же мы будем знакомиться
с объектами.
Во всех предыдущих учебниках сцены состояли из одного треугольника или цилиндра,
созданного с помощью тех же треугольников. В принципе, применяя специально разработанные
формулы, из треугольников можно слепить гладкие абстрактные объекты, очень часто
появляющиеся во всевозможных интро и демках, но что делать если ваша цель совершенно
конкретна: нарисовать некий геометрический объект, например куб.
Конечно можно прямо в программе сделать массив вершин для 12 треугольников
и создать при помощи кучи строчек куб. А если надо построить более сложный объект,
я уже не говорю про каких-либо персонажей, то количество строчек становится
просто устрашающим. И каждый раз компилировать в принципе не несущие никакой
полезной нагрузки строки совершенно неблагоразумно.
Очевидно, что надо придумать собственный формат файла объекта, чтобы в любое
время мы могли загрузить заранее рассчитанные координаты в буфер вершин. Самый
простой формат может выглядет так:
идентификатор;
количество вершин;
Вершина_x_y_z;
Используя стандартные методы работы с текстовым файлом, мы сможем с легкостью
заполнить соответствующий буфер вершин, да еще и создать класс, в который помимо
этого буфера можно поместить переменную под идентификатор, а если копнуть глубже,
то и про текстуру и вообще про все, что душа пожелает. Таким образом и создаются
всевозможные форматы, в которых потом храняся модели игроков для Quake и иже
с ними.
Однако в этом учебнике мы не будет рассматривать создание собственного формата
(по крайней мере пока), а вместо этого, мы будем учиться использовать уже существующий.
Я говорю о формате для 3D-моделей, разработанном в Microsoft специально для
использования в Direct3D. Я говорю о формате .X
Подробное описание формата вы найдете в SDK Documentations. Кстати, он довольно
не плох и оптимально подходит для первоначальных целей обучения. В формате содержатся
координаты вершин, информация о материалах, используемых текстурах и даже анимации.
Создавать .x-файлы можно хоть в блокноте, но обычно это все же делают в каком-либо
редакторе моеделей с экспортом в .3ds и последующей конвертацией в .x при помощи
этой утилиты.
Учебник по всему этому процессу выйдет на La
Vision скорее всего отдельной статьей.
В этой части мы загрузим объект из уже подготовленного .x-файла, натянем на
него текстуру и заставим вращаться. Заодно, кстати, сделаем так, чтобы наша
программа работала в полноэкранном режиме. И объект и текстуру можно скачать
тут вместе
с готовым проектом.
Ну что ж, приступим. Создайте новый проект и добавьте в него необходимую ссылку
на DirectX 8 Type Library...
Вы можете так же модифицировать код из предыдущих уроков, так как в этом уроке
изменится буквально пара процедур. Я же приведу полный код программы. В начале
как всегда стандартные объявления.
Option Explicit
Dim dx As New DirectX8
Dim d3d As Direct3D8
Dim d3dx As New D3DX8
Dim d3dDevice As Direct3DDevice8
Dim Mesh As D3DXMesh
Dim MeshMaterials() As D3DMATERIAL8
Dim MeshTextures() As Direct3DTexture8
Dim NumMaterials As Long
Ну с D3DXMesh все ясно, должен ведь загруженный объект где-то в памяти храниться.
А вот следующие объявления требуют немного более подробных объяснений. D3DMATERIAL8
и Direct3DTexture8 - это указатели на хранилища для материалов и текстур, которые
будет использовать загруженный объект. Дело в том, что D3DX сам позаботится
о создании необходимых буферов вершин и даже распихает в них координаты из файла,
но вот материалы и текстуры, объявленные в файле, остаются на нашей совести.
И это даже хорошо, так как мы имеем возможность использовать несколько различных
текстур и материалов для одного и того же объекта!
Dim Running As Boolean
Private Const pi = 3.141592
Private Sub Form_KeyPress(KeyAscii As Integer)
Running = False
End Sub
Private Sub Form_Load()
Me.Show
Running = True
InitD3D
InitGeometry
Do While Running
Render
Loop
End
End Sub
Private Sub InitD3D()
Dim DispMode As D3DDISPLAYMODE
Dim d3dpp As D3DPRESENT_PARAMETERS
Set d3d = dx.Direct3DCreate
Call d3d.GetAdapterDisplayMode(D3DADAPTER_DEFAULT, DispMode)
Следующие строчки изменятся для того, чтобы программа работала в полном экране.
d3dpp.Windowed = False
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC
d3dpp.BackBufferFormat = DispMode.Format
d3dpp.BackBufferWidth = 640
d3dpp.BackBufferHeight = 480
d3dpp.BackBufferCount = 1
d3dpp.EnableAutoDepthStencil = True
d3dpp.AutoDepthStencilFormat = D3DFMT_D16
Далее все стандартно. Обратите внимание, что мы используем Z-буфер и вещественный
цвет.
Set d3dDevice = d3d.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Me.hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, d3dpp)
Call d3dDevice.SetRenderState(D3DRS_AMBIENT, &HFFFFFFFF)
Call d3dDevice.SetRenderState(D3DRS_ZENABLE, 1)
End Sub
Далее идет процедура, которая будет загружать объект и нужные ему текстуры.
В это месте обычно появляется надпись "Loading..." :)
Private Sub InitGeometry()
Dim D3DXMtrlBuffer As D3DXBuffer
Буфер материалов - это такая временная структура, куда загружается вся информация
о материалах и текстурах прямо из файла. Далее вы и сами все поймете - читайте
комментарии!
Dim TexName As String, I As Long
Set Mesh = d3dx.LoadMeshFromX(App.Path & "\tiger.x", D3DXMESH_SYSTEMMEM,
d3dDevice, _
Nothing, D3DXMtrlBuffer, NumMaterials)
If Mesh Is Nothing Then
MsgBox "Объект не загружен." & vbCrLf & "Проверьте
правильность пути", vbCritical, "Ошибка"
Running = False
Exit Sub
End If
ReDim MeshMaterials(NumMaterials)
ReDim MeshTextures(NumMaterials)
For I = 0 To NumMaterials - 1
d3dx.BufferGetMaterial D3DXMtrlBuffer, I, MeshMaterials(I)
MeshMaterials(I).Ambient = MeshMaterials(I).diffuse
TexName = d3dx.BufferGetTextureName(D3DXMtrlBuffer, I)
If TexName <> "" Then
Set MeshTextures(I) = d3dx.CreateTextureFromFile(d3dDevice, App.Path &
"\" & TexName)
End If
Next I
У нас получились массивы материалов и текстур, которые мы сможем потом использовать
для рендеринга.
Set D3DXMtrlBuffer = Nothing
End Sub
В процедуре задания матриц, зададим вращение всго мира вокруг своей оси.
Private Sub SetupMatrices()
Dim MatWorld As D3DMATRIX
Dim MatView As D3DMATRIX
Dim MatProjection As D3DMATRIX
Call D3DXMatrixRotationAxis(MatWorld, vec3(0, 1, 0), Timer / 4)
Call d3dDevice.SetTransform(D3DTS_WORLD, MatWorld)
Call D3DXMatrixLookAtLH(MatView, vec3(0, 3, -5), vec3(0, 0, 0), vec3(0, 1,
0))
Call d3dDevice.SetTransform(D3DTS_VIEW, MatView)
Call D3DXMatrixPerspectiveFovLH(MatProjection, pi / 4, 1, 1, 1000)
Call d3dDevice.SetTransform(D3DTS_PROJECTION, MatProjection)
End Sub
Наконец, последняя процедура - рендеринг.
Private Sub Render()
Dim I As Long
DoEvents
If d3dDevice Is Nothing Then Exit Sub
Call d3dDevice.Clear(0, ByVal 0, D3DCLEAR_TARGET Or D3DCLEAR_ZBUFFER, &HFF,
1, 0)
SetupMatrices
Call d3dDevice.BeginScene
Объект может состоять из нескольких составляющих, у каждой из которых может
быть своя текстура и свой материал. Для этого мы и маялись с созданием массивов
текстур, это нам и поможет легко вывести объект на экран:
For I = 0 To NumMaterials - 1
d3dDevice.SetMaterial MeshMaterials(I)
d3dDevice.SetTexture 0, MeshTextures(I)
Mesh.DrawSubset (I)
Next I
Call d3dDevice.EndScene
Call d3dDevice.Present(ByVal 0, ByVal 0, 0, ByVal 0)
End Sub
Все! Компилируем и смотрим на тигренка. Когда надоест жмем ESC.
Приложение: Готовый
проект (48k)
Приятного программирования: Anti
[Вверх]
|