MatrixMul(rotRightFoot, transFootl))); // Поворот левой руки
matLeftHand := MatrixMul(matRot,
MatrixMul(transHand2,
MatrixMul(rotRightFoot, transHandl))); // Поворот правой руки
matRightHand := MatrixMul(matRot,
MatrixMul(transHand2, MatrixMul(rotLeftFoot, transHandl)));
end;
Рабочие матрицы, связанные с перемещениями в точки крепления конечностей, инициализируются один раз, в начале работы приложения:
SetTranslateMatrix(transFootl, О, О, 0.25);
SetTranslateMatrix(transFoot2, О, О, -0.25);
SetTranslateMatrix(transHandl, 0.25, 0.0, -0.23);
SetTranslateMatrix(transHand2, -0.25, 0.0, 0.23);
Этот пример я подготовил для использования в дальнейшем в расчете на то, что человечком можно будет легко управлять, перемещая его в пространстве. Но если на сцене присутствует только одна модель, для оптимизации можно сократить количество операций с матрицами. В самом деле, в этом примере матрица matRot, связанная с глобальной системой координат, может вообще не использоваться: модель можно не вращать и оставить неподвижной, а перемещать точку зрения наблюдателя. Эффект вращения модели останется, а количество операций существенно уменьшится.
И теперь мы можем перейти к разбору заключительного примера - проекта каталога Ех21. Как я уже говорил, это заготовка трехмерной игры: игрок попадает внутрь комнаты, населенной движущимися человечками .
Окружение игрока построено из текстур, накладываемых на треугольники, описание окружающего мира загружается из текстового файла.DirectX.
type
// Формат вершин для треугольников окружения
TNormDiffTextVertex = packed record
X, Y, Z : Single;
nX, nY, nZ : Single;
DColor : DWORD;
U, V : Single;
end;
// Формат вершин для треугольников человечков
TNormVertex = packed record
X, Y, Z : Single;
nX, nY, nZ : Single;
end;
// Отдельный треугольник описания окружения
TTriangle '= record
NumTexture : Integer; // Номер текстуры
DIFFUSE : DWORD; // Диффузная составляющая треугольника
end;
const
// FVF-флаг для треугольников окружения
D3DFVF_NORMDIFFTEXTVERTEX = D3DFVF_XYZ or D3DFVF_NORMAL or
D3DFVF_DIFFUSE or D3DFVFJTEX1; // FVF-флаг для треугольников человечков
D3DFVFJSIORMVERTEX = D3DFVF_XYZ or D3DFVFJTORMAL;
// Имя файла с описанием мира
WorldFile = 'Data/World.txt';
// Имя файла с треугольниками символов, для вывода FPS
NumbersFile = 'Data/Numbers.txt';
// Количество треугольников в описании окружения
NumTriangles = 58;
($1 legoman.pas) // Данные модели
var
frmD3D: TfrmD3D;
Frames : Integer =0; // Счетчик кадров
FpsOut : String = ''; // Значение FPS
// Вспомогательная матрица, для вывода символов FPS
LetTrans : TDSDMatrix;
// Используется как вспомогательный массив для хранения образа текстуры
TexPointer : Pointer;
// Характеристики образа текстуры
wrkTexWidth, wrkTexHeight :
Integer;
// Флаг, выводить ли FPS
flgFPS : BOOL = True;
// Угол зрения по вертикали
Lookupdown : Single = 0.0;
// Вспомогательный вектор для оптимизации
ZVector : TD3DVector;
// Угол зрения по горизонтали и положение игрока
RotY, XPos, ZPos : Single;
// Массив описания мира
World : Array [0..NumTriangles - 1] of TTriangle;
// Переменные для обработки устройств ввода
DInput : IDIRECTINPUT8 = nil;
DIMouse : IDIRECTINPUTDEVICE8 = nil;
DIKeyboard : IDirectlnputDeviceS;
KeyBuffer : TDIKeyboardState;
// Угол поворота красного человечка
Angle : Single = 0.0;
// Угол поворота конечностей человечков
AngleFoot : Single = 0.0;
StepFoot : Single = 0.1;
// Тестовая точка для определения столкновений с препятствиями
TestPointX, TestPointY : DWORD;
В файле описания окружения данных идут в следующем порядке:
строка комментария; номер текстуры; цвет треугольника; три строки описания вершин треугольника, которые включают координаты в пространстве; нормаль и текстовые координаты каждой вершины треугольника.
*
Вот что записано в текстовом файле для первого треугольника:
// Потолок
4
$00FF0000
-3.0 1.0 3.0 0.0 -1.0 0.0 0.0 0.0
-3.0 1.0 -3.0 0.0 -1.0 0.0 0.0 12.0
1.0 3.0 0.0 -1.0 0.0 12.0 0.0
Пол и потолок комнаты представляют собой квадраты с координатами точек углов по диагонали (-3; -3) и (3; 3). Координата Y для всех вершин пола нулевая, для вершин потолка - единичная. При считывании данных предусматриваем обработку исключений на случай отсутствия файла данных или присутствия ошибки при описании треугольников:
procedure TfrmD3D.SetupWorld;
var
t : TextFile;
i, j : Integer;
Vertices : /4TNormDiffTextVertex;
wrkStr : tring;
begin
if FileExists(WorldFile) then begin AssignFile(t, WorldFile);
try
Reset(t); FD3DVB.Lock(0, NumTriangles * 3 * SizeOf(TNormDiffTextVertex),
PByte(Vertices), 0) ;
for i := 0 to NumTriangles - 1 do begin
// Строка комментария, в программе не используется
ReadLn (t, wrkStr) ;
ReadLn (t, World[i].NumTexture); // Текстура треугольника
ReadLn (t, World[i].DIFFUSE); // Цвет вершин треугольника
for j := 0 to 2 do begin // Три вершины треугольника
ReadLn (t, Vertices.X, Vertices.Y, Vertices.Z,
Vertices.nX, Vertices.nY, Vertices.nZ,
Vertices.U, Vertices.V);
Vertices.DColor := World[i].DIFFUSE;
Inc(Vertices);
end;
end;
FD3DVB.Unlock;
except // Данные на треугольник заданы неверно
raise EAbort.Create ('Can''t read file: ' + WorldFile);
end;