Cодержание:
1.Создание Direct3D-программы
2.Создание главного Direct3D-объекта
3.Создание объекта усечения
4.Создание Direct3D-устройства
5.Создание Direct3D-кадров
6.Создание Direct3D-сеток
7.Создание порта просмотра
8.Освечение Direct3D-сцены
Приложение(Программа)
Теперь, когда мы знакомы с большей
частью библиотек DirectX, вы готовы к штурму
настоящих вершин этой технологии. Вне
всяких сомнений, Direct3D представляет собой
самую сложную из библиотек DirectX. Она состоит
из огромного числа интерфейсов,
программирование которых нужно освоить, а
это требует немалых знаний основ 3D
программирования. В этой статье мы
рассмотрим, как использовать в программе
основные функциональные возможности.
Создание Direct3D программы.
Процесс создание Direct3D-программы
не так легко представить в виде набора
последовательно выполняемых инструкций.
Осуществить компоновку Direct3D-программы
можно слишком многими способами, и на
каждом из этих этапов этого процесса
возникает слишком много вариантов. И все же
можно выделить ряд действий, которые
необходимо выполнить при создании Direct3D-программ.
В данном разделе мы выполним анализ этих
основных действий и выясним, как
реализовать их в программе.
Чтобы создать Direct3D-программу
обычно приходиться решать перечисленные
ниже задачи. Дальнейшие действия зависят от
типа создаваемой Direct3D-программы. Основные
этапы создание Direct3D-программы являются
следующими.
-
Создание объекта усечения. Direct3D
перенимает все лучшее от DirectDraw , пример
тому наличие объекта усечения. Благодаря
этому объекту усечения, окно Direct3D-приложения
получает возможность обновлять свое
содержимое, не обновляя при этом
остальных присутствующих на экране окон.
-
Создание Direct3D-устройства. Имея
объект усечения, вы можете использовать
его для создания Direct3D-устройства,
наиболее подходящего для окна вашего
приложения. Это устройство будет
отображать трехмерные сцены, используя
установленное в системе оборудование.
-
Создание корневого кадра. С
помощью кадров осуществляется
позиционирование и ориентация Direct3D-объектов.
Каждое Direct3D-приложение должно иметь
корневой кадр, который является
родительским(или, если хотите,
контейнером) для других кадров.
-
Создание сеток для отображаемых
объектов. Сетка представляет собой
совокупность связанных многоугольников,
задающих трехмерный каркас нужной формы.
-
Создание кадров для сеток.
Каждый включаемый в трехмерную сцену
объект должен быть связан с кадром,
определяющим позицию и ориентацию этого
объекта.
-
Создание порта просмотра для
сцены. Подобно видоискателю кинокамеры,
порт просмотра определяет какая часть
трехмерной сцены должна отображаться на
экране.
-
Добавление источников света. Как
светильники в комнате, источники света
Direct3D определяют не только освещенность
сцены но и используемые цвета, а также
особенности отображения света
различными объектами.
Если вы выполните эти действия,
ваша программа будет готова к построению на
экране изображений трехмерных сцен Direct3D. В
последующих разделах мы детально
рассмотрим каждый из приведенных ниже
этапов и проанализируем код программ,
реализующих эту схему.
Создание главного Direct3D-объекта
Для использования Direct3D в
программе необходимо создать главный Direct3D-объект,
с помощью которого программа сможет
получить доступ к интерфейсам Direct3D. Чтобы
создать Direct3D-объект, вызывается функция
Direct3DRMCreate():
LPDIRECT3DRM pD3D;
HRESULT result = Direct3DRMCreate(&pD3D);
if(result != D3DRM_OK)
{
//Обработка
неудачного вызова
}
LPDIRECT3DRM - это
указатель на главный Direct3D-объект,
создаваемый в режиме последствия. В данном
примере указатель получает имя pD3D. Адрес
этого указателя передается функцией
Direct3DRMCreate() в качестве единственного
параметра. При успешном вызове функция
Direct3DRMCreate() помещает адрес главного 3D-объекта
в указатель pD3D. Чтобы гарантировать
корректность указателя, нужно проверить
возвращаемое функцией Direct3DRMCreate() значение -
при успешном завершении работы функции оно
должно быть равно D3DRM_OK.
Создание объекта усечения
Несмотря на то что
размеры виртуального мира могут быть
огромными, видимая часть этого
виртуального мира будет ограничена для
пользователя экраном или даже окном. Объект
усечения, представляющий собой специальный
Direct3D-объект связанный с окном, управляет
представлением трехмерной сцены на экране.
Так, например, в многооконной среде объект
усечения следит за тем, чтобы данные,
отображаемые в Direct3D-окне не воздействовали
на другие области экрана, в частности окна
других программ, частично или полностью
закрывающих окно Direct3D-приложения. Создать
объект усечения можно вызвав функцию
DirectDrawCreateClipper():
LPDIRECTDRAWCLIPPER pClipper;
HRESUL result = DirectDrawCreateClipper(0, &pClipper, 0);
if(result != DD_OK)
{
//Обработка
неудачной попытки.
}
LPDIRECTDRAWCLIPPER-это указатель
на объект DIRECTDRAWCLIPPER. В данном случае
указатель получает имя pClipper. Адрес
указателя передается функции DirectDrawClipper() в
качестве ее второго параметра. (Первый и
третий параметры могут быть равны нулю) При
успешном вызове функция помещает адрес
объекта усечения в указатель pClipper. Чтобы
гарантировать корректность содержимого
указателя, нужно проверить значение, возвращаемое
функцией, при успешном завершении функция
возвращает значение равное DD_OK.
Создав объект
усечения, нужно связать его с окном, которым
этот объект будет управлять. С этой целью
вызывается функция SetHWnd(), принадлежащая
объекту усечения:
result = pClipper->SetHWnd(0, hWnd);
if(result != DD_OK)
{
//Обработка
неудачной попытки.
}
В качестве первого параметра
функции SetHWnd() передается нулевое значение,
второй параметр представляет собой
дескриптор окна. При успешном вызове эта
функция возвращает значение DD_OK.
Создание Direct3D-устройства
Объект усечения управляет
отображением сцен на экране; однако
непосредственное отображение выполняется
Direct3D-устройством. Поэтому вам придется
создать Direct3D-устройство. Сделать это можно
вызвав функцию CreateDeviceFromClipper() главного 3D
объекта.
RECT rect;
::GetClientRect(hWnd, &rect);
LPDIRECT3DRMDEVICE pDevice;
HRESULT result = pD3D->CreateDeviceFromClipper(pClipper, NULL, rect.right,
rect.bottom, &pDevice);
if(result != D3DRM_OK)
{
//Обработка
неудачной попытки.
}
В данном
примере перед тем, как вызвать функцию
CreateDeviceFromClipper(), вызывается функция GetClientRect().
Это делается для того, чтобы выяснить
размеры рабочей области окна, которые
потребуются программе при создании
устройства. LPDIRECT3DRMDEVICE- это указатель на
объект DIRECT3DRMDTVICE. В данном случае этот
указатель получает имя pDevice. Адрес
указателя передается функции CreateDeviceFromClipper()
в качестве пятого параметра. Назначение
параметров функции CreateDeviceFromClipper() следующие.
-
Указатель на объект усечения.
-
GUID устройства (для
конической цветовой модели
используется значение NULL)
-
Ширина окна, для которого
создается устройство.
-
Высота окна, для которого
создается устройство.
-
Адрес указателя LPDIRECT3DRMDEVICE.
При успешном вызове функция
CreateDeviceFromClipper() помещает адрес объекта
устройства в указатель pDevice .При успешном
вызове функция возвращает значение равное
D3DRM_OK.
Для создания Direct3D
устройства вы можете либо оставить
предлагаемую по умолчанию модель
равномерного закрашивания многоугольников,
либо выбрать закрашивание по методу Гуро (Gouraud);
оно дает более реалистичные результаты. При
использовании равномерного закрашивания
световые эффекты реализуются таким образом
что на экране могут быть видны отдельные
многоугольники ограничивающие трехмерную
поверхность.
При закрашивании по методу
Гуро цветовые значения внутри
многоугольника интерполируются так, чтобы
обеспечить плавные цветовые переходы между
вершинами, в результате чего создаваемые
поверхности выглядят более реалистично.
Чтобы использовать в программе эту более
совершенную модель закрашивания, нужно,
вызвать функцию SetQuality() объекта устройства:
pDevice->SetQuality(D3DRMRENDER_GOURAUD);
Создание корневого кадра
Как вы уже знаете сцена Direct3D
состоит из множества объектов, каждый из
которых размещается в своем кадре. Именно
объект кадра определяет позицию и
ориентацию включенного в сцену объекта. Все
кадры, составляющие сцену, являются
дочерними по отношению к корневому кадру.
Ясно, что, прежде чем создавать дочерние
кадры, нужно создать корневой кадр.
Делается что с помощью вызова функции
CreateFrame() главного Direct3D-объекта.
LPDIRECT3DRMFRAME pParentFrame;
HRESULT result = pD3D->CreateFrame(0, &pParentFrame);
if(result != D3DRM_OK)
{
//Обработка
неудачной попытки.
}
LPDIRECT3DRMFRAME - это указатель на
объект DIRECT3DRMFRAME. В данном примере
указатель получает имя pParenFrame. Его адрем
передается функции CreateFrame(); в качестве
второго параметра. при успешном вызове
функция помещает адрес объекта кадра в
указатель pParentFrame и возвращает значение
равное D3DRM_OK.
Создание сеток для объектов
К этому моменту
инициализация Direct3D в нашей программе
закончена и программа готова к работе. Все
что осталось сделать, - создать трехмерную
сцену для отображения на экране (не думайте
что это просто!). Включение в Direct3D сцену
объект представляется сеткой, которая, в
свою очередь, представляет собой группу
соединенных вместе многоугольников
задающих поверхность трехмерного объекта.
Direct3D предлягает несколько способов
построения сетки, представленного
интерфейсом Direct3DRMMeshBuilder. Объект
построителя сетки создается с помощью
функции CreateMeshBuilder() главного Direct3D- объекта.
LPDIRECT3DRMMESHBUILDER pMeshBuilder;
HRESULT result = pD3D->CreateMeshBuilder(&pMeshBuilder);
if(result != D3DRM_OK)
{
//Обработка
неудачной попытки.
}
LPDIRECT3DRMMESHBUILDER представляет
собой указатель наобъект DIRECT3DRMMESHBUILDER. В
данном случае указатель получает имя
pMeshBuilder. Адрес этого указателя передается
функции. При успешном вызове функции она
помещает адрес объекта построителя сетки в
указатель pMeshBuilder. Далее она должна вернуть
занчение равнок D3DRM_OK.
Создав построитель сетки вы
можете создать саму сетку. Для этого нужно
вызвать функцию Load() объекта построителя
сетки.
HRESULR result = pMeshBuilder->Load(fileName,
NULL, D3DRMLOAD_FROMFILE, NULL, NULL);
if(result != D3DRM_OK)
{
//Обработка
неудачной попытки.
}
Посколько в данном примере
используется флаг D3DRMLOAD_FROMFILE, функция Load()
ищет файл с именем fileName. Этот файл долже
быть представлен в формете Х-файла,
означающим тип файла создаваемого из
объектов 3D Studio путем их преобразования
из файлов *.3ds в файлы *.x утилитой CONV3DS
которую вы можете найти на сервере http://www.rpc.agava.ru/
в разделе интсрументы. Если загрузка прошла
успешно возвращается значение равное D3DRM_OK.
Создание кадров для сеток
Вы, наверное, еще помните,
что все включенные в Direct3D-сцену объекты
связываются с кадрами, определяющих
ориентацию и позицию объекта. Это касается
и сеток. Создав сетку, вы не сможете
добавить её в свой трехмерный мир до тех пор,
пока не поставите ей в соответствие
некоторый кадр. Эта проблема решается с
помощью ещё одног вызова функции CreateFrame():
LPDIRECT3DRMFRAME pFrame;
HRESULT result = pD3D->CreateFrame(pParentFrame, &pFrame);
if(result != D3DRM_OK)
{
//Обработка
неудачной попытки.
}
Обратите
внимание, что в данном случае функция CreateFrame()
в качестве первого параметра получает
указатель на родительский кадр, а это
означает, что новый кадр будет дочерним.
После того как дочерний кадр создан,
соответствие между ним и сеткой(
представляемой объектом построителя сетки)
устанавливается с помощью функции AddVisual()
этого кадра:
pFrame->AddVisual(pMeshBuilder);
Порт просмотра
Итак, трехмерная сцена,
содержащая объект, создана. Но, к сожалению
увидеть этот объект все ещё нельзя,
поскольку мы не указали Direct3D позицию, с
которой мы хотели бы видеть сцену. Чтобы
позаботиться об этой маленькой детали
необходимо создать порт просмотра, с
помощью которого не только определяется
точка и угол зрения, но и плоскости,
ограничивающие видимую часть трехмерного
мира. Представьте себе, что вы стоите в
комнате лицом к окну. По мере того как вы
перемещаетесь ближе к окну или дальше от
него, соответственно меняется вид
открывающийся из окна. Порт просмтора можно
сравнить таким окном.
Создание кадра порта просмотра
Чтобы создать порт
просмотра сначала нужно создать кадр, с
помощью которого будет осуществляться
позиционирование и ориентация порта
просмотра:
LPDIRECT3DRMFRAME pEye;
HRESULT result = pD3D->CreateFrame(pParentFrame, &pEye);
if(result != D3DRM_OK)
{
//Обработка
неудачной попытки.
}
Здесь новый
кадр указатель на который получает имя pEye ,
также создается как дочерний по отношению к
кадру, определяемому указателем pParentFrame.
После создания объекта кадра вызывается
функция SetPosition(), с помощью которой
устанавливается позиция внутри
родительского кадра.
pEye->SetPosition(pParentFrame, D3DVALUE(0),
D3DVALUE(0), D3DVALUE(-40.0));
Как
видите, функции SetPosition() передается четыре
параметра.
-
Указатель на родительское окно
-
Значение X-составляющей новой
позиции.
-
Значение Y-составляющей новой
позиции.
-
Значение Z-составляющей новой
позиции.
Кадр можно сравнить с глазом.
Перед позиционированием все объекты,
включаемые в трехмерную сцену, сначала
размещаются в самом центре трехмерного
мира, т.е. в позиции 0,0,0 . Поэтому когда вы
помещаете глаз в трехмерную сцену, он
сначала оказывается внутри трехмерного
объекта (представляемого объектом
строителем сетки), который был расположен в
той же позиции. Чтобы увидеть объект, нужно
посмотреть на него со стороны, т.е. изменить
точку зрения или проще отойти назад.
Поэтому при вызове функции SetPosition() значение
Z установлено равным -40. Отрицательные
значения означают перемещение назад от
сцены, а положительные вперед. Например, в
нашем случае значение Z, равное -40, даёт
возможность видеть объект, а при
положительном эе значении объект бы
расположился бы "за спиной" и остался
бы невидимым.
Создание порта просмотра
Создав кадр порта вы
получаете возможность создать и порт
просмотра. Сделать это можно вызвав функцию
CreateViewport() главного Direct3D объекта.
LPDIRECT3DVIEWPORT pViewport;
result = pD3D->CreateViewport (pDevice, pEye, 0,0,&pViewport);
if(result != D3DRM_OK)
{
//Обработка
неудачной попытки.
}
LPDIRECT3DVIEWPORT- это
указатель на объект DIRECT3DRMVIEWPORT. В данном
случае указатель получает имя pViewport. Адрес
этого указателя передаётся функции CreateViewport()
в качестве одного из семи параметров
-
Указатель на объект
устройства.
-
Указатель с деньгами.
-
X-составляющая позиция
порта просмотра.
-
Y-составляющая позиции
порта просмотра.
-
Ширина просмотра.
-
Высота просмотра.
-
Адрес указателя на порт
просмотра.
При успешном
вызове функция помещает адрес объекта
порта в указатель pViewport и возвращает
значение равное D3DRM_OK.
Добавление источников
света
Вы может
рассматривать трехмерную сцену с разных
точек зрения но она будет оставаться темной.
Поэтому последнее что вам осталось сделать,
- это добавить в трехмерную сцену источник
света. Direct3D поддерживает различные типы
освещения, включая позиционное,
направленное, рассеянное и световое пятно.
В нашем примере используем направленное
освещение.
Создание объекта
источника
Первым
шагом является создание объекта освещения.
Делается это с помощью функции CreateLightRGB()
главного Direct3D объекта.
LPDIRECT3DRMLIGHT pLight;
HRESULT result = pD3D->CreateLightRGB(D3DRMLIGHT_DIRECTIONAL, D3DVALUE(1.0),
D3DVALUE(1.0),
D3DVALUE(1.0), &pLight);
if(result != D3DRM_OK)
{
//Обработка
неудачной попытки.
}
LPDIRECT3DRMLIGHT -
это указатель на объект DIRECT3DRMLIGHT. В данном
примере указатель получает имя pLight.
Параметры:
-
Флаг задающий тип создаваемого
источника света.
-
Интенсивность красного
компонента света
-
Интенсивность зеленного
компонента света
-
Интенсивность синего
компонента света.
-
Адрес указателя на объект
При успешном вызове функция
CreateLightRGB() помещает адрес объекта источника
в указатель pLight и возвращает значение
равное D3DRM_OK.
Создание дочернего кадра
освещения
После построения источника
света нужно создать для него дочерний
кадр, с помощью которого можно управлять
освещением в родительском окне.
LPDIRECT3DRMFRAME pLightFrame;
result = pD3D->CreateFrame(pParentFrame, &pLightFrame);
if(result != D3DRM_OK)
{
//Обработка
неудачной попытки.
}
Чтобы
включить в кадр освещение, необходимо
вызвать функцию AddLight() кадра.
pLightFrame->AddLight(pLight);
Наконец вы
позиционируете источник света посредством
вызова функции SetOrientation(), принадлежащей
кадру.
pLightFrame->SetOrientation(pParenFrame,
D3DVALUE(0.0), D3DVALUE(-1.0), D3DVALUE(1.0)
D3DVALUE(0.0), D3DVALUE(1.0), D3DVALUE(0.0));
Ниже приведен список параметров
функции SetOrientation().
-
Указатель на родительский кадр.
-
X-составляющая вектора
направления.
-
Y-составляющая вектора
направления.
-
Z-составляющая направления
-
X-составляющая вектора высоты
-
Y-состовляющая вектора высоты
-
Z-состовляющая вектора высоты
Вектор направления
представляет собой линию, указывающую
распространение света. В функции SetOrientation()
вектор направления указывает направление
освещения, а вектор высоты задает высоту
источника.
Приложение.
Исходной код программы Direct3D http://www.helloworld.ru/texts/comp/games/directx/direct3d/direct3d.cpp
Файл my.x необходимый для программы http://www.helloworld.ru/texts/comp/games/directx/direct3d/my.x
Материал взят из книги "Секреты
программирования в windows 98" автора Велнум
Клейтон.
|