Дата публикации статьи: 10.06.2006 11:33

ГЛАВА 5. Пример работы с Direct3D Retained Mode в среде Visual Basic

    По мимо вывода битовой графики седьмая версия DirectX обладает интерфейсами, реализующими работу с трехмерными объектами. Несмотря на то, что Visual Basic поддерживает версию DirectX восемь, седьмая версия может оказаться очень полезной. Работать с трехмерной графикой в седьмой версией значительно легче, так как при использовании интерфейса Direct3D Retained Mode можно обойтись без матриц и нет нужды работать на уровне треугольников из которых состоит трехмерный объект (см. часть III).
Все примеры из этой главы построены на основе файлов *.X и реализованы через интерфейс Direct3D Retained Mode(далее D3DRM).
    Примечание. Низкоуровневый интерфейс Direct3D Immediate Mode рассматриваться не будет.
Инициализация D3DRM (как и DirectDraw) требует ряда поэтапных стандартных действий, описанных в приведенной ниже простой программе (см. проект папка N11/).
1.Создайте проект Standard EXE. Добавьте в форму элемент PictureBox. Подключите к проекту библиотеку типов DirectX(как и для DirectDraw - Project/References/DirectX7 for VB Type Library).
2.Добавте к приложению модуль – Project/AddModule. В разделе модуля General, после Option Explicit введите следующий код:

Option Explicit
Public DxVer7 As New DirectX7 'Самый главный
Public DDrawVer7 As DirectDraw7
''''''''''''''''''''''''''''''''''
Public D3DRMVer3 As Direct3DRM3  'Для основной работы и -.X
Public UstrRender As Direct3DRMDevice3    'Устр Рендеринга
Public Viewport As Direct3DRMViewport2  '
Public BuilderKubik As Direct3DRMMeshBuilder3
Public BuilderSar As Direct3DRMMeshBuilder3
Public Scene As Direct3DRMFrame3
Public Camera As Direct3DRMFrame3
Public Kubik As Direct3DRMFrame3
Public Sar As Direct3DRMFrame3
Public SvetFrm As Direct3DRMFrame3
Public Svet As Direct3DRMLight
''''''''''''''''''''''''''''''''''
Public OtsetsenieWndCliper As DirectDrawClipper

Public Sub IniVseObjectDX7(VBPict As PictureBox)
Set DDrawVer7 = DxVer7.DirectDrawCreate("") 'Первый всегда DDraw
Set D3DRMVer3 = DxVer7.Direct3DRMCreate 'Создаем 3DRM
'''''''''''''''''''''''''''''''''''''''''''''''''''''
Set OtsetsenieWndCliper = DDrawVer7.CreateClipper(0) 'Так как приложение оконное
With VBPict
OtsetsenieWndCliper.SetHWnd .hWnd
'''''''''''''''''''''''''''''''''''''''''''''''''''''
Set UstrRender = D3DRMVer3.CreateDeviceFromClipper(OtsetsenieWndCliper, _
"", .ScaleWidth, .ScaleHeight)
UstrRender.SetQuality D3DRMRENDER_GOURAUD
Set Scene = D3DRMVer3.CreateFrame(Nothing) 'Родитель для камеры
Scene.AddLight D3DRMVer3.CreateLight(D3DRMLIGHT_AMBIENT, _
DxVer7.CreateColorRGB(0, 1, 0)) 'Создали свет для Scene
Set Camera = D3DRMVer3.CreateFrame(Scene) 'Прекрепляем камеру к порту просмотра
Set Kubik = D3DRMVer3.CreateFrame(Scene)
Set Sar = D3DRMVer3.CreateFrame(Scene)
''''''''''Svet
Set SvetFrm = D3DRMVer3.CreateFrame(Scene)
Set Svet = D3DRMVer3.CreateLightRGB(D3DRMLIGHT_DIRECTIONAL, 4, 0, 0)
SvetFrm.AddLight Svet
Set Viewport = D3DRMVer3.CreateViewport(UstrRender, _
Camera, 0, 0, .ScaleWidth, .ScaleHeight)   'Создали порт просмотра
End With
End Sub

Public Sub CreateMyObject()
Set BuilderKubik = D3DRMVer3.CreateMeshBuilder
BuilderKubik.LoadFromFile App.Path & "\n2.x", 0, D3DRMLOAD_FROMFILE, Nothing, Nothing
Kubik.AddVisual BuilderKubik
Set BuilderSar = D3DRMVer3.CreateMeshBuilder
BuilderSar.LoadFromFile App.Path & "\sar.x", 0, D3DRMLOAD_FROMFILE, Nothing, Nothing
BuilderSar.ScaleMesh 0.4, 0.4, 0.4
Sar.AddVisual BuilderSar
End Sub

    Инициализация объектов происходит в функции которой передается по ссылке окно вывода - Public Sub IniVseObjectDX7(VBPict As PictureBox). Обратите внимание на присутствии интерфейса DirectDraw который нужен для создания отсечения. После создания интерфейса DirectDraw создается интерфейс D3DRM. Он необходим для порождения таких типов как: Direct3DRMDevice3 – устройство рендеринга; Direct3DRMViewport2 – порт просмотра(просмотр привязан к фрейму камеры); Direct3DRMMeshBuilder3 – “строитель” фрейма в сцене; Direct3DRMFrame3 –объект обладающий координатами(возможно формой и размерами или другими характеристиками); Direct3DRMLight – объект для освещения фреймов имеющих форму. Все фреймы при создании прикрепляются к “главному” фрейму сцены методом - D3DRMVer3.CreateFrame(Scene). Загрузка файлов *,X происходит в процедуре Public Sub CreateMyObject(). Обратите внимание, что при загрузке файлов возможно масштабирование с помощью функции BuilderSar.ScaleMesh 0.4, 0.4, 0.4, принадлежащей объекту типа Direct3DRMMeshBuilder3. Из двух файлов *.X загружаются кубик – файл n2.x и шарик – файл sar.x(оба файла должны находится в одной папке с проектом) 3.Для формы и ее событий введите следующий код :

Option Explicit
Dim FlagPaint As Long
Dim Xp As Long
Dim Zp As Long
Dim Yp As Long

Private Sub Form_Load()
Zp = -20
Xp = -5
Yp = -5
Dim Flag As Boolean
Flag = True
FlagPaint = 0
Show 'Принудительный показ
DoEvents
ModD3D.IniVseObjectDX7 Picture1
FlagPaint = 1
'''Инициализация закончена'''
''''''Создание объектов''''''
ModD3D.CreateMyObject
''Настройка
Kubik.SetColor &HFFFF6060
Kubik.SetMaterialMode D3DRMMATERIAL_FROMFRAME
Do While Flag = True
DoEvents
D3DRMVer3.Tick 1
Camera.SetPosition Scene, 0, 0, -40
Kubik.SetPosition Scene, Xp, Yp, Zp
Loop
'''''''''''''''''''''''''''''
End Sub

