Опубликован: 08.07.2007 | Доступ: свободный | Студентов: 1432 / 183 | Оценка: 4.43 / 4.02 | Длительность: 13:47:00
Специальности: Программист
Лекция 7:

Освещенность и материалы. Построения объектов

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


Именно с помощью нормалей рассчитывается освещенность объекта (граней). Как правило, нормали задаются в каждой вершине примитива.


Поэтому необходимо корректно изменить формат вершин и набор FVF флагов.

C++
struct VERTEX3D
{
    FLOAT x, y, z;
    FLOAT nx, ny, nz;
};
VERTEX3D data[];

#define MY_FVF (D3DFVF_XYZ | D3DFVF_NORMAL);
Pascal
type
  Vertex3D = packed record
      x, y, z: Single;
      nx, ny, nz: Single;
  end;

const
  MY_FVF = D3DFVF_XYZ or D3DFVF_NORMAL;

var 
  data: array of Vertex3D;

Следует заметить, что для правильной освещенности граней объектов все вектора, участвующие в расчете освещенности, должны быть нормированы (длина вектора равна единице). Библиотека Direct3D располагает функцией D3DXVec3Normalize(), которая позволяет привести вектор к единичной длине.

C++
D3DXVECTOR3 direction = D3DXVECTOR3(0.0f, 0.0f,1.0f);
D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &direction );
Pascal
D3DXVec3Normalize( light.Direction, D3DXVector3(0, 0, 1) );

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

C++ device->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE );
Pascal device.SetRenderState(D3DRS_NORMALIZENORMALS, 1 );

Для того, чтобы источник в сцене был активирован нужно проделать следующие шаги. Сначала нужно вызвать процедуру установки (регистрации) нужного источника света. Это реализуется через вызов метода SetLight() интерфейса IDirect3DDevice9. Данный метод имеет два параметра: номер источника (лампы), и второй – указатель на переменную типа D3DLIGHT9. Второй шаг состоит в вызове метода LightEnable() интерфейса IDirect3DDevice9 для включения/выключения нужного источника света. Данный метод имеет два параметра: номер источника и второй – булевская переменная (истина- включение источника, ложь - выключение).

Ниже приведен пример освещения направленным источником света треугольной грани, у которой нормали в каждой вершине одинаковы. При этом положение камеры (наблюдателя) задано точкой (2,2,-2), а направление лучей света – (-2,-2,2).


Как видно в каждом положении грань освещена одинаково (нормали в каждой вершине равны (0, 0, -1) ). Изменив хотя бы одну нормаль вершины, можно добиться того, что грань будет освещаться уже неравномерно. Пусть одна из вершин будет теперь иметь нормаль (1,0,-1). Результат освещенности грани при таких изменениях нормали показан ниже.


Ниже приведены примеры заполнения "нужных" полей для точечного и прожекторного источников света.

Пример для точечного источника света.

C++
D3DLIGHT9 light;
ZeroMemory( &light, sizeof(D3DLIGHT9) );
light.Type = D3DLIGHT_POINT;
light.Diffuse = D3DXCOLOR(1.0f, 0.0f, 0.0f, 0.0f);
light.Position = D3DXVECTOR3(2.0f, 2.0f, -2.0f);
light.Attenuation0 = 1.0f;
light.Range = 100;
Pascal
var  light: TD3DLight9;
...
ZeroMemory(@light, SizeOf(TD3DLight9));
light._Type:=D3DLIGHT_POINT;
light.Diffuse:=D3DXColor(1,1,0,0);
light.Position:=D3DXVector3(2,2,-2);
light.Attenuation0:=1;
light.Range:=100;

Пример для прожекторного источника света.

C++
D3DLIGHT9 light;
ZeroMemory( &light, sizeof(D3DLIGHT9) );
light.Type = D3DLIGHT_SPOT;
light.Diffuse = D3DXCOLOR(1.0f, 0.0f, 0.0f, 0.0f);
light.Position = D3DXVECTOR3(2.0f, 2.0f, -2.0f);
D3DXVECTOR3 direction = D3DXVECTOR3(-2.0f, -2.0f, 2.0f);
D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &direction );
light.Attenuation0 = 1.0f;
light.Range = 100;
light.Phi = D3DX_PI/2;
light.Theta = D3DX_PI /3;
light.Falloff = 1.0f;
Pascal
var  light: TD3DLight9;
...
ZeroMemory(@light, SizeOf(TD3DLight9));
light._Type:=D3DLIGHT_SPOT;
light.Diffuse:=D3DXColor(1,1,0,0);
light.Position:=D3DXVector3(2,2,-2);
D3DXVec3Normalize(light.Direction, D3DXVector3(-2,-2,2));
light.Attenuation0:=1;
light.Range:=100;
light.Phi:=pi/2;
light.Theta:=pi/3;
light.Falloff:=1;