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

         

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


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

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

BOOL ZoomWin::CreateScene() { // ------- СЕТКА -------- D3DRMLOADRESOURCE resinfo; resinfo.hModule = NULL; resinfo.lpName = MAKEINTRESOURCE(IDR_Z_MESH); resinfo.lpType = "MESH"; d3drm->CreateMeshBuilder(&meshbuilder); meshbuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL); meshbuilder->SetColorRGB(D3DVALUE(.67), D3DVALUE(.82), D3DVALUE(.94)); ScaleMesh(meshbuilder, D3DVALUE(25)); // ------- МАТЕРИАЛ ---------- LPDIRECT3DRMMATERIAL material; d3drm->CreateMaterial(D3DVALUE(10), &material); meshbuilder->SetMaterial(material); material->Release(); material = 0; // ------ ФРЕЙМ СЕТКИ ------ LPDIRECT3DRMFRAME meshframe; d3drm->CreateFrame(scene, &meshframe); meshframe->SetRotation(scene, D3DVALUE(1), D3DVALUE(.4), D3DVALUE(0), D3DVALUE(.1)); meshframe->AddVisual(meshbuilder); meshframe->Release(); meshframe = 0; // ------- АНИМАЦИЯ -------- d3drm->CreateAnimation(&animation); animation->SetOptions(D3DRMANIMATION_SPLINEPOSITION | D3DRMANIMATION_CLOSED | D3DRMANIMATION_POSITION); animation->AddPositionKey(D3DVALUE(0), D3DVALUE(.4), D3DVALUE(0), D3DVALUE(0)); animation->AddPositionKey(D3DVALUE(24), D3DVALUE(5), D3DVALUE(0), D3DVALUE(0)); animation->AddPositionKey(D3DVALUE(49), D3DVALUE(1), D3DVALUE(0), D3DVALUE(0)); animation->AddPositionKey(D3DVALUE(74), D3DVALUE(5), D3DVALUE(0), D3DVALUE(0)); animation->AddPositionKey(D3DVALUE(99), D3DVALUE(.4), D3DVALUE(0), D3DVALUE(0)); d3drm->CreateFrame(scene, &zoomframe); animation->SetFrame(zoomframe); // --------- СВЕТ -------- LPDIRECT3DRMLIGHT dlight; d3drm->CreateLightRGB(D3DRMLIGHT_DIRECTIONAL, D3DVALUE(1.00), D3DVALUE(1.00), D3DVALUE(1.00), &dlight); LPDIRECT3DRMLIGHT alight; d3drm->CreateLightRGB(D3DRMLIGHT_AMBIENT, D3DVALUE(.40), D3DVALUE(.40), D3DVALUE(.40), &alight); LPDIRECT3DRMFRAME lightframe; d3drm->CreateFrame(scene, &lightframe); lightframe->SetOrientation(scene, D3DVALUE(0), D3DVALUE(-1), D3DVALUE(1), D3DVALUE(0), D3DVALUE(1), D3DVALUE(0)); lightframe->AddLight(dlight); lightframe->AddLight(alight); dlight->Release(); dlight = 0; alight->Release(); alight = 0; lightframe->Release(); lightframe = 0; //------ КАМЕРА ---------- d3drm->CreateFrame(scene, &camera); camera->SetPosition(scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(-50)); d3drm->CreateViewport(device, camera, 0, 0, device->GetWidth(), device->GetHeight(), &viewport); camera->AddMoveCallback(AdjustField, NULL); return TRUE; }

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

  1. Создает и загружает сетку.
  2. Создает материал и применяет его к сетке.
  3. Создает фрейм для сетки.
  4. Конструирует анимационную последовательность, которая будет применяться для управления полем зрения порта просмотра.
  5. Создает два источника света.
  6. Создает порт просмотра и устанавливает функцию обратного вызова.

На первом этапе мы воспользуемся интерфейсом Direct3DRMMeshBuilder чтобы загрузить сетку из файла. Давайте еще раз взглянем на код:

D3DRMLOADRESOURCE resinfo; resinfo.hModule = NULL; resinfo.lpName = MAKEINTRESOURCE(IDR_Z_MESH); resinfo.lpType = "MESH"; meshbuilder->Load(&resinfo, NULL, D3DRMLOAD_FROMRESOURCE, NULL, NULL); meshbuilder->SetColorRGB(D3DVALUE(.67), D3DVALUE(.82), D3DVALUE(.94)); ScaleMesh(meshbuilder, D3DVALUE(25));

Структура D3DRMLOADRESOURCE используется для идентификации элемента ресурсов приложения, содержащего сетку. Член данных meshbuilder инициализируется функцией CreateMeshBuilder() интерфейса Direct3DRM. Затем вызывается функция Load(), которая и загружает сетку. Цвет сетки назначается с помощью функции SetColorRGB(). После выполнения всех этих действий сетка масштабируется до размера в 25 единиц с помощью функции ScaleMesh().

Теперь к сетке применяется материал:

LPDIRECT3DRMMATERIAL material; d3drm->CreateMaterial(D3DVALUE(10), &material); meshbuilder->SetMaterial(material); material->Release(); material = 0;

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

СОВЕТ Тестирование параметров материала. Xpose — это законченная программа просмотра объектов, созданная с использованием рассмотренных в этой книге технологий. И исходный код и исполняемый файл этой программы содержатся на прилагаемом к книге CD-ROM. Самый быстрый способ познакомиться с параметрами материала и тем, какое влияние они оказывают на внешний вид сетки — провести несколько экспериментов с программой Xpose. Диалоговое окно Material Settings программы Xpose позволяет изменить параметры материала и сразу же увидеть результат.

Для создания материала используется функция CreateMaterial() интерфейса Direct3DRM. Новый материал применяется к сетке с помощью функции SetMaterial() интерфейса Direct3DRMMeshBuilder. После выполнения этих действий локальный указатель material освобождается.

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

LPDIRECT3DRMFRAME meshframe; d3drm->CreateFrame(scene, &meshframe); meshframe->SetRotation(scene, D3DVALUE(1), D3DVALUE(.4), D3DVALUE(0), D3DVALUE(.1)); meshframe->AddVisual(meshbuilder); meshframe->Release(); meshframe = 0;

Фрейм создается функцией CreateFrame() интерфейса Direct3DRM. С помощью функции SetRotation() новому фрейму назначаются атрибуты вращения. Назначение атрибутов является единственной технологией, используемой для анимации фрейма сетки. Во время работы программы фрейм остается в начале координат (позиции по умолчанию). После того, как конструктор сеток будет присоединен к новому фрейму с помощью функции AddVisual(), указатель meshframe освобождается.

Затем конструируется анимационная последовательность, которая будет использоваться для управления полем зрения порта просмотра. Выполняющий эти действия код выглядит так:

d3drm->CreateAnimation(&animation); animation->SetOptions(D3DRMANIMATION_SPLINEPOSITION | D3DRMANIMATION_CLOSED | D3DRMANIMATION_POSITION); animation->AddPositionKey(D3DVALUE(0), D3DVALUE(.4), D3DVALUE(0), D3DVALUE(0)); animation->AddPositionKey(D3DVALUE(24), D3DVALUE(5), D3DVALUE(0), D3DVALUE(0)); animation->AddPositionKey(D3DVALUE(49), D3DVALUE(1), D3DVALUE(0), D3DVALUE(0)); animation->AddPositionKey(D3DVALUE(74), D3DVALUE(5), D3DVALUE(0), D3DVALUE(0)); animation->AddPositionKey(D3DVALUE(99), D3DVALUE(.4), D3DVALUE(0), D3DVALUE(0)); d3drm->CreateFrame(scene, &zoomframe); animation->SetFrame(zoomframe);

Сначала с помощью функции CreateAnimation() интерфейса Direct3DRM создается анимация. Затем вызывается функция SetOptions() интерфейса Direct3DRMAnimation чтобы задать параметры анимации. Мы используем константу D3DRMANIMATION_SPLINEPOSITION чтобы указать, что желаем получить сплайновую анимацию (а не линейную). Этот параметр может быть изменен с помощью меню Animation приложения Zoom. Константа D3DRMANIMATION_CLOSED указывает, что анимационная последовательность должна непрерывно повторяться. Это позволяет использовать непрерывно увеличивающиеся значения времени для повторного выполнения анимационной последовательности. Константа D3DRMANIMATION_POSITION указывает, что анимационная последовательность будет изменять только местоположение объекта (мы не используем константу D3DRMANIMATION_SCALEANDROTATION поскольку, как вы вскоре увидите, мы не используем анимацию для изменения вращения или масштаба объекта).

Затем с помощью функции AddPositionKey() к анимации добавляются пять позиционных ключей. Первым аргументом функции AddPositionKey() является значение, указывающее в какой момент времени данный ключ должен вступить в действие. Оставшиеся три аргумента задают связанную с новым ключом позицию. Обратите внимание, что устанавливаемые ключи отличаются только значением координаты по оси X. Эта ось выбрана произвольно. Мы могли бы использовать оси Y или Z, поскольку мы создаем линейную, или одномерную, анимационную последовательность. Мы будем использовать в анимационной последовательности только ось X.

Затем создается фрейм с именем zoomframe. Новый фрейм присоединяется к анимационной последовательности с помощью функции SetFrame() интерфейса Direct3DRMAnimation.

Фрейм zoomframe является пустым, но он используется не так, как использовались пустые фреймы в приложениях Firefly (глава 6) или Decal (глава 5). Этот пустой фрейм не будет использоваться как родитель для других фреймов. Вместо этого он будет анимироваться созданной ранее анимационной последовательностью, а его координаты будут применяться для установки параметров поля зрения порта просмотра. Обратите внимание, что значение координаты по оси X в анимационной последовательности изменяется в диапазоне от 0.4 до 5.0. Эти значения не будут интерпретироваться как позиции. Вместо этого, они будут использоваться в качестве параметров поля зрения и передаваться в аргументах функции SetField() интерфейса Direct3DRMViewport.

Возвратимся к шести этапам работы функции CreateScene(). На пятом этапе создаются два источника света. Мы пропустим обсуждение этого этапа. Источники света были предметом обсуждения в главе 6.

На шестом, завершающем этапе, выполняется создание порта просмотра:

d3drm->CreateFrame(scene, &camera); camera->SetPosition(scene, D3DVALUE(0), D3DVALUE(0), D3DVALUE(-50)); d3drm->CreateViewport(device, camera, 0, 0, device->GetWidth(), device->GetHeight(), &viewport); camera->AddMoveCallback(AdjustField, NULL); return TRUE;

Сначала создается и размещается фрейм camera. Затем этот фрейм передается в аргументе функции CreateViewport() интерфейса Direct3DRM. Последнее, что делает функция CreateScene() — установка функции обратного вызова AdjustField() с помощью функции AddMoveCallback(). Для установки функции обратного вызова мы используем фрейм camera, но с тем же успехом может быть использован любой другой фрейм сцены.



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