Private Sub Picture1_KeyDown(KeyCode As Integer, Shift As Integer)
Dim TempVector As D3DVECTOR
If KeyCode = 38 Then 'Вверх
Zp = Zp + 1
ElseIf KeyCode = 40 Then
Zp = Zp - 1
ElseIf KeyCode = 39 Then
Xp = Xp + 1
ElseIf KeyCode = 37 Then
Xp = Xp - 1
ElseIf KeyCode = 89 Then
Yp = Yp + 1
ElseIf KeyCode = 72 Then
Yp = Yp - 1
End If
End Sub

Private Sub Form_Paint()
If FlagPaint = 1 Then ModD3D.UstrRender.HandlePaint Picture1.hDC
End Sub

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Set BuilderKubik = Nothing
Set Viewport = Nothing
Set Kubik = Nothing
Set Svet = Nothing
Set SvetFrm = Nothing
Set Camera = Nothing
Set Scene = Nothing
Set UstrRender = Nothing
Set OtsetsenieWndCliper = Nothing
Set D3DRMVer3 = Nothing
Set DDrawVer7 = Nothing
End
End Sub

    В разделе формы General, после Option Explicit представлены три переменные для хранения координат кубика. В событии Private Sub Form_Load() вызываются две функции из модуля. Для инициализации объектов D3DRM вызывается ModD3D.IniVseObjectDX7 Picture1, а для загрузки файлов *.X вызывается ModD3D.CreateMyObject. Фрейму кубика назначается красный цвет в строках:
Kubik.SetColor &HFFFF6060
Kubik.SetMaterialMode D3DRMMATERIAL_FROMFRAME
    После функций вступает в работу “бесконечный” цикл. В за один проход “бесконечный” цикл выполняет рендеринг сцены с помощью метода D3DRMVer3.Tick 1. Завершается цикл установкой фреймов камеры и кубика. Камере назначен порт просмотра - через него мы обозреваем сцену. Камера статична, а координаты кубика изменяются кнопками клавиатуры в событии Private Sub Picture1_KeyDown(KeyCode As Integer, Shift As Integer). Кнопки со стрелками перемещают кубик по горизонтали, а кнопки “Y” и “H” по вертикале.
На рисунке 1 можно видеть приложение в работе. Рисунок 2 показывает, что произойдет если исключить событие Private Sub Form_Paint().


Рис. 1


Рис. 2

 

    В заключении приведем пример использования интерфейса D3DRM на базе которого можно построить трехмерное представление технического объекта, например воображаемый отсек подводной лодки (см. проект папка N12/). Приложение в работе представлено на рисунке 3.


Рис. 3

    Перемещение по трехмерной сцене производится с помощью кнопок клавиатуры. Просмотр осуществляется через фрейм камеры, но в данном случае камера неподвижна. Фреймы применяются и для источников освещения. Качеством отображения можно управлять меняя значения “Уд” и “Хор”(более сглаженные углы).
В сцене предусмотрены активные элементы – это четыре клапана. При нажатии на клапан он окрасится в красный цвет, а в текстовой панели отобразится его номер(Рис. 4).


Рис. 4

    Важным отличием от предыдущего примера является наличие текстур. На текстурах можно нарисовать элементы, которые придадут больше реализма трехмерной сцене. В данном случае текстуры нанесены на воображаемый пульт управления и переборку между отсеками. Самое сложное правильно растянуть текстуры по объекту. Для текстур используется тип - Direct3DRMTexture3, а для натяжения на объект тип - Direct3DRMWrap. Создать текстуру можно из файла или поверхности DirectDraw(в данном приложении текстура создана из поверхности). Код по созданию и наложению текстуры может иметь вид:

Set PultTexture = D3DRMVer3.CreateTextureFromSurface(OsnovaBMP1)
'Set PultTexture = D3DRMVer3.LoadTexture("pult1.bmp")
Set RastiaskaPult = D3DRMVer3.CreateWrap(D3DRMWRAP_FLAT, Nothing, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0.09, _
0,1 / 26, 1 / 20)
RastiaskaPult.Apply BuilderPult
BuilderPult.SetTexture PultTexture

    Обратите внимание на флаг D3DRMWRAP_FLAT в функции CreateWrap – это значит, что текстура наносится на плоскую поверхность. Можно наносить текстуры на цилиндрические и сферические поверхности. Сложность трехмерной сцены, количество в ней активных элементов и текстур, ограничена только аппаратными возможностями вашего компьютера.