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

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;

В заголовке окна выводится количество считанных треугольников, ведь эта информация потребуется для дальнейшего кодирования. Результирующий файл не обязательно должен быть текстовым, вы можете закодировать данные. Также с помощью небольших манипуляций вы можете масштабировать модель, чтобы потом, при ее воспроизведении, не тратить на это драгоценное время.

В Internet существует масса ресурсов, содержащих свободно распространяемые модели. Например, на сайте http://www.3dcafe.com находятся сотни DXF-файлов моделей самой разнообразной тематики, и некоторыми из этих моделей я воспользовался при подготовке примеров настоящей книги. Если же нужная вам модель записана в другом формате, вы можете воспользоваться импортирующей программой.

Таких программ существует множество, я могу порекомендовать 3D Exploration, разработанную компанией X Dimension Software. Эта программа поддерживает огромный набор форматов и поэтому заслуживает вашего внимания.

С любезного разрешения авторов программы, я поместил на компакт-диск, прилагаемый к книге, демонстрационную версию продукта, которую скачал с сайта http://www.xdsoft.com/explorer.

Должен предупредить все ваши возможные вопросы о проблемах с конкретными DXF-файлами. Прежде всего, редактор или импортирующая программа, в которых создан файл, должны уметь разбивать поверхность модели на отдельные треугольники (программа, которую я вам рекомендовал, делает это успешно). В таких файлах самая громоздкая секция следует после фразы ENTITIES, за которой обязан идти большой массив данных, а не короткие фразы.

Вершины треугольников должны перечисляться либо по часовой стрелке, либо против нее. Если по полученному текстовому файлу построить модель у вас не выходит, попробуйте начать разрешение вопросов с того, что отключите отсечение. Если вы уверены, что вершины всех треугольников перечисляются в одинаковом порядке, а вместо модели выводится черный контур, то проблема состоит в вычислении нормали. Обратите внимание, что в коде этого примера при вычислении нормали я поменял порядок перечисления вершин, подобрав такую последовательность, при которой нормали перпендикулярны треугольникам. Поскольку вершин только три, вы не потеряете много времени на поиски подходящего для конкретного DXF-файла порядка. И последнее, что, возможно, вам придется сделать, если вы получаете только черную тень модели, - это поменять направление нормали на противоположное:

wrkVector.X := - nx / wrki;

wrkVector.Y := - ny / wrki;

wrkVector.Z := - nz / wrki;

Мне пришлось столкнуться с тем, что многие корреспонденты обращаются с возникающими проблемами при обработке DXF-файлов, поэтому должен четко ограничить круг действительно серьезных проблем лишь двумя: либо файл не содержит разбиение модели по треугольникам, либо вершины треугольников перечисляются в различном порядке. Во всех остальных случаях решение получить нетрудно.

Достоинствами использования DXF-файлов является то, что это открытый формат, и поддерживается он практически всеми моделирующими программами. Недостатки таковы:

* модель строится по отдельным, независимым треугольникам, что приводит к избыточности данных; это текстовый формат, поэтому для больших моделей получаются файлы гигантских размеров.

Однако в наших примерах эти файлы нужны только при подготовке кода, непосредственно при работе приложения они не применяются, и нет необходимости распространять их вместе с приложением. Наши примеры загружают данные модели из текстового файла. Полученные текстовые файлы, конечно, тоже имеют большие размеры, но помните, что вы не обязаны использовать именно текстовые файлы. Записывайте данные в виде вещественных значений, и объем файла сразу же значительно уменьшится.

А теперь перейдем к следующему примеру, проекту каталога Ех07 - несложной заготовке увлекательной игры. Вам остается только развить программу, чтобы получить законченное произведение, со стрельбой и коварными противниками, а пока что сюжет игры совсем прост: космический корабль мчится в пространстве, наполненном сферами (рис. 9.8).

Уже сейчас пример во многом напоминает профессиональный продукт: существует полноэкранный режим. Для управления положением космического корабля используется библиотека Directlnput.

Модели сферы и космического корабля загружаются из текстовых файлов, их я получил с помощью изученных утилит.

Поскольку операции с матрицами осуществляются центральным процессором, а именно нашим приложением, оптимизации их выполнения необходимо уделять максимум внимания. Для каждой движущейся сферы запоминаем текущую матрицу трансформаций, чтобы не тратить время на ее инициализацию при очередном обновлении кадра:

type

TSPHERE = packed record // Запись, относящаяся к отдельной сфере

Z : Single; // Текущая координата по оси Z

Radius : Single; // Радиус

MaterialSphere : TD3DMaterial8; // Индивидуальный материал

matSphere : TDSDMatrix; // Текущая матрица трансформаций сферы