netlib.narod.ru< Назад | Оглавление | Далее >

Точечный свет

Точечный источник света испускает лучи света из одной точки во всех направлениях. Он подобен источникам света, к которым мы привыкли в обычной жизни, например, электрической лампочке. Привычное поведение точечного источника света делает его естественным выбором для многих ситуаций. Точечный источник света зависит от местоположения, но игнорирует ориентацию (поскольку световые лучи испускаются во всех направлениях).

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

Приложение Firefly

В приложении Firefly точечный источник света применяется для освещения чаши. Чаша помешена в начало координат, а источник света перемещается вокруг нее. Вместе с источником света перемещается небольшая сферическая сетка, что создает иллюзию, будто именно эта сфера (светлячок) испускает лучи и освещает чашу. Помните, что сфера добавлена только ради визуального эффекта. Вы не можете увидеть точечный источник света (как и любой другой источник света) — вы можете видеть только испускаемый им свет. Вид окна приложения Firefly показан на рис. 6.4.


Рис. 6.4. Приложение Firefly

Рис. 6.4. Приложение Firefly


Если вы запустите приложение Firefly, то увидите, что местоположение источника света влияет на освещение чаши. С помощью меню Render можно изменить метод визуализации. Заметьте, что при использовании каркасного режима визуализации источник света не оказывает никакого влияния на изображение сцены.

В приложении Firefly демонстрируются следующие технологии:

Рассматривая код приложения Firefly мы подробнее обсудим каждую из этих технологий.

Класс FireflyWin

Основная функциональность приложения Firefly реализована в классе FireflyWin, наследуемом от класса RMWin. Определение класса выглядит следующим образом:

class FireflyWin : public RMWin
{
public:
    FireflyWin();
    BOOL CreateScene();
protected:
    //{{AFX_MSG(FireflyWin)
    afx_msg void OnRenderWireframe();
    afx_msg void OnRenderFlat();
    afx_msg void OnRenderGouraud();
    afx_msg void OnUpdateRenderFlat(CCmdUI* pCmdUI);
    afx_msg void OnUpdateRenderGouraud(CCmdUI* pCmdUI);
    afx_msg void OnUpdateRenderWireframe(CCmdUI* pCmdUI);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
private:
    LPDIRECT3DRMMESHBUILDER chalicebuilder;
};

В классе FireflyWin объявлены две открытых функции: конструктор и функция CreateScene(). Конструктор обнуляет переменную класса chalicebuilder:

FireflyWin::FireflyWin()
{
    chalicebuilder = 0;
}

Шесть защищенных функций обеспечивают в приложении Firefly поддержку меню Render.

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

В приложении 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() выполняет следующие действия:

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

Сначала создаем сетку чаши:

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.


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz