DirectX Graphics - начнем снова
VB Edition
Часть 5 - Шкурный вопрос
[Предыдущая часть]
[Следующая часть] [Приложения
к этой части]
Пятая часть учебника целиком и полностью посвящена тому, без чего 3D графика
была бы голая и никому не нужная. Я конечно же имею в виду текстуры.
В этой части мы переделаем прошлый пример с цилиндром, выкинем из него освещение,
но зато добавим код, загружающий и отображающий текстуры.
Так как рассусоливать здесь больше нечего, переходим сразу к практике.
Создаем новый проект и приаттачиваем к нему Reference DirectX8 for VB
В новом файле кода формы начнем вколачивать программу.
Option Explicit
Dim dx As New DirectX8
Dim d3d As Direct3D8
Dim d3dx As New D3DX8
Dim d3dDevice As Direct3DDevice8
Dim pVB As Direct3DVertexBuffer8
Dim pTexture As Direct3DTexture8
У нас появился новый класс D3DX8 - набор полезных функций Direct3D, фактически
переделанный RM. Но зато он теперь полностью интегрирован в основной D3D. Так
же мы ввели объект текстуры.
Dim Running As Boolean
Private Type CUSTOMVERTEX
Position As D3DVECTOR
color As Long
tu As Single
tv As Single
End Type
Из формата вершины мы выкинули нормали, так как не будем возиться со светом,
а зато добавили новую фичу: координаты текстуры. Что это такое, вам сейчас станет
понятно.
Координаты текстуры преследуют одну цель - определить растяжение текстуры по
поверхности геометрии. Координаты могут меняться от (0.0, 0.0) - левый верхний
угол картинки с текстурой, до (1.0, 1.0) - правый нижний. Таким образом, мы
прикрепляем определенный участок шкуры к определенной вершине.
Не трудно догадаться, что этот способ позволяет растягивать текстуру как угодно.
Пойдем дальше:
Private Const D3DFVF_CUSTOMVERTEX = (D3DFVF_XYZ Or D3DFVF_DIFFUSE Or D3DFVF_TEX1)
Private Const pi = 3.141592
Дальше опять нет ничего нового.
Private Sub Form_KeyPress(KeyAscii As Integer)
Running = False
End Sub
Private Sub Form_Load()
Me.Show
InitD3D
InitGeometry
Running = True
Do While Running
Render
Loop
End
End Sub
В InitD3D добавилась только одна строчка. Сейчас мы до нее дойдем:
Private Sub InitD3D()
Dim DispMode As D3DDISPLAYMODE
Dim d3dpp As D3DPRESENT_PARAMETERS
Set d3d = dx.Direct3DCreate
Call d3d.GetAdapterDisplayMode(D3DADAPTER_DEFAULT, DispMode)
d3dpp.Windowed = True
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC
d3dpp.BackBufferFormat = DispMode.Format
d3dpp.BackBufferCount = 1
d3dpp.EnableAutoDepthStencil = True
d3dpp.AutoDepthStencilFormat = D3DFMT_D16
Set d3dDevice = d3d.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Me.hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, d3dpp)
Call d3dDevice.SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE)
Call d3dDevice.SetRenderState(D3DRS_ZENABLE, 1)
Вот тут - мы выключили освещение в D3D
d3dDevice.SetRenderState D3DRS_LIGHTING, 0
End Sub
В Cleanup добавилась операция уничтожения объекта текстуры
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Set pTexture = Nothing
Set pVB = Nothing
Set d3dDevice = Nothing
Set d3d = Nothing
End Sub
Function vec3(x As Single, y As Single, z As Single) As D3DVECTOR
vec3.x = x
vec3.y = y
vec3.z = z
End Function
Большие изменения произошли в InitGeometry
Private Sub InitGeometry()
Dim Vertices(100) As CUSTOMVERTEX
Dim I As Integer, Theta As Single
On Error Resume Next
Set pTexture = d3dx.CreateTextureFromFile(d3dDevice, App.Path + "\texture.bmp")
If pTexture Is Nothing Then
MsgBox "Текстура не найдена"
End
End If
Текстура загружается в память с помощью всего лишь одной процедуры. Здорово,
правда? А помните нудный процесс загрузки битмапа на поверхность в DirectDraw?!
Далее повторяется процесс создания цилиндра, но теперь вместо нормалей, мы
просчитываем и устанавливаем координаты текстуры.
if( FAILED( g_pd3dDevice->CreateVertexBuffer( 50*2*sizeof(CUSTOMVERTEX),
0, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &g_pVB ) ) )
{
return E_FAIL;
}
For I = 0 To 49
Theta = (2 * pi * I) / (50 - 1)
Vertices(2 * I + 0).Position = vec3(Sin(Theta), -1, Cos(Theta))
Vertices(2 * I + 0).color = &HFFFFFFFF
Vertices(2 * I + 0).tu = I / (50 - 1)
Vertices(2 * I + 0).tv = 1
Vertices(2 * I + 1).Position = vec3(Sin(Theta), 1, Cos(Theta))
Vertices(2 * I + 1).color = &HFF808080
Vertices(2 * I + 1).tu = I / (50 - 1)
Vertices(2 * I + 1).tv = 0
Next I
Set pVB = d3dDevice.CreateVertexBuffer(50 * 2 * Len(Vertices(0)), 0, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT)
Call D3DVertexBuffer8SetData(pVB, 0, Len(Vertices(0)) * 100, 0, Vertices(0))
End Sub
В принципе, это не так уж сложно. Я бы посоветовал вам вместо цилиндра избразить
нечто попроще, например прямоугольник, и попробовать установить кооринаты текстуры
"вручную"
Следующая функция осталась без изменений
Private Sub SetupMatrices()
Dim MatWorld As D3DMATRIX
Dim MatView As D3DMATRIX
Dim MatProjection As D3DMATRIX
Call D3DXMatrixRotationAxis(MatWorld, vec3(1, 1, 1), 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 v As CUSTOMVERTEX
Dim sizeOfVertex As Long
DoEvents
sizeOfVertex = Len(v)
If d3dDevice Is Nothing Then Exit Sub
Call d3dDevice.Clear(0, ByVal 0, D3DCLEAR_TARGET Or D3DCLEAR_ZBUFFER, &HFF,
1, 0)
Call d3dDevice.BeginScene 'Начало рендеринга
Теперь мы должны выбрать текстуру, с помощью которой устройство рендеринга
будет рисовать геометрию, вплоть до следующего переопределения SetTexture
d3dDevice.SetTexture 0, pTexture
Первый параметр - это номер текстуры. На этом самом моменте, мы вплотную сталкиваемся
с возможностями мультитекстурирования в DirectX. Текстура под номером 0 - это
базовая текстура, которая должна быть всегда. Если вы собираетесь нанести несколько
текстур одновременно на одну поверхность, то бишь провести смешивание (blending).
DirectX поддерживает смешивание восьми текстур одновременно, то есть значение
первого параметра будет меняться от 0 до 7. Однако реальная цифра зависит от
возможностей графической карты, и вам следует проверить ее перед использованием
смешения с помощью GetDeviceCaps.
Впрочем, у нас с вами тут рассматривается простейший случай и никаким мультитекстурированием
голову забивать мы не будем.
Итак, после того как мы выбрали текстуру, мы должны задать параметры того,
как она будет накладываться. Для того же мультитекстурирования это будет процент
смешивания и так далее. Для простого случая, необходимо указать следующие свойства,
полностью являющиеся "по умолчанию".
d3dDevice.SetTextureStageState 0, D3DTSS_COLOROP, D3DTOP_MODULATE
d3dDevice.SetTextureStageState 0, D3DTSS_COLORARG1, D3DTA_TEXTURE
d3dDevice.SetTextureStageState 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE
d3dDevice.SetTextureStageState 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE
Во всех подробностях об этих параметрах вы можете почитать в документации к
SDK. На самом деле, как я уже сказал, здесь выставлены значения по умолчанию.
Далее идет стандартный рендеринг потока вершин.
SetupMatrices
Call d3dDevice.SetStreamSource(0, pVB, sizeOfVertex)
Call d3dDevice.SetVertexShader(D3DFVF_CUSTOMVERTEX)
Call d3dDevice.DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, (4 * 25) - 2)
Call d3dDevice.EndScene
Call d3dDevice.Present(ByVal 0, ByVal 0, 0, ByVal 0)
End Sub
Ну вот, собственно, и все! Откомпилируйте программу. После этого положите в
папку с exe-файлом какую-нить картинку размером 2^xx например 256x256 и с именем
texture.bmp Когда сие будет выполнено, можно запускать программу.
Теперь, скажу пару строк тем, кого ну никак не устраивают текстуры в формате
bmp. В DirectX вы не можете загружать напрямую ни jpg, ни gif, ни даже tga.
Для того, чтобы использовать текстуры собственного формата, вам необходимо писать
собственный загрузчик. Вся соль в том, чтобы в конечном итоге получить в объекте
Direct3DTexture8 полноценную текстуру. А как уж она туда попадет: с помощью
встроенных функций или методом хитрых преобразований - тема совсем других бесед.
Увидимся в следующей части!
Приложение: Готовый
проект (48k)
Приятного программирования: Anti
[Вверх]
Posted: 31.03.2k1
Author: Anti
<anti_loop@mail.ru>
|