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

         

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


Функция CreateScene() приложения OrbStar создает сетку звезды и сетку сферы, текстуру, которая будет наложена на сферу, два источника света и порт просмотра. Код функции CreateScene() приведен в листинге5.4.

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

BOOL OrbStarWin::CreateScene() { //-------- СЕТКА ЗВЕЗДЫ -------- D3DRMLOADRESOURCE resinfo; resinfo.hModule = NULL; resinfo.lpName = MAKEINTRESOURCE(IDR_STARMESH); resinfo.lpType = "MESH"; LPDIRECT3DRMMESHBUILDER starbuilder; d3drm->CreateMeshBuilder(&starbuilder); starbuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL); starbuilder->SetColorRGB(D3DVALUE(1.0), D3DVALUE(0.0), D3DVALUE(0.0)); ScaleMesh(starbuilder, D3DVALUE(20)); //--------- ФРЕЙМ ЗВЕЗДЫ -------- LPDIRECT3DRMFRAME starframe; d3drm->CreateFrame(scene, &starframe); starframe->SetRotation(scene, D3DVALUE(1.0), D3DVALUE(0.0),D3DVALUE(0.0), D3DVALUE(0.1)); starframe->AddVisual(starbuilder); starframe->AddMoveCallback(MoveStar, NULL); starframe->Release(); starframe = 0; starbuilder->Release(); starbuilder = 0; //--------- СЕТКА СФЕРЫ -------- resinfo.hModule = NULL; resinfo.lpName = MAKEINTRESOURCE(IDR_SPHEREMESH); resinfo.lpType = "MESH"; LPDIRECT3DRMMESHBUILDER spherebuilder; d3drm->CreateMeshBuilder(&spherebuilder); spherebuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL); spherebuilder->SetPerspective(TRUE); ScaleMesh(spherebuilder, D3DVALUE(25)); //---------- ТЕКСТУРА ДЛЯ СФЕРЫ ------ LPDIRECT3DRMTEXTURE texture; HRSRC texture_id = FindResource(NULL, MAKEINTRESOURCE( IDR_TRANSTEXTURE), "TEXTURE"); d3drm->LoadTextureFromResource(texture_id, &texture); texture->SetDecalTransparency(TRUE); spherebuilder->SetTexture(texture); texture->Release(); texture = 0; //---------- НАЛОЖЕНИЕ ТЕКСТУРЫ ДЛЯ СФЕРЫ -------- D3DRMBOX box; spherebuilder->GetBox(&box); D3DVALUE width = box.max.x - box.min.x; D3DVALUE height = box.max.y - box.min.y; 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(0.5), D3DVALUE(0.5), // начало координат D3DDivide(1,width), D3DDivide(1,height), // масштаб &wrap); wrap->Apply(spherebuilder); wrap->Release(); wrap = 0; //-------- ФРЕЙМ СФЕРЫ ---------- LPDIRECT3DRMFRAME sphereframe; d3drm->CreateFrame(scene, &sphereframe); sphereframe->SetRotation(scene, D3DVALUE(0), D3DVALUE(1), D3DVALUE(0), D3DVALUE(.1)); sphereframe->AddVisual(spherebuilder); sphereframe->AddMoveCallback(MoveSphere, NULL); sphereframe->Release(); sphereframe = 0; spherebuilder->Release(); spherebuilder = 0; //----------- СВЕТ -------- LPDIRECT3DRMLIGHT light1, light2; d3drm->CreateLightRGB(D3DRMLIGHT_AMBIENT, D3DVALUE(0.8),D3DVALUE(0.8), D3DVALUE(0.8), &light1); d3drm->CreateLightRGB(D3DRMLIGHT_DIRECTIONAL, D3DVALUE(0.9), D3DVALUE(0.9), D3DVALUE(0.9), &light2); LPDIRECT3DRMFRAME lightframe; d3drm->CreateFrame(scene, &lightframe); lightframe->SetOrientation(scene, D3DVALUE(-1), D3DVALUE(-1), D3DVALUE(1), D3DVALUE(0), D3DVALUE(1), D3DVALUE(0)); lightframe->AddLight(light1); lightframe->AddLight(light2); lightframe->Release(); lightframe = 0; light1->Release(); light1 = 0; light2->Release(); light2 = 0; //----------- ПОРТ ПРОСМОТРА -------- d3drm->CreateFrame(scene, &camera); camera->SetPosition(scene, D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(-50)); d3drm->CreateViewport(device, camera, 0, 0, device->GetWidth(), device->GetHeight(), &viewport); return TRUE; }

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

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

Сначала создается сетка звезды:

D3DRMLOADRESOURCE resinfo; resinfo.hModule = NULL; resinfo.lpName = MAKEINTRESOURCE(IDR_STARMESH); resinfo.lpType = "MESH"; LPDIRECT3DRMMESHBUILDER starbuilder; d3drm->CreateMeshBuilder(&starbuilder); starbuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL); starbuilder->SetColorRGB(D3DVALUE(1.0), D3DVALUE(0.0), D3DVALUE(0.0)); ScaleMesh(starbuilder, D3DVALUE(20));

