Итак, с помощью цилиндров и кубиков мы можем получить занятные построения, но наверняка трудно удовлетвориться только такими фигурами. Вы уже видели в одном из предыдущих примеров модель чайника и справедливо полагаете, что она создана с использованием редактора, а опорные точки треугольников извлечены мною с помощью каких-то дополнительных средств. Конечно, для масштабных проектов требуются подобные вспомогательные средства, облегчающие процесс разработки будущих элементов сцены. Большинство трехмерных редакторов и программ моделирования объектов позволяют записывать в открытом формате или применять собственные форматы с помощью встраиваемых модулей. Так, к примеру, вы можете использовать распространенный 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);
AssignFile (t, SaveDialogl.FileName);
Rewrite (t);
// Запись в текстовый файл результатов
for i := 0 to Normals.Count - 1 do begin
n := Normals.Items [i];
// Первым выводится вектор нормали к треугольнику
WriteLn (t, n.X);
WriteLn (t, n.Y);
WriteLn (t, n.Z);
// Координаты вершин треугольников
р := Model.Items [i * 3};
WriteLn (t, p.X)
WriteLn (t, p.Y)
WriteLn (t, p.Z)
p := Model.Items [i * 3 + I];
WriteLn (t, p.X)
WriteLn (t, p.Y)
WriteLn (t, p.Z)
p := Model.Items [i * 3 + 2];
WriteLn (t, p.X)
WriteLn (t, p.Y)
WriteLn (t, p.Z)
end;
CloseFile (t);
Model. Free ;
Normals.Free ;
end;
end;
end;
В заголовке окна выводится количество считанных треугольников, ведь эта информация потребуется для дальнейшего кодирования. Результирующий файл не обязательно должен быть текстовым, вы можете закодировать данные. Также с помощью небольших манипуляций вы можете масштабировать модель, чтобы потом, при ее воспроизведении, не тратить на это драгоценное время.