Программирование графики с использованием Direct3D

         

Функция ShadowWin::CreateScene()


Сцена создается функцией CreateScene(), код которой представлен в листинге6.6.

Листинг 6.6. Функция ShadowWin::CreateScene()

//------------- СЕТКА ПОЛА -------- D3DRMLOADRESOURCE resinfo; resinfo.hModule = NULL; resinfo.lpName = MAKEINTRESOURCE(IDR_CUBEMESH); resinfo.lpType = "MESH"; d3drm->CreateMeshBuilder(&floorbuilder); floorbuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL); floorbuilder->Scale(D3DVALUE(5), D3DVALUE(.05), D3DVALUE(5)); floorbuilder->SetPerspective(TRUE); floorbuilder->SetQuality(D3DRMRENDER_FLAT); //------------ ТЕКСТУРА ПОЛА -------------- LPDIRECT3DRMTEXTURE texture; HRSRC texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_FLOORTEXTURE), "TEXTURE"); d3drm->LoadTextureFromResource(texture_id, &texture); floorbuilder->SetTexture(texture); texture->Release(); texture = 0; //------------ НАЛОЖЕНИЕ ТЕКСТУРЫ ПОЛА ------------ D3DRMBOX box; floorbuilder->GetBox(&box); D3DVALUE w = box.max.x - box.min.x; D3DVALUE h = box.max.z - box.min.z; LPDIRECT3DRMWRAP wrap; d3drm->CreateWrap( D3DRMWRAP_FLAT, NULL, D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(0.0), // начало координат наложения D3DVALUE(0.0), D3DVALUE(1.0), D3DVALUE(0.0), // ось z наложения D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(1.0), // ось y наложения D3DVALUE(.5) ,D3DVALUE(0.5), // начало координат текстуры D3DDivide(1,w), D3DDivide(1,h), // масштаб текстуры &wrap); wrap->Apply(floorbuilder); wrap->Release(); wrap = 0; //------------- ФРЕЙМ ПОЛА ---------- LPDIRECT3DRMFRAME floorframe; d3drm->CreateFrame(scene, &floorframe); floorframe->AddVisual(floorbuilder); floorframe->Release(); floorframe = 0; //---------------- СЕТКА ВИЛКИ -------- resinfo.hModule = NULL; resinfo.lpName = MAKEINTRESOURCE(IDR_FORKMESH); resinfo.lpType = "MESH"; d3drm->CreateMeshBuilder(&forkbuilder); forkbuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL); forkbuilder->SetQuality(D3DRMRENDER_FLAT); //--------------- ФРЕЙМ ВИЛКИ ---------- LPDIRECT3DRMFRAME forkframe; d3drm->CreateFrame(scene, &forkframe); forkframe->SetRotation(scene, D3DVALUE(1), D3DVALUE(1), D3DVALUE(1), D3DVALUE(0.4)); forkframe->SetPosition(scene, D3DVALUE(0), D3DVALUE(6), D3DVALUE(0)); forkframe->AddVisual(forkbuilder); forkframe->AddMoveCallback(AdjustSpin, NULL); //-------------- РАССЕЯННЫЙ СВЕТ -------- LPDIRECT3DRMLIGHT ambientlight; d3drm->CreateLightRGB(D3DRMLIGHT_AMBIENT, D3DVALUE(1),D3DVALUE(1), D3DVALUE(1), &ambientlight); scene->AddLight(ambientlight); ambientlight->Release(); ambientlight = 0; //-------------- ТОЧЕЧНЫЙ СВЕТ ---------- LPDIRECT3DRMLIGHT pointlight; d3drm->CreateLightRGB(D3DRMLIGHT_POINT, D3DVALUE(1),D3DVALUE(1), D3DVALUE(1), &pointlight); LPDIRECT3DRMFRAME lightframe; d3drm->CreateFrame(scene, &lightframe); lightframe->SetPosition(scene, D3DVALUE(0), D3DVALUE(30), D3DVALUE(0)); lightframe->AddLight(pointlight); lightframe->Release(); lightframe = 0; //-------------- ТЕНЬ ---------- LPDIRECT3DRMVISUAL shadow; d3drm->CreateShadow(forkbuilder, pointlight, D3DVALUE(0), box.max.y+D3DVALUE(0.1), D3DVALUE(0), D3DVALUE(0), box.max.y+D3DVALUE(1.0), D3DVALUE(0), (LPDIRECT3DRMVISUAL*)&shadow); forkframe->AddVisual(shadow); shadow->Release(); shadow = 0; forkframe->Release(); forkframe = 0; pointlight->Release(); pointlight = 0; //------------- ПОРТ ПРОСМОТРА -------- d3drm->CreateFrame(scene, &camera); camera->SetPosition(scene, D3DVALUE(0.0), D3DVALUE(25.0), D3DVALUE(-20.0)); camera->SetOrientation(scene, D3DVALUE(0), D3DVALUE(-25), D3DVALUE(20), D3DVALUE(.1), D3DVALUE(1), D3DVALUE(0)); d3drm->CreateViewport(device, camera, 0, 0, device->GetWidth(), device->GetHeight(), &viewport); return TRUE; }

