KnigaRead.com/

Михаил Краснов - Графика DirectX в Delphi

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Михаил Краснов, "Графика DirectX в Delphi" бесплатно, без регистрации.
Перейти на страницу:

end;


Положение точки зрения и параметры матриц я подобрал с помощью пройденного нами примера с осями координат.

При движении курсора мыши с нажатой кнопкой видовая матрица пересчитывается в соответствии с положением курсора:


procedure TfrmDSD.FormMouseDown(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

Down := True; // Кнопка нажата, флаг устанавливается

оХ := X; // Запомнили положение курсора

oY := Y;

end;


procedure TfrmD3D.FormMouseUp(Sender: TObject; Button: TMouseButton;

Shift:. TShiftState; X, Y: Integer);

begin

Down : = False; // Кнопка отпущена, флаг сбрасывается

end;


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

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-файлов является то, что это открытый формат, и поддерживается он практически всеми моделирующими программами. Недостатки таковы:


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

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

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*