В приложении Firefly создание сцены осуществляется в функции CreateScene(). Функция отвечает за создание двух сеток: одной для чаши и одной для светлячка. Кроме того, в ней создается один точечный источник света и один порт просмотра. Для анимации источника света и сферической сетки применяются пустые фреймы. За дополнительной информацией о пустых фреймах можно обратиться к описанию приложения Decal в главе 5. Код функции CreateScene() приложения Firefly приведен в листинге 6.2.
Листинг 6.2. Функция FireflyWin::CreateScene() |
BOOL FireflyWin::CreateScene() { //-------- СЕТКА ЧАШИ -------- D3DRMLOADRESOURCE resinfo; resinfo.hModule = NULL; resinfo.lpName = MAKEINTRESOURCE(IDR_CHALICEMESH); resinfo.lpType = "MESH"; d3drm->CreateMeshBuilder(&chalicebuilder); chalicebuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL); ScaleMesh(chalicebuilder, D3DVALUE(25)); //------- ФРЕЙМ ЧАШИ ------ LPDIRECT3DRMFRAME chaliceframe; d3drm->CreateFrame(scene, &chaliceframe); chaliceframe->AddVisual(chalicebuilder); chaliceframe->Release(); chaliceframe = 0; //-------- ТОЧЕЧНЫЙ СВЕТ -------- LPDIRECT3DRMLIGHT pointlight; d3drm->CreateLightRGB(D3DRMLIGHT_POINT, D3DVALUE(1.0),D3DVALUE(1.0), D3DVALUE(1.0), &pointlight); //-------- СЕТКА СВЕТЛЯЧКА ------ resinfo.hModule = NULL; resinfo.lpName = MAKEINTRESOURCE(IDR_SPHEREMESH); resinfo.lpType = "MESH"; LPDIRECT3DRMMESHBUILDER flybuilder; d3drm->CreateMeshBuilder(&flybuilder); flybuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL); flybuilder->SetQuality(D3DRMRENDER_WIREFRAME); ScaleMesh(flybuilder, D3DVALUE(0.3)); //-------- ФРЕЙМЫ ИСТОЧНИКА СВЕТА -------- LPDIRECT3DRMFRAME dummyframe; d3drm->CreateFrame(scene, &dummyframe); dummyframe->SetRotation(scene, D3DVALUE(0), D3DVALUE(1), D3DVALUE(0), D3DVALUE(.08)); LPDIRECT3DRMFRAME lightframe; d3drm->CreateFrame(dummyframe, &lightframe); lightframe->SetPosition(dummyframe, D3DVAL(15), D3DVAL(6), D3DVAL(0)); lightframe->AddLight(pointlight); lightframe->AddVisual(flybuilder); flybuilder->Release(); flybuilder = 0; lightframe->Release(); lightframe = 0; dummyframe->Release(); dummyframe = 0; pointlight->Release(); pointlight = 0; //-------- ПОРТ ПРОСМОТРА ------------ d3drm->CreateFrame(scene, &camera); camera->SetPosition(scene, D3DVALUE(0.0), D3DVALUE(20.0), D3DVALUE(-50.0)); camera->SetOrientation(scene, D3DVALUE(0), D3DVALUE(-20), D3DVALUE(50), D3DVALUE(0), D3DVALUE(1), D3DVALUE(0)); d3drm->CreateViewport(device, camera, 0, 0, device->GetWidth(), device->GetHeight(), &viewport); return TRUE; } |
Функция CreateScene() выполняет следующие действия:
Сначала создаем сетку чаши:
D3DRMLOADRESOURCE resinfo; resinfo.hModule = NULL; resinfo.lpName = MAKEINTRESOURCE(IDR_CHALICEMESH); resinfo.lpType = "MESH"; d3drm->CreateMeshBuilder(&chalicebuilder); chalicebuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL); ScaleMesh(chalicebuilder, D3DVALUE(25));Интерфейс Direct3DRMMeshBuilder используется для загрузки сетки из ресурсов программы. Затем, для изменения размеров сетки применяется функция ScaleMesh().
Новая сетка присоединяется к фрейму с именем chaliceframe:
LPDIRECT3DRMFRAME chaliceframe; d3drm->CreateFrame(scene, &chaliceframe); chaliceframe->AddVisual(chalicebuilder); chaliceframe->Release(); chaliceframe = 0;Для присоединения сетки чаши к новому фрейму вызывается функция AddVisual(). Перемещение фрейма не выполняется, поэтому сетка располагается в начале координат. Обратите внимание, что указатель chalicebuilder не объявлен в функции CreateScene(), а является членом класса FireflyWin. Это сделано для того, чтобы с помощью меню Render можно было изменять используемый метод визуализации. Также обратите внимание, что указатель chalicebuilder не освобождается в функции CreateScene(). Если мы освободим указатель chalicebuilder, то у нас не останется способа изменить метод визуализации во время работы программы.
Следующий шаг — создание точечного источника света. Сначала для создания источника света применим функцию CreateLightRGB() интерфейса Direct3DRM:
LPDIRECT3DRMLIGHT pointlight; d3drm->CreateLightRGB(D3DRMLIGHT_POINT, D3DVALUE(1.0), D3DVALUE(1.0), D3DVALUE(1.0), &pointlight);Константа D3DRMLIGHT_POINT используется для указания типа создаваемого источника света. Следующие три числовых аргумента сообщают, что мы создаем источник излучающий белый свет. Последний аргумент — это адрес указателя, который будет указывать на новый интерфейс Direct3DRMLight.
Теперь создается сетка, представляющая светлячка:
resinfo.hModule = NULL; resinfo.lpName = MAKEINTRESOURCE(IDR_SPHEREMESH); resinfo.lpType = "MESH"; LPDIRECT3DRMMESHBUILDER flybuilder; d3drm->CreateMeshBuilder(&flybuilder); flybuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL); flybuilder->SetQuality(D3DRMRENDER_WIREFRAME); ScaleMesh(flybuilder, D3DVALUE(0.3));Фактически в программе нет сетки реального светлячка, а для представления светлячка используется просто сетка сферы. Идентификатор ресурса сетки сферы используется при подготовке структуры resinfo. Конструктор сеток создается с помощью функции CreateMeshBuilder() интерфейса Direct3DRM, а затем функция Load() интерфейса Direct3DRMMeshBuilder загружает сетку. Функция SetQuality() используется, чтобы включить для сетки каркасный метод визуализации. Это сделано для того, чтобы сетка была ясно видна на сцене. Вспомните, что каркасный метод визуализации использует при изображения сетки только ее цвет и игнорирует любые, включенные в сцену источники света. Использование каркасного метода приводит к тому, что сетка будет точно того цвета, который указан для нее, и никакие дополнительные вычисления цвета не требуются. Потом конструктор сеток масштабируется с помощью функции ScaleMesh().
На пятом этапе создаются два фрейма, которые мы будем использовать для анимации источника света и сферической сетки:
LPDIRECT3DRMFRAME dummyframe; d3drm->CreateFrame(scene, &dummyframe); dummyframe->SetRotation(scene, D3DVALUE(0), D3DVALUE(1), D3DVALUE(0), D3DVALUE(.08)); LPDIRECT3DRMFRAME lightframe; d3drm->CreateFrame(dummyframe, &lightframe); lightframe->SetPosition(dummyframe, D3DVAL(15), D3DVAL(6), D3DVAL(0)); lightframe->AddLight(pointlight); lightframe->AddVisual(flybuilder); flybuilder->Release(); flybuilder = 0; lightframe->Release(); lightframe = 0; dummyframe->Release(); dummyframe = 0; pointlight->Release(); pointlight = 0;Указатель dummyframe инициализируется функцией CreateFrame() интерфейса Direct3DRM и является прямым потомком корневого фрейма сцены (scene). Новому фрейму назначается вращение вокруг оси Y. Это приведет к тому, что его дочерние фреймы (например, тот, который мы создадим чуть позже) тоже будут вращаться вокруг оси Y.
Второй фрейм (lightframe) создается как потомок фрейма dummyframe. Потом вызывается функция SetPosition(), чтобы переместить новый фрейм от начала координат. Если мы не переместим этот фрейм, он будет вращаться на одном месте, вместо того, чтобы перемещаться по орбите вокруг пустого фрейма.
Теперь к фрейму lightframe присоединяются сферическая сетка и источник света. Это гарантирует, что источник света и светлячок будут находиться в одной и той же точке пространства.
В конце все четыре указателя (два указателя на фреймы, указатель flybuilder и указатель pointlight) освобождаются и обнуляются.
Оставшаяся часть функции FireflyWin::CreateScene() (см. листинг 6.2) создает для приложения порт просмотра. Мы подробно изучим порты просмотра в главе 9.