До сих пор мы работали только с плоскими фигурами DirectDraw. Сегодня мы познакомимся с Direct3D, который позволяет строить трёхмерные сцены, которые мы уже умеем делать с помощью OpenGL. Хотя сцену мы не построим, а загрузим из файла. И самое главное, наше приложение будет оконным, а не полноэкранным, как это было в прошлых статьях. Работа с оконным DirectX отличается от полноэкранного и достаточно сильно.
Рис 1. Пример формы
Сразу же приготовься и забери исходники сегодняшнего примера здесь. А теперь приступим к рассмотрению функции FormCreate.
procedure TForm1.FormCreate(Sender: TObject);
var
hr: HResult;
begin
Application.OnIdle:=IdleEvent;
hr:=Direct3DRMCreate(FDirect3D);
if hr<>D3DRM_OK then
ShowMessage('Direct3DRMCreate failed');
CreateDevice;
end;
Direct3DRMCreate - создаёт объект типа IDirect3DRM, с которым будет происходить вся сегодняшняя работа. Этот объект умеет работать с трехмерными объектами, освещением и текстурами, что и предстоит нам сегодня изучить.
Далее вызываеться процедура CreateDevice, которая иницаализирует DirectDraw:
procedure TForm1.CreateDevice;
var
hr : HResult;
Bpp : Integer;
begin
hr:=DirectDrawCreateClipper(0, FD3DClipper, nil);
if(hr<>D3DRM_OK) then
ShowMessage('DirectDrawCreateClipper failed');
FD3DClipper.SetHWnd(0, Handle);
hr:=FDirect3D.CreateDeviceFromClipper(FD3DClipper, nil, ClientWidth,
ClientHeight, FD3Device);
if(hr<>D3DRM_OK) then
ShowMessage('CreateDeviceFromClipper failed');
FD3Device.SetQuality(D3DRMRENDER_GOURAUD);
bpp:=GetDeviceCaps(Canvas.Handle, BITSPIXEL);
case (bpp) of
8: FD3Device.SetDither(false);
16:
begin
FD3Device.SetShades(32);
FDirect3D.SetDefaultTextureColors(64);
FDirect3D.SetDefaultTextureShades(32);
FD3Device.SetDither(false);
end;
24, 32:
begin
FD3Device.SetShades(256);
FDirect3D.SetDefaultTextureColors(64);
FDirect3D.SetDefaultTextureShades(256);
FD3Device.SetDither(false);
end;
end;
hr:=FDirect3D.CreateFrame(nil, FD3DScene);
if(hr<>D3DRM_OK) then
ShowMessage('CreateFrame failed');
CreateScene;
end;
Сегодняшнее приложение я сделаю оконным. Когда ты програмируешь обычными средствами Windows, то он сам следит за тем, что попадает в окно, а что нет. Если какая-то точка не попадет в область вывода, то Windows самостоятельно отсекает её. В случае работы с DirectDraw, этого не происходит. Ты сам должен следить за всем, что происходит в окне, отсекая ненужное. Но есть способ лучше, в DirectDraw есть встроенный объект, который может сделать за тебя эту рутинную работу - объект отсечения. Чтобы он начал работать, ты должен его инициализировать.
DirectDrawCreateClipper создаёт объект отсечения, который будет отсекать всё, что не попадает в область вывода. Первый параметр - должен быть 0. Второй - указатель на объект типа IDirectDrawClipper, который будет проинициализирован и использоваться для отсечения. Третий - не используется и должен быть nil.
FD3DClipper.SetHWnd - устанавливает объекту отсечения окно, за которым он будет следить и отсекать всё, что в него не попадает.
CreateDeviceFromClipper - привязывает нашему объекту сцены, который мы создали в процедуре FormCreate, объект отсечения. Первый параметр - ссылка на объект отсечения. Второй - глобальный идентификатор (можно использовать nil). Третий и четвёртый - ширина и высота окна. Последний - указатель типа IDirect3DRMDevice, который будет проинициализирован с указанными новыми возможностями.
SetQuality - устанавливает качество отображения сцены. В качестве параметра указывается константа, которая может быть:
D3DRMRENDER_GOURAUD - для отображения использовать метод какого-то Гуро.
D3DRMRENDER_FLAT - метод сглаживания.
D3DRMRENDER_WIREFRAME - рисовать линиями. Объекты получаться как из проволок.
GetDeviceCaps - это функция из WinAPI и не относится к DirectX, но я её распишу. Она возвращает текущие свойства контекста рисования. Первый параметр - указатель на контекст экрана. Второй - константа, которая указывает, какой параметр нам нужен. Мне нужно установленное с системе количество бит на пиксел. Остальные константы смотри в документации по WinAPI.
Далее, в зависимости от количества бит на пиксел, я использую разную инициализацию.
SetDither - устанавливает сглаживание. Если в качестве параметра будет true, то при рисовании будет происходить сглаживание сцены, иначе изображение получается немного грубым.
SetShades - устанавливает количество оттенков цветов.
SetDefaultTextureColors - устанавливает значение по умолчанию для количества цветов текстуры.
SetDefaultTextureShades - устанавливает значение по умолчанию для количества оттенков текстуры.
CreateFrame - создаёт новый слой для родительского. Первый параметр - указатель на родительский слой. Если он отсутствует, то инициализируется слой со значениями по умолчанию. Второй параметр - укачатель на объект типа IDirect3DRMFrame, который будет создан.
В самом конце я вызываю функцию CreateScene, которая производит дальнейшую инициализацию:
procedure TForm1.CreateScene;
var
D3DAmbientLight : IDirect3DRMLight;
D3DAmbientLightFrame : IDirect3DRMFrame;
begin
if not (LoadScene()) then
Exit;
FD3DTextureWrapType:=D3DRMWRAP_FLAT;
if not (LoadWrapTexture()) then
Exit;
FDirect3D.CreateLightRGB(D3DRMLIGHT_AMBIENT, 1, 1, 1, D3DAmbientLight);
FDirect3D.CreateFrame(FD3DScene, D3DAmbientLightFrame);
D3DAmbientLightFrame.AddLight(D3DAmbientLight);
D3DAmbientLightFrame:=nil;
D3DAmbientLight:=nil;
FDirect3D.CreateFrame(FD3DScene, FD3DCamera);
FD3DCamera.SetPosition(FD3DScene, 0, 0, -50);
FDirect3D.CreateViewport(FD3Device, FD3DCamera,0, 0,
FD3Device.GetWidth(), FD3Device.GetHeight(), FD3DViewPort);
Flat2Click(nil);
FD3DScene.SetSceneBackgroundRGB(0, 0, 1);
end;
LoadScene - моя фунция, которая загружает сцену. Эту функцию мы рассмотрим через месяц.
FD3DTextureWrapType - устанавливает тип текстуры. D3DRMWRAP_FLAT - означает, что текстура должна быть сглаженная.
LoadWrapTexture - моя процедура, которая загружает текстуру. Её мы также рассмотрим в следующий раз. Если сможешь, попробуй разобраться сам, она есть в примере.
CreateLightRGB - создаём освещение. Первый параметр - тип. D3DRMLIGHT_AMBIENT - означает, что нам нужно рассеянное освещение. Следующие три параметра - интенсивности красного, зелёного и синего, которые вместе означают цвет освещения. Последний параметр - указатель на объект типа IDirect3DRMLight, это источник света, который будет создан.
Далее мы создаём новый кадр с помощью CreateFrame. Новый кадр будет дочерним к уже созданному FD3DScene.
AddLight - добавляет источник освещения к нашей сцене.
Далее мы создаём камеру. Для этого создаём новый дочерний кадр с помощью CreateFrame и устанавливаем позицию наблюдателя SetPosition, что создаёт эффект камеры.
SetPosition - устанавливает позицию наблюдателя. Первый параметр - указатель на сцену, в которой надо установить позицию. Следующие три параметра - позиции по оси X,Y и Z.
CreateViewport - устанавливает область просмотра. Первый параметр - указатель на устройство. Второй - указатель на камеру. Следующие четыре параметра - левая, правая позиции и ширина и высота области просмотра. Последний параметр - указатель на объект типа IDirect3DRMViewport, который будет проинициализирован с новыми параметрами.
SetSceneBackgroundRGB - устанавливает цвет фона. В качестве параметров идут интенсивности красного, зелёного и синего. Интенсивность изменяется от 0 до 1, как и в OpenGL.
На сегодня хватит. Я продолжу рассматривать этот пример через месяц. А пока попробуй поиграть с примером сам. Может до чего-нибудь дойдёшь без моей помощи.