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

Часть 5 - Шкурный вопрос

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

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

Так как рассусоливать здесь больше нечего, переходим сразу к практике.
Создаем новый проект и приаттачиваем к нему Reference DirectX8 for VB

В новом файле кода формы начнем вколачивать программу.

Option Explicit

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

У нас появился новый класс D3DX8 - набор полезных функций Direct3D, фактически переделанный RM. Но зато он теперь полностью интегрирован в основной D3D. Так же мы ввели объект текстуры.

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

'Структура, определяющая наш формат вершины (aka FVF)
Private Type CUSTOMVERTEX
Position As D3DVECTOR '3D-позиция вершины
color As Long 'Цвет
tu As Single 'Координаты текстуры
tv As Single
End Type

Из формата вершины мы выкинули нормали, так как не будем возиться со светом, а зато добавили новую фичу: координаты текстуры. Что это такое, вам сейчас станет понятно.

Координаты текстуры преследуют одну цель - определить растяжение текстуры по поверхности геометрии. Координаты могут меняться от (0.0, 0.0) - левый верхний угол картинки с текстурой, до (1.0, 1.0) - правый нижний. Таким образом, мы прикрепляем определенный участок шкуры к определенной вершине. Не трудно догадаться, что этот способ позволяет растягивать текстуру как угодно.

Пойдем дальше:

'Флаговое описание нашего FVF
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

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

В InitD3D добавилась только одна строчка. Сейчас мы до нее дойдем:

'Инициализация 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_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)

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

'Включить Z-буфер
Call d3dDevice.SetRenderState(D3DRS_ZENABLE, 1)

Вот тут - мы выключили освещение в D3D

'Выключить освещение 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

'Используем инструменты D3DX для того, чтобы создать объект текстуры из файла
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;
}

'Заполнить буфер вершин. Мы устанавливаем координаты tu и tv,
'которые находятся в промежутке от 0.0 до 0.1

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

'Очистить задний буфер и z-буфер в синий цвет
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 'Конец рендеринга

'Показать задний буфер человечеству (aka Flip)
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>

 


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

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


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








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