Visual Basic - мастерская разработчика
Библиотеки

DirectX

Обзоры
DirectDraw
Direct3D
DirectX Audio
DirectPlay
DirectInput
Fido Topics
SourceCode
Tools&Libs

OpenGL

Статьи и учебники
Fido Topics
SourceCode
Tools&Libs

Архив по Glide

Движки

Обзоры
Учебники
SourceCode
Downloads

Создание игр

Ваши игры

Обзорные статьи
Учебники
Fido Topics
SourceCode
Download

Stuff

Программер-Чат

Псевдо-FTP
Disclaimer
Оффтопик

 

DirectX Graphics - начнем снова

VB Edition

Часть 3- Использование матриц

[Предыдущая часть] [Следующая часть] [Приложения к этой части]

В предыдущей части мы занимались рендерингом треугольника и даже раскрашивали его в разные цвета. Но не спешите создавать свой энжин, сначала прочитайте хотя бы эту часть :) Дело в том, что в прошлой части мы не использовали самого главного, без чего не обходится никакая современная трехмерная система - это матрицы. Только не та, которая поимела нас всех, а маленькая, 4x4. Матрицы нужны для правильного отображения геометрии в виртуальном мире. С помощью матриц мы можем вращать, передвигать и масштабировать объекты. Например, чтобы повернуть треуголник в этой части мы применим к нему матрицу вращения. После ее применения соответствующего метода, Direct3D посчитает нам новые координаты точек, в которые переместится треугольник после вращения на определенное количество градусов.

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

Создайте новый проект, подключите к нему необходимый reference и задайте форме подобающие размеры и caption

'Объявляем объекты DirectX
Dim dx As New DirectX8 'Класс DirectX8
Dim d3d As Direct3D8 'Объект Direct3D
Dim d3dDevice As Direct3DDevice8 'Объект устройства рендеринга
Dim pVB As Direct3DVertexBuffer8 'Буфер для вершин.

'Мы еще работаем?
Dim Running As Boolean

'Структура, определяющая наш формат вершины (aka FVF)
Private Type CUSTOMVERTEX
x As Single
y As Single
z As Single
Color As Long
End Type

'Флаговое описание нашего FVF
Private Const D3DFVF_CUSTOMVERTEX = (D3DFVF_XYZ Or D3DFVF_DIFFUSE)

Private Const pi = 3.141592

Здесь мы используем в структуре вершины нетрансформированные координаты. Это потому, что мы используем матрицу для трансформации 3D координат в 2D, так чтобы вы могли видеть на экране проекцию трехмерного мира.

'При нажатии на клавишу - конец программы
Private Sub Form_KeyPress(KeyAscii As Integer)
Running = False
End Sub

'При загрузке формы вызываем функцию инициализации Direct3D
Private Sub Form_Load()
Me.Show 'Показать окно
InitD3D 'Инициализировать D3D
InitVB 'Создать буфер вершин
Running = True
Do While Running 'Запустить цикл рендеринга
Render
Loop
End
End Sub

'При выходе все уничтожить
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Set pVB = Nothing
Set d3dDevice = Nothing
Set d3d = Nothing
End Sub

'Инициализация Direct3D
Private Sub InitD3D()
'Необходимые объекты и структуры
Dim DispMode As D3DDISPLAYMODE
Dim d3dpp As D3DPRESENT_PARAMETERS

'Создать объект Direct3D
Set d3d = dx.Direct3DCreate
'Получить текущий режим экрана
Call d3d.GetAdapterDisplayMode(D3DADAPTER_DEFAULT, DispMode)

'Установить параметры создаваемого устройства рендеринга
d3dpp.Windowed = True
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD
d3dpp.BackBufferFormat = DispMode.Format

'Создать устройство рендеринга
Set d3dDevice = d3d.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Me.hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, d3dpp)

'Убрать culling так, чтобы мы видели и переднюю и заднюю сторону треуголника
Call d3dDevice.SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE)

'Убрать иллюминацию, так как у нас собственный цвет вершин
Call d3dDevice.SetRenderState(D3DRS_LIGHTING, False)

End Sub

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

Теперь задаем геометрию:

Private Sub InitVB()
Dim Vertices(3) As CUSTOMVERTEX

'Указать координаты трех вершин для нашего треугольника
With Vertices(0): .x = -1: .y = -1: .z = 0: .Color = &HFFFF0000: End With
With Vertices(1): .x = 1: .y = -1: .z = 0: .Color = &HFF00FF00: End With
With Vertices(2): .x = 0: .y = 1: .z = 0: .Color = &HFFFFFFFF: End With

Как видите, теперь мы используем другие координаты - относительные виртуального трехмерного мира. Поэтому нам и нужны будет позже матрица проекции, чтобы трансформировать трехмерный мир в двухмерную проекцию на экране.

'Создать буфер под хранение информации о вершинах
Set pVB = d3dDevice.CreateVertexBuffer(3 * Len(Vertices(0)), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT)
'Скопировать информацию о вершинах в буфер
Call D3DVertexBuffer8SetData(pVB, 0, Len(Vertices(0)) * 3, 0, Vertices(0))

End Sub

Private Sub Render()
Dim v As CUSTOMVERTEX
Dim sizeOfVertex As Long

DoEvents

sizeOfVertex = Len(v)