Функция CreateScene() выполняет следующие десять действий:

  1. Создание сетки, представляющей платформу или пол.
  2. Создание текстуры для сетки пола.
  3. Создание и применение наложения текстуры для сетки пола.
  4. Размещение сетки пола и ее фрейма.
  5. Создание сетки вилки.
  6. Размещение сетки вилки и ее фрейма.
  7. Создание источника рассеянного света.
  8. Создание точечного источника света.
  9. Создание тени.
  10. Создание порта просмотра.

Давайте начнем изучение кода с шага 1, создания сетки пола:

D3DRMLOADRESOURCE resinfo; resinfo.hModule = NULL; resinfo.lpName = MAKEINTRESOURCE(IDR_CUBEMESH); resinfo.lpType = "MESH"; d3drm->CreateMeshBuilder(&floorbuilder); floorbuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL); floorbuilder->Scale(D3DVALUE(5), D3DVALUE(.05), D3DVALUE(5)); floorbuilder->SetPerspective(TRUE); floorbuilder->SetQuality(D3DRMRENDER_FLAT);

Для представления пола используется сетка кубической формы. Она загружается с помощью функции Load() интерфейса Direct3DRMMeshBuilder, а затем делается плоской с помощью функции Scale(). Для сетки разрешается перспективная коррекция и устанавливается плоский метод визуализации.

На следующем этапе осуществляется загрузка текстуры, которая будет наложена на сетку пола:

LPDIRECT3DRMTEXTURE texture; HRSRC texture_id = FindResource(NULL, MAKEINTRESOURCE(IDR_FLOORTEXTURE), "TEXTURE"); d3drm->LoadTextureFromResource(texture_id, &texture); floorbuilder->SetTexture(texture); texture->Release(); texture = 0;

Значение, идентифицирующее текстуру, получается с помощью функции FindResource(), входящей в Win32 API. Затем текстура загружается с помощью функции LoadTextureFromResource() и связывается с созданным ранее конструктором сеток с помощью функции SetTexture(). После выполнения этих действий указатель texture освобождается.

На третьем этапе происходит создание и применение наложения текстуры для сетки пола:

D3DRMBOX box; floorbuilder->GetBox(&box); D3DVALUE w = box.max.x - box.min.x; D3DVALUE h = box.max.z - box.min.z; LPDIRECT3DRMWRAP wrap; d3drm->CreateWrap(D3DRMWRAP_FLAT, NULL, D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(0.0), // начало координат наложения D3DVALUE(0.0), D3DVALUE(1.0), D3DVALUE(0.0), // ось z наложения D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(1.0), // ось y наложения D3DVALUE(.5) ,D3DVALUE(0.5), // начало координат текстуры D3DDivide(1,w), D3DDivide(1,h), // масштаб текстуры &wrap); wrap->Apply(floorbuilder); wrap->Release(); wrap = 0;

Функция GetBox() интерфейса Direct3DRMMeshBuilder используется для получения размеров сетки пола. Размеры сетки (и ряд других значений) используются при создании плоского наложения текстуры. Наложение текстуры используется чтобы применить привязанную ранее текстуру к сетке пола с помощью функции Apply() интерфейса Direct3DRMWrap. Затем указатель wrap освобождается. Подробное описание функции CreateWrap() приведено в разделе главы 5, посвященном описанию приложения Wraps.

Теперь создадим фрейм для сетки пола:

LPDIRECT3DRMFRAME floorframe; d3drm->CreateFrame(scene, &floorframe); floorframe->AddVisual(floorbuilder); floorframe->Release(); floorframe = 0;

Фрейм создается функцией CreateFrame() интерфейса Direct3DRM. Функция AddVisual() применяется для присоединения конструктора сеток к новому фрейму. После этого указатель floorframe освобожлается поскольку он больше нам не потребуется.

На пятом этапе создается сетка вилки:

resinfo.hModule = NULL; resinfo.lpName = MAKEINTRESOURCE( IDR_FORKMESH ); resinfo.lpType = "MESH"; d3drm->CreateMeshBuilder(&forkbuilder); forkbuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL); forkbuilder->SetQuality(D3DRMRENDER_FLAT);

Файл сетки вилки является частью ресурсов программы (также как и сетка пола и текстура пола). Сетка загружается функцией Load() интерфейса Direct3DRMMeshBuilder. Для сетки задается плоский метод визуализации. Обратите внимание, что мы не включаем перспективную коррекцию, поскольку на сетку вилки текстура не накладывается.

