Графика DirectX в Delphi
Шрифт:
Range := 2.5;
end;
with FD3DDevice do begin SetLight(0, LightO);
SetLight(l, Lightl);
SetLight(2, Light2);
LightEnable(0, True);
LightEnable(1, True);
LightEnable (2, True);
end;
end;
Все объекты сцены, за исключением человечков, освещаются тремя источниками света. При воспроизведении человечков точечный источник выключается.
При воспроизведении сцены голову наблюдателя "помещаем" в точку, соответствующую
procedure TfrmDSD.DrawScene;
var
i : Integer;
matView : TD3DMatrix;
begin
// Видовая матрица, в соответствии с текущими параметрами игрока
SetViewMatrix(matView, D3DVector(XPos, 0.25, ZPos).,
D3DVector (XPos + cos (RotY) ,* 0.25 + Lookupdown,
ZPos - sin (RotY)), ZVector);
with FD3DDevice do begin
SetTransform(D3DTS_VIEW, matView);
SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
SetRenderState(D3DRS_LIGHTING, DWORD (True));
end;
// При необходимости выводим значение
FPS if flgFPS then DrawLetters; // Рисуем человечков
DrawManl; // Красный
DrawMan2; // Синий
DrawMan3; // Зеленый
// Подготовка к рисованию стен
with FD3DDevice do begin
// Учитывать освещение
SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
// Проводить интерполяцию текстур
SetTextureStageState(0,D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
SetTextureStageState(0,D3DTSS_MINFILTER, D3DTEXF_LINEAR);
// He учитывать диффузию треугольников окружения
SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
SetRenderState(D3DRS_AMBIENT, $OOOFOFOF);
// Задаем белый материал
SetMaterial(MaterialWhite);
// Направляем потоки на буфер вершин описания мира
SetStreamSource(0, FD3DVB, SizeOf(TNormDiffTextVertex));
SetVertexShader(D3DFVF_NORMDIFFTEXTVERTEX);
// Координаты треугольников заданы в глобальной системе координат
SetTransform(D3DTS_WORLD, IdentityMatrix);
end;
// Цикл вывода треугольников окружения
for i := 0 to NumTriangles - 1 do with FDSDDevice do begin
// Устанавливаем нужную текстуру в соответствии с описанием
SetTexture(0, FD3DTextures[World [i].NumTexture]);
DrawPrimitive(D3DPT_TRIANGLELIST, i * 3, 1); // Вывод треугольника
end;
FD3Ddevice.SetTexture(0, nil); // Текстура больше не используется
end;
Обратите внимание, что в этом примере задано интерполирование текстур, так называемая билинейная фильтрация. Сделано это для того, чтобы при приближении к ящику и стенам не проявлялась блочность текстур, а изображение не становилось бы крупнозернистым.
Учтите, что использование интерполяции существенно снижает работу приложения, поэтому обычно ее включают только при приближении к поверхности, покрытой текстурой. Другой способ достижения мелкой зернистости - использование
чередующихся текстур. В зависимости от расстояния до объекта на него накладываются текстуры различной детализации.Также я должен напомнить, что для оптимизации работы приложения следует применять запомненные блоки состояний.
Три человечка, присутствующие на сцене, перемещаются по различным законам. Первый, одетый в красную футболку, беспрерывно кружит вокруг центра комнаты:
procedure TfrmD3D.MoveManl;
begin
// Поворот вокруг вертикальной оси
SetRotateYMatrix (rotManl, Angle + Pi);
// Перемещение по кругу
transManl._41 := cos (-Angle) / 2;
transManl._43 := sin(-Angle) / 2;
// Опорная трансформация первого человечка
matManl := MatrixMul(transManl, MatrixMul(rotManl, matWrkl));
Второй человечек пересекает комнату, появляясь из одной стены и исчезая в противоположной:
procedure TfrmD3D.MoveMan2;
begin
// Изменение Х-координаты
transMan2._41 := transMan2._41 - 0.01;
// При прохождении комнаты процесс начинается сначала
if transMan2._41 < -3.1 then transMan2._41 := 3.1;
matMan2 := MatrixMul(transMan2, matWrk2);
Третий человечек назойливо преследует игрока, перемещается в направлении к наблюдателю, всегда разворачиваясь к нему лицом:
procedure TfrmD3D.MoveMan3;
var
wrkAngle : Single;
distX, distZ : Single;
begin
// Расстояния до игрока
distX := XPos - МапЗРозХ;
distZ := ZPos - ManSPosZ;
// Вычисляем угол поворота человечка
if distZ < 0
then wrkAngle := arctan (distX / distZ) - Pi / 2 else
wrkAngle := arctan (distX / distZ) + Pi / 2; // Разворот человечка лицом к игроку
SetRotateYMatrix (rotMan3, wrkAngle);
// Если человечек удален от зрителя, то двигается,в его направлении
if (abs(distX) > 0.02) and (abs (distZ) > 0.02) then begin
МапЗРозХ := МаnЗРозХ + distX / 20; // Новое положение человечка
Man3PosZ := Man3PosZ + distZ / 20;
transMan3._41 := МаnЗРозХ;
transMan3._43 := Man3PosZ;
end;
// Опорная матрица третьего человечка
matMan3 := MatrixMul(transManS, MatrixMul(rotMan3, matWrk2));
Для упрощения вычислений я позволяю человечкам проходить сквозь препятствия и друг через друга. Код предотвращения этих ситуаций очень прост, и вы можете самостоятельно дополнить его отслеживанием таких ситуаций.
Для вывода значения FPS треугольники символов цифр и точки объединены мною в один файл numbers.txt. Процедура piaceLetter определяет в потоке положение и количество треугольников для нужного символа:
procedure TfrmD3D.DrawLetters;
var
i : Integer; nS, nW : Integer;
begin
with FDSDDevice do begin
// Некоторые треугольники построены против часовой
SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
//Не тратить время на освещение