Call d3dDevice.Clear(0, ByVal 0, D3DCLEAR_TARGET, &HFF, 1, 0) 'Очистить вьюпорт
Call d3dDevice.BeginScene 'Начало рендеринга

Перед рендерингом очередного кадра мы должны провести трансформацию нашего мира, чтобы треугольник вращался. Мы вызываем функцию SetupMatrices, которую сами же напишем чуть позже.

'Установить матрицы мира, обзора и проекции
SetupMatrices

'Выполнить рендеринг треугольника по координатам, заданным в буфере вершин
Call d3dDevice.SetStreamSource(0, pVB, sizeOfVertex)
Call d3dDevice.SetVertexShader(D3DFVF_CUSTOMVERTEX)
Call d3dDevice.DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1)

Call d3dDevice.EndScene 'Конец рендеринга

'Показать задний буфер человечеству (aka Flip)
Call d3dDevice.Present(ByVal 0, ByVal 0, 0, ByVal 0)
End Sub

Теперь, как я и обещал мы напишем функцию, в которой зададим все нужные нам матрицы:

Private Sub SetupMatrices()
Dim MatWorld As D3DMATRIX
Dim MatView As D3DMATRIX
Dim MatProjection As D3DMATRIX

'Матрице мира задаем вращение объекта вокруг оси Y
Call D3DXMatrixRotationY(MatWorld, Timer * 4)

Этой функцией мы задаем вращение вокруг оси Y на указанное количество радиан. Первый параметр - возвращаемая измененная матрица, второй параметр - угловая мера в радианах. Обратите внимание, что мы здесь привязываем ее ко времени для того чтобы треугольник вращался с одинаковой скоростью на всех компьютерах. Это важный момент, так как мы должны строго соответствовать ходу времени в отображении объектов, то есть скажем Лара Крофт должна пробегать дистанцию за одинаковое время и на P166 и на K7-1200, независимо от скорости рендеринга при этом. Мы можем отрендерить несколько кадров, когда треугольник будет все в той же позиции, но не должны рендерить новую позицию треугольника каждый очередной кадр.

Call d3dDevice.SetTransform(D3DTS_WORLD, MatWorld)

После того, как мы получили измененную матрицу, мы должны применить трансформацию, заложенную в ней к миру. Функция SetTransform делает это. D3DTS_WORLD - означает объекты виртуального мира.

'Установить матрицу обзора
Call D3DXMatrixLookAtLH(MatView, vec3(0#, 3#, -5#), vec3(0#, 0#, 0#), vec3(0#, 1#, 0#))
Call d3dDevice.SetTransform(D3DTS_VIEW, MatView)

После того, как мы установили трансформацию объектов в мире, мы должны определиться с собственным взглядом на этот мир. Здесь мы устанавливам точку обзора на мир следующим образом: Функции D3DXMatrixLookAtLH передаем результирующую матрицу, положение нашего глаза (0,3,-5), затем направление взгляда (0,0,0) - то есть смотрим в начало координат и напоследок мы указываем где у нас верх (0,1,0). Видите ли без силы всемирного тяготения очень трудно определиться, а где соьственно тут верх, поэтому нам надо указать вертикаль сего бренного мира, как ось Y.
SetTransform( D3DTS_VIEW, &matView ) применяет трансформацию обзора в соответствии с установленной матрицей.

'Установить матрицу проекции
Call D3DXMatrixPerspectiveFovLH(MatProjection, pi / 4, 1, 1, 1000)
Call d3dDevice.SetTransform(D3DTS_PROJECTION, MatProjection)
End Sub

Я уже упоминал, что для того, чтобы спроецировать трехмерный мир на плоскую поверхность монитора, надо применить специальную матрицу проекции. Окромя этой необходимости, матрица проекции позволяет задавать несколько интересных параметров. Во-первых, это угол обзора (aka FOV), применяющийся повсеместно в качестве увеличивающего фактора камеры. В данном примере он установлен в pi/4, то есть 45° Затем мы затаем aspect ratio, то есть отношение длины к высоте. Так как нам не надо ничего сплющивать или вытягивать, передаем в функцию единицу. Следующие два параметра называются ближней и дальней границей клиппинга или по русски - обрезания. Эти параметры задают границы, после которых Direct3D перестает рендерить чего либо. Это коллосально сокращает время на операцию рендеринга в больших уровнях. Соответственно, чем дальше границы, тем медленней рендеринг и тем реалистичнее картинка.

Осталась маленькая вспомогательная функция, которая будет быстро создавать нам трехмерный вектор по заданным координатам

'Вспомогательная функция для быстрого создания векторов
Function vec3(x As Single, y As Single, z As Single) As D3DVECTOR
vec3.x = x
vec3.y = y
vec3.z = z
End Function

Вот так незаметно, мы подошли к концу программы. Компилируйте проект и смотрите как треуголник вертится!

В следующей части мы добавим к нашей сцене источник освещения.

Приложение: Готовый проект (8k)

Приятного программирования: Antiloop

[Вверх]

Posted: 23.01.2k1
Autor: Antiloop
<anti_loop@mail.ru>

 


Проект
Создание Народного Учебника по OpenGL

Участвовать!
Поиск
Найдите статью или файл:


Рассылка
Новости сайта
La Vision в вашем почтовом ящике








Программирование на С++ Delphi и Паскаль
Центр демо-искусства в России