Как и в других демонстрационных приложениях, для загрузки сетки из ресурсов программы используется функция Load() интерфейса Direct3DRMMeshBuilder. Как только сетка загружена, вызывается функция SetColorRGB() для окрашивания всей сетки в красный цвет. Затем для масштабирования сетки в соответствии с заданным размером применяется функция ScaleMesh().

Теперь создается фрейм (с именем starframe) и ему назначаются атрибуты вращения:

LPDIRECT3DRMFRAME starframe; d3drm->CreateFrame(scene, &starframe); starframe->SetRotation(scene, D3DVALUE(1.0), D3DVALUE(0.0),D3DVALUE(0.0), D3DVALUE(0.1)); starframe->AddVisual(starbuilder); starframe->AddMoveCallback(MoveStar, NULL); starframe->Release(); starframe = 0; starbuilder->Release(); starbuilder = 0;

Новый фрейм получает атрибуты вращения, задающие его вращение вокруг оси X. Как вы увидите, эти атрибуты являются временными, поскольку мы используем функцию обратного вызова, для изменения атрибутов вращения во время работы приложения. Созданный ранее конструктор сеток присоединяется к новому фрейму с помощью функции AddVisual(). Перед освобождением указателей starframe и starbuilder выполняется установка функции обратного вызова MoveStar(). На код функции MoveStar() мы взглянем чуть позже. После выполнения описанных действий выполняется освобождение указателей starframe и starbuilder.

Далее создается и загружается сетка сферы:

resinfo.hModule = NULL; resinfo.lpName = MAKEINTRESOURCE(IDR_SPHEREMESH); resinfo.lpType = "MESH"; LPDIRECT3DRMMESHBUILDER spherebuilder; d3drm->CreateMeshBuilder(&spherebuilder); spherebuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL); spherebuilder->SetPerspective(TRUE); ScaleMesh(spherebuilder, D3DVALUE(25));

После загрузки сетки вызывается функция SetPerspective() чтобы разрешить перспективную коррекцию для сетки сферы. Мы не делали этого для сетки звезды, поскольку на нее не накладывается текстура. Далее сетка сферы масштабируется, чтобы ее размеры слегка превышали размеры сетки звезды.

Этап 4 — это создание текстуры для сферы:

LPDIRECT3DRMTEXTURE texture; HRSRC texture_id = FindResource(NULL, MAKEINTRESOURCE( IDR_TRANSTEXTURE), "TEXTURE"); d3drm->LoadTextureFromResource(texture_id, &texture); texture->SetDecalTransparency(TRUE); spherebuilder->SetTexture(texture); texture->Release(); texture = 0;

Как и в других приложениях, для создания текстуры используется функция LoadTextureFromResource(). Потом, чтобы разрешить прозрачность текстуры вызывается функция SetDecalTransparency(). Мы не определяем прозрачный цвет, поэтому по умолчанию как прозрачный будет восприниматься черный цвет. Для привязки текстуры к сетке сферы применяется функция SetTexture() интерфейса Direct3DRMMeshBuilder. После выполнения этих действий указатель texture освобождается.

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

D3DRMBOX box; spherebuilder->GetBox(&box); D3DVALUE width=box.max.x-box.min.x; D3DVALUE height=box.max.y-box.min.y; 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(0.5), D3DVALUE(0.5), // начало координат D3DDivide(1,width), D3DDivide(1,height), // масштаб &wrap); wrap->Apply(spherebuilder); wrap->Release(); wrap = 0;

В данном примере используется плоское наложение текстуры, а размеры сетки используются, чтобы размер покрытия соответствовал сетке. Функция Apply() интерфейса Direct3DRMWrap вызывается, чтобы применить покрытие текстурой к сетке сферы.

На шестом шаге создается фрейм для сетки сферы:

LPDIRECT3DRMFRAME sphereframe; d3drm->CreateFrame(scene, &sphereframe); sphereframe->SetRotation(scene, D3DVALUE(0), D3DVALUE(1), D3DVALUE(0), D3DVALUE(.1)); sphereframe->AddVisual(spherebuilder); sphereframe->AddMoveCallback(MoveSphere, NULL); sphereframe->Release(); sphereframe = 0; spherebuilder->Release(); spherebuilder = 0;

Новому фрейму присваиваются атрибуты вращения, но, также как и для фрейма, созданного на этапе 2, для изменения этих атрибутов используется функция обратного вызова. С помощью функции AddVisual() к фрейму присоединяется сетка сферы и устанавливается функция обратного вызова MoveSphere(). Затем выполняется освобождение указателей sphereframe и spherebuilder.

На седьмом и восьмом этапах для сцены создаются источники света и порт просмотра. Код очень похож на тот, который используется в приложении Jade. Вы узнаете больше об источниках света и портах просмотра в следующих главах книги.



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