Выбрать главу

LetTrans := IdentityMatrix;

LetTrans._42 := 0.5;

LetTrans._43 := 0.9;

// Первоначальные положения человечков

transManl := IdentityMatrix;

transMan2 := IdentityMatrix;

transMan2._41 := 3.1; // Синий человечек перемещается по оси X

transManS := IdentityMatrix;

// Зеленый человечек устанавливается в первоначальное положение

transMan3._41:= МапЗРозХ;

transMan3._43 := ManSPosZ;

// Разворот модели человечков

SetRotateYMatrix (wrkMat, -Pi / 2);

SetRotateXMatrix (matWrkl, -Pi / 2) ;

matWrk2 := MatrixMul (wrkMat, Matwrkl);

matWrk3 := matWrk2;

// Вспомогательные матрицы для поворота конечностей

SetTranslateMatrix(transFootl, 0, 0, -0.1);

SetTranslateMatrix(transFoot2, 0, 0, 0.1);

SetTranslateMatrix(transHandl, 0.25, 0.0, -0.2);

SetTranslateMatrix(transHand2, -0.25, 0.0, 0.2);

SetupLights;

// Первоначальные установки, в дальнейшем переопределяются

SetViewMatrix(matView, D3DVector(0, 0, 0), D3DVector(0, 0, 1),

ZVector);

FDSDDevice.SetTransform(D3DTS_VIEW, matView);

SetProjectionMatrixfmatProj, 1, 1, 0.01, 6) ;

FDSDDevice.SetTransform(D3DTS_PROJECTION, matProj);

// Инициализация текстур

try

InitTexture (FD3DTextures [0], 'data/0.bmp');

InitTexture (FD3DTextures [1], 'data/1.bmp1);

InitTexture (FD3DTextures [2], 'data/2.bmp');

InitTexture (FD3DTextures [3], 'data/3.bmp');

InitTexture (FD3DTextures [4], 'data/4.bmp');

InitTexture (FDSDTextures [5], 'data/5.bmp');

BukupTexture (FD3DTextures [6], 'data/6.bmp1);

except

on E : EAbort do ErrorOut (PChar(E.Message), S_FALSE) ;

end;

OnCreateDevice; // Инициализация устройств ввода

end;

Всего предусмотрено три источника света: два направленных и один точечный, располагающийся под потолком в центре комнаты:

procedure TfrmD3D.SetupLights;

var

LightO : TD3DLight8;

Lightl : TD3DLight8;

Light2 : TD3DLight8;

begin

// Направленные источники светят во взаимно противоположных направлениях

LightO := InitDirectionalLight(D3DVector(-0.5, -0.5, -1) , 0.5,

0.5, 0.5, 0); Lightl := InitDirectionalLight(VectorNormalize(DSDVector(0.5, 0.5, D),

0.5, 0.5, 0.5, 0); // Точечный источник

ZeroMemory(@Light2, SizeOf(Light2));

with Light2 do begin

JType := D3DLIGHT_POINT;

Diffuse.r := 0.5;

Diffuse.g := 0.5;

Diffuse.b := 0.5;

Specular := Diffuse;

Ambient := Diffuse;

Position := DSDVector(0.0, 1.0, 0.0);

Attenuation0 := 1.0;

Attenuationl := 0.0;

Attenuation2 := 0.0;

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;

Все объекты сцены, за исключением человечков, освещаются тремя источниками света. При воспроизведении человечков точечный источник выключается.

При воспроизведении сцены голову наблюдателя "помещаем" в точку, соответствующую его текущему положению в пространстве, и поворачиваем ее в направлении RotY:

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));