Графика DirectX в Delphi
Шрифт:
procedure TfrmDSD.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var
eyeX, eyeZ : Single; matView : TD3DMatrix;
begin
if Down then begin // При нажатой кнопке мыши
// Величина перемещения курсора по горизонтали
// задает перемещения точки обзора в пространстве по осям X и Z
Angle := Angle + (X - оХ) / 50.0;
// Перемещение курсора по вертикали задает сдвиг по оси Y
sHeight := sHeight + (У - oY) / 15.0;
eyeX := cos(Angle) * 5;
eyeZ := sin(Angle) * 5;
//
SetViewMatrixfmatView, D3DVector(eyeX, sHeight, eyeZ),
D3DVector(0, 0, 0), D3DVector(0, -I, 0));
FD3DDevice.SetTransform(D3DTS VIEW, matView);
// Запомнили новое положение курсора
оХ := X;
oY := Y;
end;
end;
В качестве упражнения "обуйте" человечка в башмаки, для чего постройте параллелепипед, масштабируя куб.
Итак, с помощью цилиндров и кубиков мы можем получить занятные построения, но наверняка трудно удовлетвориться только такими фигурами. Вы уже видели в одном из предыдущих примеров модель чайника и справедливо полагаете, что она создана с использованием редактора, а опорные точки треугольников извлечены мною с помощью каких-то дополнительных средств. Конечно, для масштабных проектов требуются подобные вспомогательные средства, облегчающие процесс разработки будущих элементов сцены. Большинство трехмерных редакторов и программ моделирования объектов позволяют записывать в открытом формате или применять собственные форматы с помощью встраиваемых модулей. Так, к примеру, вы можете использовать распространенный DXF-формат, поддерживаемый большинством трехмерных редакторов, а из файла такого формата легко извлекаются вершины треугольников, образующих модель. В каталоге Ех06 располагается проект, с помощью которого я получил из файла такого формата текстовый файл, содержащий данные о нормалях и треугольниках модели чайника. При запуске приложения запрашиваются имена DXF-файла и файла-результата.
Списки, переменные типа TList, Model и Normals содержат данные о считанных вершинах и вычисленных нормалях:
// Блокировать предупреждения компилятора
//о возможно пропущенной инициализации переменных
{$WARNINGS OFF}
procedure TForml.LoadDXF (const FileName : String);
var
f : TextFile;
wrkstring : String;
group, err : Integer;
xl, x2, yl, y2, zl, z2, x3, y3, z3 : Single;
// Процедура, дополняющая список вектором procedure
AddToList (const X, Y, Z : Single);
var
pwrkVector : ^TD3DVector;
begin
New (pwrkVector);
pwrkVector^ := D3DVector (X, Y, Z) ;
Model.Add (pwrkVector);
end;
begin
AssignFile(f, FileName);
Reset(f);
// Считываем данные из DXF-файла до секции ENTITIES
repeat
ReadLn(f, wrkString);
until (wrkString = 'ENTITIES') or eof(f);
while not eof (f) do begin
ReadLn (f, group); //
ReadLn (f, wrkString); // Идентификатор либо координата
case group of
0: begin
AddToList (хЗ, y3, z3) // Добавляем вершины в список
AddToList (х2, y2, z2)
AddToList (xl, yl, zl)
end;
10: val(wrkString, xl, err)
20: val(wrkString, yl, err)
30: val(wrkString, zl, err)
11: val(wrkString, x2, err)
21: val(wrkString, y2, err)
31: val(wrkString, z2, err)
12: val(wrkString, x3, err)
22: val(wrkString, y3, err)
32: val(wrkString, z3, err)
end;
end;
CloseFile(f);
end;
{$WARNINGS ON}
// Процедура вычисления нормалей к треугольникам списка
Model procedure TForml.CalcNormals;
var
i : Integer;
wrki, vxl, vyl, vzl, vx2, vy2, vz2 : Single;
nx, ny, nz : Single;
wrkVector : TD3DVector;
pwrkVector : ^TDSDVector;
wrkVectorl, wrkVector2, wrkVectorS : TD3DVector;
pwrkVectorl, pwrkVector2, pwrkVectorS : ATD3DVector;
begin
for i := 0 to Model.Count div 3 - 1 do begin pwrkVectorl := Model [i * 3 + 1];
wrkVectorl := pwrkVectorl^; pwrkVector2 := Model [i * 3];
wrkVector2 := pwrkVector2^-
pwrkVector3 := Model [i * 3 + 2];
wrkVectorS := pwrkVector3^;
// Приращения по координатам
vxl = wrkVectorl.X - wrkVector2.X;
vyl = wrkVectorl.Y - wrkVector2.Y;
vzl = wrkVectorl.Z - wrkVector2.Z;
vx2 = wrkVector2.X - wrkVectorS.X;
vy2 = wrkVector2.Y - wrkVectorS.Y;
vz2 = wrkVector2.Z - wrkVectorS.Z;
// Вектор, перпендикулярный центру треугольника
nx := vyl * vz2 - vzl * vy2;
ny := vzl * vx2 - vxl * vz2;
nz := vxl * vy2 - vyl * vx2;
// Получаем вектор единичной длины
wrki := sqrt (nx * nx + ny * ny + nz * nz);
if wrki = 0 then wrki := 1; // Для предотвращения деления на ноль
wrkVector.X := nx / wrki;
wrkVector.Y := ny / wrki;
wrkVector.Z := nz / wrki;
New (pwrkVector);
pwrkVector^ := wrkVector;
Normals.Add (pwrkVector);
end;
end;
procedure TForml.FormCreate(Sender: TObject);
var
i : Integer; t : TextFile;
p : ATD3DVector;
n : "TDSDVector;
begin
if OpenDialogl.Execute then begin
if SaveDialogl.Execute then begin
Model := TList.Create;
Normals := TList.Create;
LoadDxf (OpenDialogl.FileName);
CalcNormals;
Caption := 'Треугольников - ' + IntToStr(Normals.Count);