Type := D3DLIGHT POINT;
Diffuse.r := 0.4; // Поскольку присутствует три источника,
Diffuse.g := 0.4; // их яркость задается небольшой
Diffuse.b := 0.4;
Specular := Diffuse;
Ambient := Diffuse;
Position := D3DVector(0.5, 0.75, 1.5);
AttenuationO := 1.0;
Attenuationl := 1.0;
Attenuation2 := 0.0;
Range := 2.56; end;
ZeroMemory(@Light1, SizeOf(Light1));
with Lightl do begin
_Type := D3DLIGHT_POINT;
Diffuse.r := 0.4;
Diffuse.g := 0.4;
Diffuse.b := 0.4;
Specular := Diffuse;
Ambient := Diffuse;
Position := D3DVector(0.5, 0.3, 0.3);
AttenuationO := 1.0;
Attenuationl := 1.0;
Attenuation2 := 0.0;
Range := 2.5;
end;
ZeroMemory(@Light2, SizeOf(Lightl));
with Light2 do begin
_Type := D3DLIGHT_POINT;
Diffuse.r := 0.4;
Diffuse.g := 0.4;
Diffuse.b := 0.4;
Specular := Diffuse;
Ambient := Diffuse;
Position := DSDVector(0.5, -0.3, 0.3);
AttenuationO := 1.0;
Attenuationl := 1.0;
Attenuation2 := 0.0;
Range := 2.5;
end;
// Один направленный источник света
Lights:=InitDirectionalLight(DSDVector(-0.5, -0.5, -1),
1.0, 1.0, 1.0, 0);
// Источники только инициализируются, но пока не включаются
with FDSDDevice do begin SetLight(0, LightO);
SetLight(1, Lightl);
SetLight(2, Light2);
SetLight(3, Light3);
end;
end;
При рисовании объектов включаем только определенные источники света:
procedure TfrmD3D.DrawScene;
begin
// Стены комнаты - 10 независимых треугольников
with FD3DDevice do begin
// Матрица идентичности возвращает в мировую систему координат
SetTransform(D3DTS_WORLD, IdentityMatrix);
SetMaterial(Materialwhite); // Стены из белого материала
LightEnable(0, True); // Работают только точечные источники
LightEnabled, True);
LightEnable (2, True);
LightEnable(3, False); // Направленный источник выключаем
DrawPrimitive(D3DPT_TRIANGLELIST, 0, 10);
end;
// Конус и сфера освещаются только направленным источником with FDSDDevice do begin
LightEnable(0, False);
LightEnabled, False);
LightEnable(2, False);
LightEnable(3, True);
SetMaterial(MaterialConus); // Синий материал конуса
SetTransform(D3DTS_WORLD, matCone); // Неизменное положение конуса
DrawPrimitive(D3DPTJTRIANGLEFAN, 30, 49); // Сам конус
DrawPrimitive(D3DPT_TRIANGLEFAN, 81, 49); // Основание конуса
end;
// Перемещаем сферу в новое положение
matSphere._41 := cos (Angle) / 2; // Меняем только два элемента
matSphere._43 := sin (Angle) / 2; // текущей матрицы трансформаций
// Вывод сферы; источник света - текущий, направленный
with FDSDDevice do begin
// Переносим систему координат
SetTransform(D3DTS_WORLD, matSphere);
SetMaterial(MaterialSphere) ;
DrawPrimitive(D3DPTJFRIANGLELIST, 30 + 51 + 51, 1200);
end;
end;
Обратите внимание, что среди задаваемых режимов воспроизведения появилось что-то новое для нас.
with FD3DDevice do begin
// Все вершины примитивов перечисляются по часовой стрелке
SetRenderState(D3DRS_CULLMODE, D3DCOLL_CCW);
SetRenderState(D3DRS_ZENABLE, D3DZBJTRUE);
SetRenderState(D3DRS_AMBIENT, S00202020);
SetRenderState{D3DRS_LIGHTING, Dword (True));
// Конус масштабируется, поэтому включаем пересчет нормалей
SetRenderState(D3DRS_NORMALIZENORMALS, DWORD (True));
end;
Включение режима DSDRS_AMBIENT равносильно включению дополнительного источника света, эмулирующего окружающую среду. Свет этого рассеянного источника излучается из всех направлений. Предназначен такой источник для передачи присутствия на сцене, в данном случае, воздуха, в котором лучи света рассеиваются во всех направлениях.
Записи, определяющие источник света и материал, содержат поля Diffuse, Ambient и specular. Первая структура соответствует диффузным свойствам объекта: для источника света это светофильтр, накладываемый на него; для материала это непосредственно цвет материала, та составляющая падающего света, которая не поглощается поверхностью. Это самая весомая составляющая получающегося цвета. Вторая, рассеянная составляющая проявляется в областях, примыкающих к области, на которую непосредственно падает свет. Используется она в комбинации с третьей, зеркальной составляющей для передачи таких свойств, как гладкость или матовость. Комбинируя значения этих составляющих, можно получать яркие или тусклые блики на поверхности объекта.
Разницы в том, задаются оптические свойства материала или источника, нет, но вы можете комбинировать свойства источника и материала для того, чтобы передать, что на сцене присутствуют, например, светящиеся объекты и объекты с обычными свойствами.
Проект из каталога Ех03 наглядно демонстрирует смысл атрибутов свойств материала и источника света. Это развитие примера с тором. Теперь мы можем произвольно задавать значения всех параметров (рис. 10.3).
При нажатии кнопок вызывается стандартный диалог задания цвета. Выбранный пользователем цвет устанавливается в качестве параметров источника света или материала. Обратите внимание, как подготавливается диалог:
procedure TfrmD3D.Button2Click(Sender: TObject);
begin
// Предоставляем пользователю увидеть установленный диффузный цвет
ColorDialogl.Color :=
Round(MaterialTorus.Diffuse.R * 255) +
Round(MaterialTorus.Diffuse.G * 255 * $100) +
Round(MaterialTorus.Diffuse.В * 255 * $10000);
if ColorDialogl.Execute then
with MaterialTorus.Diffuse do begin
R := (ColorDialogl.Color and SFF) / 255;
G := ((ColorDialogl.Color and 3FFOO) shr 8) / 255;
В := ((ColorDialogl.Color and SFFOOOO) shr 16) / 255;
end;
end;
По умолчанию зеркальная составляющая в расчет не принимается, блики на поверхностях объектов не появляются. Чтобы учесть ее, надо включить режим D3DRS_SPECULARENABLE.
Я советую вам внимательно поработать с этим примером. Для начала по отдельности включите одну из трех составляющих, чтобы увидеть, как они проявляются на поверхности объектов. Назначьте ей белый цвет, а всем остальным - черный, и посмотрите результат.
Этот пример может стать очень полезным в моменты, когда вам потребуется подобрать материал для построений. Ведь наверняка далеко не у каждого из вас под рукой окажется справочник оптических свойств материалов.
После того как вы хорошенько поработаете с этим примером, я хочу обсудить с вами важную проблему, напрямую не относящуюся к основной теме главы. Поговорим с вами на тему выбора объектов. Выбор по цвету, предлагаемый мною в предыдущих примерах, напрямую использовать очень сложно. Если мы вернемся к тестовой сцене с конусом и сферой и внимательно посмотрим на получающуюся картинку, то увидим, что значение пиксела экрана никак не поможет решить задачу выбора: оба объекта имеют
участки черного или очень темного цвета. Даже в таком случае, когда цвета объектов различаются кардинально, их очень тяжело отличать. Например, на поверхности объектов могут появляться блики одинакового цвета. А если на объекты накладывается текстура, или объекты покрашены одинаковым цветом, задача выбора по цвету становится неразрешимой. В случае DirectDraw мы решали подобную проблему использованием вспомогательной поверхности, на которой объекты раскрашивались по произвольной схеме, аналогичный метод можно применять и в Direct3D. Мы можем на вспомогательном, невидимом зрителю экране, повторить построения сцены, окрашивая объекты так, как нам удобно для их идентификации, и ориентироваться при выборе по значению пиксела в определенной точке этого экрана.
Вспомним, что нам системой предоставлены два экрана, передний и задний буферы, причем второй экран скрыт от зрителя до тех пор, пока не вызывается метод Present объекта устройства. Поэтому данным экраном мы можем воспользоваться для наших целей, осуществляя в него построения по нужной схеме, и не выкладывать его содержимое на передний экран. Система предоставляет нам доступ к содержимому заднего буфера, с помощью метода GetBackBuffer объекта устройства, результат помещается в объект типа IDirect3DSurface8.