Теперь пришло время создать фрейм для сетки вилки и настроить его параметры:

LPDIRECT3DRMFRAME forkframe; d3drm->CreateFrame(scene, &forkframe); forkframe->SetRotation(scene, D3DVALUE(1), D3DVALUE(1), D3DVALUE(1), D3DVALUE(0.4)); forkframe->SetPosition(scene, D3DVALUE(0), D3DVALUE(6), D3DVALUE(0)); forkframe->AddVisual(forkbuilder); forkframe->AddMoveCallback(AdjustSpin, NULL);

Новому фрейму присваиваются атрибуты вращения, но это является временной мерой, поскольку вскоре функция обратного вызова AdjustSpin() перезапишет эти параметры. Фрейм вилки размещается на шесть единиц выше начала координат (сетка пола размещена в начале координат).

Сетка вилки присоединяется к своему фрейму с помощью функции AddVisual(). Затем с помощью функции AddMoveCallback() интерфейса Direct3DRMFrame устанавливается функция обратного вызова AdjustSpin().

На седьмом этапе создается источник рассеянного света:

LPDIRECT3DRMLIGHT ambientlight; d3drm->CreateLightRGB(D3DRMLIGHT_AMBIENT, D3DVALUE(1),D3DVALUE(1), D3DVALUE(1), &ambientlight); scene->AddLight(ambientlight); ambientlight->Release(); ambientlight = 0;

Ранее в этой главе, когда мы изучали способы работы с источником рассеянного света, мы присоединяли источник света непосредственно к корневому фрейму сцены. Здесь мы тоже не будем тратить силы на создание фреймов и воспользуемся корневым фреймом сцены (scene).

Восьмым шагом является создание точечного источника света. Это тот источник света, который будет создавать тень от вилки. Код его создания выглядит так:

LPDIRECT3DRMLIGHT pointlight; d3drm->CreateLightRGB(D3DRMLIGHT_POINT, D3DVALUE(1),D3DVALUE(1), D3DVALUE(1), &pointlight); LPDIRECT3DRMFRAME lightframe; d3drm->CreateFrame(scene, &lightframe); lightframe->SetPosition(scene, D3DVALUE(0), D3DVALUE(30), D3DVALUE(0)); lightframe->AddLight(pointlight); lightframe->Release(); lightframe = 0;

Сразу после создания источника света, создается фрейм для его размещения. Фрейм перемещается от начала координат на 30 единиц вверх. Для присоединения источника света к новому фрейму используется функция AddLight().

На следующем этапе выполняется создание объекта Direct3DRMShadow:

LPDIRECT3DRMSHADOW shadow; d3drm->CreateShadow(forkbuilder, pointlight, D3DVALUE(0), box.max.y+D3DVALUE(0.1), D3DVALUE(0), D3DVALUE(0), box.max.y+D3DVALUE(1.0), D3DVALUE(0), (LPDIRECT3DRMVISUAL*)&shadow); forkframe->AddVisual(shadow); shadow->Release(); shadow = 0; forkframe->Release(); forkframe = 0; pointlight->Release(); pointlight = 0;

Тень создается с помощью функции CreateShadow() интерфейса Direct3DRM, которая получает девять аргументов. Первый аргумент — это указатель на объект, который будет отбрасывать тень. Второй аргумент — указатель на источник света, который будет использоваться при вычислении формы тени. Следующие шесть аргументов определяют плоскость, на которую будет отбрасываться тень (первые три аргумента задают точку плоскости, а следующие три определяют перпендикулярный плоскости вектор). Последний аргумент, передаваемый функции CreateShadow() интерфейса Direct3DRM, — адрес инициализируемого функцией указателя. По непонятным причинам в качестве последнего аргумента функция CreateShadow() ожидает указатель на интерфейс Direct3DRMVisual, а не указатель на интерфейс Direct3DRMShadow. Поэтому для корректной компиляции программы необходимо указать явное преобразование типа указателя.

На заключительном этапе работы функция CreateScene() создает порт просмотра:

d3drm->CreateFrame(scene, &camera); camera->SetPosition(scene, D3DVALUE(0.0), D3DVALUE(25.0), D3DVALUE(-20.0)); camera->SetOrientation(scene, D3DVALUE(0), D3DVALUE(-25), D3DVALUE(20), D3DVALUE(.1), D3DVALUE(1), D3DVALUE(0)); d3drm->CreateViewport(device, camera, 0, 0, device->GetWidth(), device->GetHeight(), &viewport);

Фрейм camera инициализируется функцией CreateFrame() интерфейса Direct3DRM, перемещается вверх и вперед от начала координат, и направляется на начало координат. Функция CreateViewport() применяется для инициализации указателя viewport.

Завершая свою работу, функция CreateScene() возвращает TRUE, чтобы сообщить об успешном завершении создания сцены.



Содержание раздела