Программная реализация построения изображения
При обучении часто встает вопрос о программировании графических приложений ввиду некоторых факторов. Прежде всего, это кажущиеся сложности в инициализации графического модуля. До недавнего времени система программирования Borland Turbo Pascal устанавливалась простым копированием с компьютера на компьютер, при этом не происходило прописывание системных переменных и путей. По этой причине при попытке инициализации графического режима и выходили сообщения об ошибке:15: File not found (GRAPH.TPU) Следующая, более серьёзная причина отказа от использования графики в обучении - создание графических программ отнимает много времени, занимая скудные часы учебного плана, а так же резко увеличивает время разработки приложения. Не менее весомым аргументом является тот факт, что после того как ученики, и, как показывает практика, рядовые пользователи поработают с графическими программами, их уже не заставить использовать в повседневной жизни обычные, текстовые или вычислительные аналоги. Графические программы красивы, ярки, образы хорошо запоминаются, ошибки гораздо легче увидеть, поскольку результат представлен наглядно. Что же касается работы с учащимися, так они намного лучше представляют результат работы графической программы, чем вычислительной, вследствие чего могут намного эффективнее самостоятельно проанализировать результат. При создании графической программы всегда присутствует интрига, порой значительно повышающая мотивацию, что в особенности хорошо в процессе обучения. Основной задачей при создании и выводе объемной графики на экран является преобразование трех координат в две, так как на экран можно вывести лишь 2 координаты. Учитывая, что "структуры данных+ алгоритмы= программы", определим изначально структуры данных.
Чем же является 3D-объект. Наиболее просто его можно представить в виде совокупности точек, комбинируя которые в пары или по тройкам можно в дальнейшем получать соответственно требуемые модели. Таким образом для работы с 3D объектами будет достаточно обычного массив точек: [1..n] of record x,y,z:double end; или [1..n1*3]of double;
В первом случае задан массив точек (record~point) а во втором массив координат, который необходимо интерплитировать как:
((x1,y1,z1),(x2,y2,z2),...,(xi,yi,zi),...,(xn,yn,zn))
Таким образом каждые 3 элемента массива - точка. Организовывая первым способом массивы для хранения координат для фигур создадим пользовательский тип записи (для более удобной работы с координатами): type d=record,y,z: real;;
После чего можно начать ввод координат. Создадим первую фигуру. Это будет простейшая пирамида, состоящая из треугольников. Известно, что она содержит в себе 3 треугольника и 4 вершины. Организуя координаты вершин в массив, относительно некоторой нулевой точки получим конструкцию: tet: array[1..4] of d3d = ((x:50;y:80;z:50), (x:50;y:0;z:80), (x:100;y:0;z:0), (x:0;y:0;z:0));
Аналогично можно поступить, задавая координаты куба. Суть остается прежней, изменится только количество вершин: cub: array[1..8] of d3d = ((x:-50;y:-50;z:50), (x:-50;y:50;z:50), (x:50;y:50;z:50), (x:50;y:-50;z:50), (x:-50;y:-50;z:-50), (x:-50;y:50;z:-50), (x:50;y:50;z:-50), (x:50;y:-50;z:-50)); На данном этапе основные подготовительные операции завершены, и можно приступить непосредственно к реализации построения графики. В первую очередь необходимо инициализировать графический режим: := Detect; (grDriver, grMode,'');:= GraphResult;
На этом этапе предоставим графической системе возможность самостоятельно определить графический режим. Так как современные графические адаптеры, а так же непосредственно видеодисплеи, имеют гораздо большие возможности, всвязи с этим можно предположить, что графическим драйвером будет EGAVGA. Главное при этом иметь необходимый внешний модуль для среды разработки.
В случае, если инициализация прошла успешно, достаточно организовать цикл с постусловием, выполняя его пока пользователь не нажмет на клавишу выхода. В процессе работы приложения, а соответственно основного цикла, должны выполняться следующие действия: установка цвета по умолчанию и отчистка экрана; поворот фигуры на заданный угол, в случае если он задан; отрисовка текущей проекции фигуры; проверка действий пользователя. В структуру цикла следует ввести ряд процедур и функций, упрощающих написание и читаемость кода, а так же для исключения переписывания однотипных участков кода для различных моделей: ErrCode = grOk then{если инициализация графического режима успешна, то }(0); {установка цвета} clrscr;; {процедура отрисовки фигуры}(4000);; {поворот фигур}keypressed then {обработка нажатия клавиши пользователем}:=readkey;;codekey of {были нажаты клавиши отвечающие за вращение} 'w':a1:=4.0; {укажем соответствующие углы поворота} 'a':a2:=4.0; 's':a3:=4.0; 'd':a2:=-4.0; '1':figura:=1; '2':figura:=2;;CodeKey=#27; {выход из цикла по нажатию Esc}
Проанализируем и реализуем процедуру отрисовки объекта в целом. Здесь для каждой фигуры будет свой участок кода, состоящий из процедур отрисовки конкретных граней. У пирамиды имеем 4 грани, у куба 6. Чтобы четко видеть грани объекта, каждой назначаем свой индивидуальный цвет. Но для того чтобы построить грань нужно знать, является ли она видимой, и впоследствии расположить ее по центру экрана. Для проверки видимости введем небольшую функцию проверки грани: TestGran(a, b, c: d3d): boolean;v1, w2, v2, w1, n: real;:=a.x-c.x; v2:=a.y-c.y;:=b.x-c.x;:=b.y-c.y;:=v1*w2-v2*w1; n>0 then:=true {грань видна}:=false; {грань не видна};
Здесь выполняется построение нормали относительно грани, заданной тремя точками. Грань можно представить в виде треугольника для упрощения расчетов, как известно прямоугольник можно разбить на два треугольника. Единственным ограничением будет являться только то, что прямоугольник должен являться выпуклым, в противном случае могут возникнуть «артефакты» при отрисовке граней. Впоследствие выполняется проверка ориентации нормали в соответствие с приложенным способом. Основной нюанс состоит в том, что все точки в вершинах граней задаются в одном направлении - по часовой либо против часовой стрелки. Направление обхода крайне важно соблюдать, иначе существует некоторая вероятность, как отмечалось ранее, получить неверное направление нормали относительно плоскости. Нормаль к треугольнику - это векторное произведение сторон- векторов, образованных вершинами. Нормаль будет располагаться снаружи у всех граней, и по знаку нормали можно судить, видим ли мы лицевую сторону или изнанку. Если скалярное произведение вектора зрения на нормаль плоскости (треугольника в плоскости) меньше или равно 0, значит плоскость (треугольник) повернут к наблюдателю либо изнаночной стороной, либо ребром, и отображать его нет необходимости.
Далее если грань видна, остается вывести ее на экран. Для этих целей применима встроенная в модуль языка Паскаль процедура FillPoly, которой можно передать заранее подготовленные координаты на экране и формат заливки. Процедура FillPoly вычисляет все горизонтальные пересечения, а затем закрашивает многоугольник, используя текущий стиль и цвет закраски, определенные с помощью сопутствующих процедур SetFillStyle и SetFillPattern. Контур многоугольника выделяется текущим цветом и типом линии, установленными при обращении к процедурам SetLineStyle и SetColor. Так как изначально координаты заданы относительно начала координат, необходимо задать некоторое приращение для расположения объекта в видимой части экрана. В данном случае объект будет отображен строго по центру экрана, учитывая что установленная разрешающая способность составляет 640х480 пикселей: (1, col); {определяем тип заполнения }[1].x:=round(p1.x+320);[1].y:=round(p1.y+240);[2].x:=round(p2.x+320);[2].y:=round(p2.y+240);[3].x:=round(p3.x+320);[3].y:=round(p3.y+240);[4].x:=round(p4.x+320);[4].y:=round(p4.y+240);
Так как плоскость отображения двухмерная, для воссоздания проекции на экране достаточно воспользоваться только двумя координатами - х и у, z нам нужна только для определения положения грани - выходит она на передний план или нет. Рассчитывать и отрисовывать программно ее имело смысл только при построении «проволочной модели». Впоследствии остается проверить является ли полученная грань треугольником или четырехугольником и отобразить ее:
if (zar[1].x=zar[4].x) and (zar[1].y=zar[4].y)fillpoly(3, zar)fillpoly(4, zar);
Так как алгоритм проверки и рисования граней довольно универсален, его можно применить для прочих фигур. Данный участок кода в дальнейшем будет применим не раз, соответственно имеет смысл вывести его как некоторую отдельную процедуру (DrawGran). Теперь вызывая процедуру рисования граней и передавая в качестве параметров координаты точек, обходим их по часовой стрелке: (tet[1],tet[2], tet[3],tet[1], 1);(tet[1],tet[3], tet[4],tet[1], 2);(tet[1],tet[4], tet[2],tet[1], 3);(tet[4],tet[3], tet[2],tet[4], 4);
И для куба: (cub[4],cub[3], cub[2],cub[1], 11);(cub[5],cub[6], cub[7],cub[8], 12);(cub[1],cub[2], cub[6],cub[5], 13);(cub[3],cub[4], cub[8],cub[7], 14);(cub[2],cub[3], cub[7],cub[6], 15);(cub[5],cub[8], cub[4],cub[1], 16);
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|