4. Освещение.

4.1. Компоненты света и материалы.

    Свет в Direct3D состоит из трех компонент: фоновый свет, рассеиваемый свет и отраженный свет. Фоновый свет освещает всю сцену. Он состоит из совокупности света, отраженного всеми поверхностями объектов сцены. Рассеиваемый свет распространяется в определенном направлении. Сталкиваясь с объектом, он отражается во всех направлениях (рассеивается в пространстве). Отражаемый свет, при столкновении с поверхностью, формирует на ней блики. Этот тип света требует большего объема вычислений, чем остальные два, поэтому Direct3D позволяет его отключить (вернее, подключить, так как по умолчанию он не используется).

    рDevice->SetRenderState(D3DRS_SPECULARENABLE, true);

    В Direct3D компоненты света задаются, фактически, своим цветом (то есть структурами D3DCOLORVALUE или D3DXCOLOR). При использовании D3DXCOLOR альфа-канал не учитывается.

    Как известно, яблоко имеет зеленый цвет потому, что их кожура поглощает все лучи, кроме зеленых. В Direct3D подобный эффект моделируется заданием материала для объекта. Материал задает цвет, тип и количество отражаемого света. Он инициализируется структурой D3DMATERIAL9.

    typedef struct _D3DMATERIAL9 {
       D3DCOLORVALUE Diffuse, Ambient, Specular, Emissive;
       float Power;
    } D3DMATERIAL9;

    Diffuse - рассеиваемый свет.
    Ambient - фоновый свет.
    Specular - отражаемый свет.
    Emissive - собственное свечение объекта.
    Power - резкость отражений.

При визуализации, материал объекта задается с помощью метода IDirect3DDevice9::SetMaterial(CONST D3DMATERIAL9* pMaterial). Вот пример задания материала:

    D3DMATERIAL9 green, red;

    //задаем один материал
    рDevice->SetMaterial(&green);
    //рисуем зеленые яблоки...

    //задаем другой материал
    рDevice->SetMaterial(&red);
    //рисуем красные яблоки...

4.2. Задание освещения.

    Для того, чтобы Direct3D мог правильно рассчитать освещение сцены, нам придется усовершенствовать нашу структуру с описанием вершины, добавив туда координаты нормали (или задав её как D3DXVECTOR3). Также, нам придется изменить формат вершин (FVF).

    struct NormalVertex
    {
       float x, y, z;
       float nx, ny, nz;//координаты нормали
       static const DWORD FVF;
    }
    const DWORD NormalVertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL;

    Нормаль точки можно рассчитать как среднее арифметическое нормалей к граням, содержащим эту точку.

    Direct3D поддерживает три типа источников света. Точечный источник испускает лучи во всех направлениях (например: солнце). Источник направленного света испускает параллельные лучи в строго определенном направлении (например: солнечный зайчик от зеркала). Источник зонального света испускает конический сноп лучей в заданном направлении (например: фонарик). Любой источник света задается структурой D3DLIGHT9.

    typedef struct _D3DLIGHT9 {
       D3DLIGHTTYPE Type;
       D3DCOLORVALUE Diffuse;
       D3DCOLORVALUE Specular;
       D3DCOLORVALUE Ambient;
       D3DVECTOR Position;
       D3DVECTOR Direction;
       float Range;
       float Falloff;
       float Attenuation0;
       float Attenuation1;
       float Attenuation2;
       float Theta;
       float Phi;
    } D3DLIGHT9;

    Type - тип источника света(D3DLIGHT_POINT, D3DLIGHT_SPOT, D3DLIGHT_DIRECTIONAL).
    Diffuse, Specular, Ambient - цвета составляющих света.
    Position - позиция источника света (для направленного света не используется).
    Direction - направление испускаемых лучей (для точечного света не используется).
    Остальные параметры задают некоторые физические характеристики света и используются довольно редко.

    После инициализации, нам остается только зарегистрировать источник света в списке источников, управляемых Direct3D, и включить его.

    //регистрируем
    рDevice->SetLight(
       n, //номер источника
       &light); //указатель на источник

    //включаем
    Device->LightEnable(n, true);

    Пример приложения: "Освещенная пирамида"