Министерство общего и профессионального образования Российской Федерации Уфимский государственный авиационный технически...
21 downloads
200 Views
286KB Size
Report
This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Report copyright / DMCA form
Министерство общего и профессионального образования Российской Федерации Уфимский государственный авиационный технический университет Кафедра технической кибернетики
МЕТОДИЧЕСКИЕ УКАЗАНИЯ к лабораторным работам по курсу "Интерактивная машинная графика" для подготовки инженеров по специальности 220200 "Автоматизированные системы обработки информации и управления" Часть 1 "Синтез графических образов простыми средствами"
Уфа 1997
2 Составитель: О.В. Трушин УДК 681.3.06
Методические указания к лабораторным работам по курсу "Интерактивная машинная графика" для подготовки инженеров по специальности 220200 "Автоматизированные системы обработки информации и управления" Часть 1. "Синтез графических образов простыми средствами" / Уфимск. гос. авиац. техн. унив-т; Сост. О.В. Трушин. - Уфа, 1997. - 34 с.
Приведены задания для лабораторных работ по первой части курса "Интерактивная машинная графика", где рассматривается ряд классических, а также авторских методик и принципов программирования двумерных графических образов с использованием простых алгоритмов. Приводимые алгоритмы реализованы на языке Turbo-Pascal_7 в форме, позволяющей при необходимости легко адаптировать их для других систем программирования. Ил. 15. Библиогр.: 10 наимен.
Рецензенты:
В. Н. Мукасеева М. Е. Сидоров
3 Содержание Стр. Лабораторная работа № 1. Приемы синтеза динамических образов на плоскости ................. 4 Лабораторная работа № 2. Синтез сложных динамических образов ....................................... 9 Лабораторная работа № 3. Простые приемы мультипликации ................................................ 17 Лабораторная работа № 4. Мультипликация с запоминанием части экрана .......................... 26 Список литературы ............................................ .......................... 31 Приложение А Типовые графические функции BGI ............................................. 32
4 Лабораторная работа № 1 ПРИЕМЫ СИНТЕЗА ДИНАМИЧЕСКИХ ОБРАЗОВ НА ПЛОСКОСТИ 1 Цель работы Практическое освоение типовых приемов синтеза динамических графических образов на примере создания программ управления движением набора простых графических объектов. 2 Зрительное восприятие быстрой смены образов Синтез динамических эффектов на экране монитора проводится чередованием набора образов, в той или иной степени моделирующим моменты какого-либо реального физического процесса. При этом для достижения приемлемых результатов следует учитывать психофизические особенности восприятия глазом быстрой смены образов, а также принципы и особенности формирования образов на экране монитора. Приводимые ниже две программы создания эффектов мерцания позволяют понять некоторые из этих принципов. Uses Сrt, Graph; Var Gx,Gy, Gd,Gm, x,y, x1,y1 ,i :integer; begin Gd:=detect; InitGraph(Gd,Gm,'c:\tp7\bgi'); Gx:=GetMaxX; Gy:=GetMaxY; randomize; {-----------------------------------------------------------------------------------"Небо в алмазах" генератор точек с гашением в их окрестности набора точек --------------------------------------------------------------------------------------} Repeat i:=random(7)+9; x:=random(Gx); y:=random(Gy); Putpixel(x,y,i); for i:=0 to random(900) do Putpixel(x-15+random(31),y-15+random(31),0) Until KeyPressed; ReadKey; Cleardevice; {--------------------------------------------------------------------------------------"Мерцание" последовательно высвечиваются и гасятся две случайные точки, из-за инерционности зрения возникает эффект мерцающего набора точек -------------------------------------------------------------------------------------------------------} Repeat i:=random(7)+9; x1:=x; x:=random(Gx); y1:=y; y:=random(Gy); Putpixel(x,y,i); delay(100); Putpixel(x1,y1,0) Until KeyPressed; CloseGraph end.
5 3 Практическое задание 3.1 Модифицировать алгоритм "Небо в алмазах" 3.1.1 Выводить точки в определенную область экрана, например
3.1.2 Выводить точки с сортировкой по цвету в зависимости от ее положения на экране яркость
3.2 Модифицировать алгоритм "Мерцание" 3.2.1 Увеличить "заполненность" экрана, оперируя одновременно с несколькими точками 3.2.2 Организовать "мерцающую волну" с направлением по вариантам п. 3.1.2 4 Синтез динамических эффектов с анализом возможности выполнения процедур Одним из узловых моментов моделирования большинства динамических процессов является установка набора ограничительных условий на выполнение тех или иных элементов этих процессов. Причем эти условия обычно являются весьма точным отображением реальных физических ограничений. Рассмотрим это на примере моделирования некоторых физических процессов. В раздел описаний предыдущих программ добавим const N=500; { число объектов } var X,Y, { массивы координат объектов } vX,vY { массивы скоростей объектов } P: { цвет объектов } array[1..N] of integer; {-------------------------------------------------------------------------------------"Молекулы газа в поле тяготения" динамический процесс с анализом его допустимости. ---------------------------------------------------------------------------------------}
6 for i:=1 to N do begin X[i]:=random(Gx); { начальные координаты "молекул"} Y[i]:=random(Gy) end; REPEAT for i:=1 to N do begin PutPixel(X[i],Y[i],0); { стирание старого изображения } { Генерируем случайные составляющие скорости "молекул" } dX:=-20+random(41); { -20...20 - равновероятно влево и вправо } dY:=-10+random(41); { -10...30 - с тяготением вниз } { Если при выбранной скорости "молекула" не выйдет за границу, то проводится смена ее координат и перерисовка } if( X[i]+dX> 0) and( X[i]+dX< Gx) then inc(X[i],dX); if( Y[i]+dY> 0) and( Y[i]+dY< Gy) then inc(Y[i],dY); PutPixel(X[i],Y[i], 14) end until KeyPressed; ReadKey; ClearDevice; 5 Практическое задание по модификации алгоритма "Молекулы газа в поле тяготения" 5.1 Точки ярких цветов направить к одной из границ экрана, прочие к противоположной границе.
яркие темные
5.2 Смоделировать поведение молекул газа в цилиндре под движущимся поршнем. 5.3 Смоделировать процесс испарения смеси трех жидкостей с разной температурой кипения. 6 Анализ взаимодействия и свойств объектов Следующие фрагменты программы иллюстрируют принцип выполнения графических процедур с анализом области, где моделируется динамический процесс. {-------------------------------------------------------------------------------------"Снег" - перемещение малых объектов с анализом "пути следования" ---------------------------------------------------------------------------------------} for i:=1 to N do begin X[i]:=random(Gx); { начальное положение "снежинок"}
7 Y[i]:=random(Gy); PutPixel(X[i],Y[i],15) end; Rectangle(100,Gy-100, Gx-100,Gy); { преграда } REPEAT for i:=1 to N do begin if(Y[i]
for i:=1 to 300 do begin sound(random(i)); delay(1); nosound
end;
REPEAT { процесс разлета осколков } for i:=1 to N do begin if( X[i]+vX[i]> 0) and( X[i]+vX[i]< Gx)and ( Y[i]+vY[i]> 0) and( Y[i]+vY[i]< Gy) then begin { если осколок еще не долетел до края } PutPixel(X[i],Y[i], 0); inc(X[i],vX[i]); inc(Y[i],vY[i]); PutPixel(X[i],Y[i],12) end { перерисовка в новом положении } else begin vX[i]:=0; vY[i]:=0; end end
{ пиксель долетел до края - обнуляем его скорость и генерируем звук при "ударе" о край } sound(200); delay(2); nosound until KeyPressed
END.
8 7 Практическое задание 7.1 Модифицировать алгоритм "Снег" 7.1.1 Смоделировать снег с ветром переменного направления. 7.1.2 Смоделировать образование "снежных хлопьев" при достижении движущимися пикселями нижней части экрана. 7.1.3 Смоделировать град, соскальзывающий на наклонных преградах. 7.2 Модифицировать алгоритм "Взрыв" 7.2.1 Смоделировать взрыв объекта со снижением скорости осколков в процессе их разлета. 7.2.2 Смоделировать ракету, взрывающуюся при столкновении с препятствием. 7.2.3 Смоделировать две бомбы: осколки от взрыва первой подрывают вторую. 7.2.4 Смоделировать разлет осколков с учетом действия сопротивления воздуха и силы тяжести. 7.2.5 Смоделировать фейерверк (или салют) с ограничением "времени жизни" светящихся осколков.
9 Лабораторная работа № 2 СИНТЕЗ СЛОЖНЫХ ДИНАМИЧЕСКИХ ОБРАЗОВ 1 Цель работы Практическое освоение приемов синтеза динамических графических образов моделированием характеристик физических процессов. 2 Динамические эффекты с корректировками по условиям Простая установка набора ограничительных условий на выполнение тех или иных элементов моделируемых физических процессов обычно является лишь базовым элементом при отображении этих процессов. Более сложной (но и более актуальной) задачей является программирование самих характеристик процесса. Рассмотрим простейшие случаи такого моделирования. {-------------------------------------------------------------------------------------"Волны" динамический процесс с корректировками по граничным условиям ----------------------------------------------------------------------------------------} for i:=1 to N do begin X[i]:=random(Gx); { начальные координаты объектов } Y[i]:=random(40); P[i]:=random(7)+9; { и их цвет } vX[i]:=-2+random(5); vY[i]:=P[i]-6 end; { вертикальная скорость зависит от цвета } REPEAT for i:=1 to N do begin { при достижении границы меняем направление составляющей вектора скорости } if (X[i]+vX[i]<0) or (X[i]+vX[i]>Gx) then vX[i]:=-vX[i]; if (Y[i]+vY[i]<0) or (Y[i]+vY[i]>Gy) then vY[i]:=-vY[i]; PutPixel(X[i],Y[i], 0 ); { стирание старого изображения } inc(X[i],vX[i]); inc(Y[i],vY[i]); { смена координат } PutPixel(X[i],Y[i],P[i]) end { вывод нового изображения } until KeyPressed; ReadKey; ClearDevice; 3 Практическое задание по модификации алгоритма "Волны" 3.1 Создать два перекрещивающихся набора волн по горизонтали и вертикали. 3.2 Организовать поочередную остановку волн на краях экрана в зависимости от их цвета.
10 3.3 Организовать исчезновение элементов волн при совпадении их координат. 4 Динамические эффекты с анализом состояния процесса {-------------------------------------------------------------------------------------"Рой" -динамический процесс с постоянной корректировкой по условию. ---------------------------------------------------------------------------------------} for i:=1 to N do begin X[i]:=random(Gx); { начальные координаты объектов } Y[i]:=random(Gy) end; xc:=1; yc:=Gy div 2; { координаты центра роя } vxc:=3; { и его скорость} REPEAT { Рой меняет направление движения при достижении края экрана } if( xc>Gx)or( xc<0) then vxc:=-vxc; inc(xc,vxc); { смещение центра роя } for i:=1 to N do begin dx:=-25+random(51); dy:=-25+random(51); PutPixel(X[i],Y[i], 0);
{ генерируем случайное изменение } { координат объектов } { и стираем их старые положения }
{ Если смещение элемента роя в случайно сгенерированном направлении возможно, то оно корректируется по направлению к центру роя } if (X[i]+dx> 0 ) and( X[i]+dx< Gx) then begin if (X[i]+dx< xc) then inc(dx,5) else dec(dx,5); inc(X[i],dx) end; if( Y[i]+dy> 0 ) and( Y[i]+dy< Gy) then begin if( Y[i]+dy< yc) then inc(dy,5) else dec(dy,5); inc(Y[i],dy) PutPixel(X[i],Y[i], 14) end until KeyPressed end.
end;
{ новое положение объекта }
5 Практическое задание по модификации алгоритма "Рой" 5.1 Смоделировать разноцветный рой с разными скоростями объектов в зависимости от из цвета. 5.2 Смоделировать два роя разного цвета, центры которых перемещаются с разными скоростями. 5.3 Смоделировать рой с изменяющимися размерами
11 и активностью в процессе его существования. 5.4 Смоделировать движение кометы. 6 Синтез простых трехмерных динамических образов При синтезе трехмерных графических образов обычно объект или набор объектов задается набором пространственных координат своих узловых точек. Затем определяются координаты перспективной проекции этих точек на визуальную плоскость. Ниже приведен простейший алгоритм создания трехмерной динамической сцены, где не стоит задача удаления невидимых частей трехмерного образа ввиду предельной простоты самих объектов (рисунок 1). Задается скорость по оси Z (speed) для набора пикселей. Если какойлибо пиксель выходит из зоны видимости, то для него генерируются новые координаты в дальней части зоны видимости, моделируя перемещение наблюдателя относительно бесконечного набора пикселей. Цвет пикселей по мере приближения ( уменьшения координаты Z ) становится более ярким. {-------------------------------------------------------------------------------------"Межзвездный полет" перспективная проекция движущегося трехмерного образа. ---------------------------------------------------------------------------------------} uses crt,graph; const N=100; { число звезд } view=200; { дистанция просмотра } speed=50; { скорость полета } var x,y,z,_x,_y,color: array[1..N] of integer; i,gm,gd,gx,gy,xc,yc :integer; begin randomize; for i:=1 to N do begin { установка начальных координат звезд } x[i]:=-10*view +random(20*view); y[i]:=-10*view +random(20*view); z[i]:= view +random(20*view) end; gd:=0; initgraph(gd,gm,''); xc:=GetmaxX div 2; yc:=GetmaxY div 2;
speed
Z экран
Y
X
REPEAT { Расчет перспективных проекций звезд и их вывод } for i:=1 to N do { если проекция звезды в пределах экрана } if( z[i]/(abs(x[i])+1) > view/xc)
view
Рисунок 1
12 and( z[i]/(abs(y[i])+1) > view/yc) then begin { вычисление координат с учетом перспективы } _x[i]:=xc +round( x[i]*(view/z[i])); _y[i]:=yc +round( y[i]*(view/z[i])); putpixel(_x[i],_y[i],color[i]) end else { для вышедших из поля зрения звезд переназначаем координаты } z[i]:=view +random(20*view); delay(50); { задержка видимости набора звезд } for i:=1 to N do begin dec( z[i], speed); { смена координат звезд } { цвет зависит от дальности } if z[i]<4*view then color[i]:=14 else if z[i]<9*view then color[i]:=11 else color[i]:= 9 end; { стирание по старым координатам } for i:=1 to N do putpixel(_x[i],_y[i],0); until KeyPressed;
CloseGraph
END.
7 Практическое задание по модификации алгоритма "Межзвездный полет" 7.1 Смоделировать различные типы обзора при "движении среди звезд": боковой, задний, под определенным углом к направлению движения. 7.2 Смоделировать вращение вокруг одной из осей координат при движении. 7.3 Вместо пикселей в качестве объектов использовать какие-либо простые фигуры (например, окружности), задавая увеличение их размера по мере приближения. 8 Моделирование динамического процесса с анализом комплекса граничных условий и состояния движущихся объектов В приведенных выше примерах моделировалось лишь движение объектов как для набора материальных точек, но не рассматривались свойства самих объектов. Рассмотрим процесс с изменением свойств самого движущегося объекта. {-------------------------------------------------------------------------------------"Движение в лабиринте" ---------------------------------------------------------------------------------------} Uses Crt, Graph;
Var
13 Gd,Gm, _x,_y, lx,ly, xc,yc, dx,dy, rx,ry, rx_old, ry_old, i,j: integer; ix,iy: boolean;
begin Gd:=0; Rectangle( 10,10, Rectangle( 90,90, Rectangle( 400,90,
InitGraph(Gd,Gm,'c:\tp7\bgi'); 600,350); { элементы лабиринта } 300,190); 450,290);
dx:= 4; dy:= 3; { составляющие начальной скорости объекта } rx:=10; ry:=10; { начальные размеры объекта } xc:=150; yc:=30; { начальные координаты объекта } Ellipse(xc,yc, 0,360, rx,ry); { объект в начальном положении } lx:= abs(dx)+1; ly:= abs(dy)+1; { число пикселов по ходу движения объекта } REPEAT rx_old:=rx; { запоминание размеров объекта } ry_old:=ry; _x:=dx div abs(dx); { текущие направления движения объекта } _y:=dy div abs(dy); iy:=false; ix:=false; { признаки удара о стенку } for i:=1 to lx do { анализ пути объекта по горизонтали } if GetPixel( xc+(rx+i)*_x, yc)>0 { на пути вертикальная стенка} then begin dx:=-dx; { смена знака горизонтальной скорости } ix:=true; { признак удара о вертикаль } if rx>1 then begin inc(ry); dec(rx) end; { корректировка размеров объекта } { звук удара и прекращение анализа пути } sound(300); delay(9); nosound; break end; for i:=1 to ly do { анализ пути объекта по вертикали } if GetPixel( xc, yc+(ry+i)*_y)>0 { на пути горизонтальная стенка } then begin dy:=-dy; { смена знака вертикальной скорости } iy:=true; { признак удара о горизонталь } if ry>1 then begin inc(rx); dec(ry) end; { корректировка размеров объекта } sound(400); delay(9); nosound; break end; if (not ix) and(not iy) then { Если не было удара о стенки, то анализируем возможность удара во внешний угол }
14 for i:=1 to lx do for j:=1 to ly do if( GetPixel( xc+(rx+i)*_x, yc+(ry+j)*_y)> 0) { удар во внешний угол} then begin dy:=-dy; dx:=-dx; { смена знака обеих составляющих скорости } sound(500); delay(9); nosound; break end; { стирание объекта } SetColor( 0); Ellipse( xc,yc, 0,360, rx_old,ry_old); inc(xc,dx); inc(yc,dy); { смена координат объекта } { вывод нового положения объекта } SetColor(14); Ellipse( xc,yc, 0,360, rx,ry); delay(30) until KeyPressed; CloseGraph end. Смоделируем процесс, в котором определяющим является изменение свойств набора рассматриваемых однотипных объектов. Выводится набор окружностей случайного радиуса и расположения. Затем радиусы окружностей начинают возрастать ( рисунок 2). При касании окружностей меньшая уничтожается. При касании края экрана центр окружности начинает смещаться. Рисунок 2 При составлении подобных программ для получения простой без перегрузки различными условиями модели важно корректно и полно определить набор свойств составляющих модель объектов. {--------------------------------------------------------------------------------------"Мыльные пузыри" ----------------------------------------------------------------------------------------} Uses Crt,Graph; Const N=50; { количество объектов } VAR Gx,Gy, Gm,Gd, i,j: integer; L: real; stop: boolean; {признак остановки процесса} r,dr, { размер объектов и скорость изменения размера} xc,yc: { координаты центров объектов } array[1..N] of longint; good: array[1..N] of boolean; { признак существования объектов} BEGIN Gd:=0; initgraph(Gd,Gm, 'с:\tp7\bgi'); Gx:=GetMaxX; Gy:=GetMaxY; Randomize; { установка начальных параметров объектов } for i:=1 to N do begin R[i]:= 5+random(10); { радиус }
15 dR[i]:= 1+random( 3);
{ скорость роста }
xc[i]:=R[i]+random(Gx-2*R[i]); yc[i]:=R[i]+random(Gy-2*R[i]); end;
good[i]:=true
{ координаты центра }
{ признак существования объекта }
stop:=false; { признак остановки процесса } Repeat for i:=1 to N do { перебор объектов } if good[i] then begin circle(xc[i],yc[i],R[i]); { вывод объектов } for j:=1 to N do { анализ соседей "j" для выбранного объекта } if(j<>i)and(good[j]) then begin { расстояние между центрами объектов } L:=sqrt(sqr(xc[i]-xc[j])+sqr(yc[i]-yc[j])); { если происходит касание объекта "i" с объектом "j" большего радиуса, то рассматриваемый объект "i" уничтожается } if(R[i]+R[j]+dR[i]+dR[j]>=L) and(R[j]>=R[i]) then begin sound(100); delay(10); nosound; good[i]:=false; break end; end{j}; { при достижении края растущий объект отодвигается от этого края } if(xc[i]-R[i]-dR[i]<= 0) then inc(xc[i],dR[i]); if(yc[i]-R[i]-dR[i]<= 0) then inc(yc[i],dR[i]); if(xc[i]+R[i]+dR[i]>=Gx) then dec(xc[i],dR[i]); if(yc[i]+R[i]+dR[i]>=Gy) then dec(yc[i],dR[i]); end{i}; { увеличение размеров объектов с контролем максимального размера } for i:=1 to N do begin if good[i] then inc(R[i],dR[i]); if 2*R[i]>Gy then stop:=true end; delay(100); ClearDevice until (KeyPressed)or(stop)
end.
9 Практическое задание 9.1 Модифицировать алгоритм "Движение в лабиринте" 9.1.1 Смоделировать движение в лабиринте двух разноцветных
16 объектов разной формы. 9.1.2 Смоделировать уменьшение скорости объекта при отражениях от стенок лабиринта. 9.1.3 Изменять цвет стенки лабиринта в месте удара о нее движущегося объекта. 9.1.4 Смоделировать изменение геометрии лабиринта в процессе движения. 9.2 Модифицировать алгоритм "Мыльные пузыри", смоделировав аналогичный процесс эволюции для объектов квадратной формы ( рисунок 3). При касании двух квадратов меньший уничтожается. При касании края экрана рост квадрата прекращается. Рисунок 3
17 Лабораторная работа № 3 ПРОСТЫЕ ПРИЕМЫ МУЛЬТИПЛИКАЦИИ 1 Цель работы Практическое освоение стандартных приемов синтеза динамических образов, не требующих мощных вычислительных ресурсов. 2 Процедуры перемещения и масштабирования фигур Наиболее простой метод имитации сложного движения образа - рисование фигуры как контура на наборе узловых точек с вызовом процедур преобразования координат узловых точек контура. При этом как рисование самой фигуры, так и преобразования координат узловых точек выполняется по простым и быстро работающим алгоритмам, и процесс перерисовки происходит почти незаметно для глаз даже на не слишком мощных ПК. Ниже приведен пример программы с использованием подобных процедур - плоскопараллельного движения, вращения и масштабирования линейчатой фигуры. Набор процедур преобразования координат несложно при необходимости расширить, добавив, например, зеркальные отображения, деформации сдвига, нелинейные деформации. В процедуре рисования фигуры можно использовать не только отрезки прямых линий, но и дуги окружности или эллипса. При необходимости имитации движения по фоновому изображению можно использовать режим вывода SetWriteMode(1) для линейчатых фигур. Массивы координат рассчитываются как реальные числа с целью устранения накопления погрешностей округления при многократном вызове процедур изменения координат. Округление до целых чисел, необходимое при выводе на экран, производится непосредственно в процедуре рисования фигуры. uses crt,graph; const N=4; var x,y: array[1..N] of real;
gd,gm, gx,gy: integer;
PROCEDURE DRAW(color: integer); { Вывод фигуры (рисунок 1) по массиву x,y ее узловых точек } var i,gc: integer; _x,_y: array[1..N] of integer; begin { старый и новый цвета рисования линий } gc:=getcolor; setcolor(color); { округление значений координат } for i:=1 to N do begin Рисунок 1 _x[i]:=round(x[i]);
18 _y[i]:=round(y[i]) end; { рисование } MoveTo(_x[N],_y[N]); for i:=1 to N do LineTo(_x[i],_y[i]); LineTo(_x[2],_y[2]); Line(_x[1],_y[1],_x[3],_y[3]); { восстановление старого цвета рисования } setcolor(gc) end; PROCEDURE MOVE(dx,dy: real); { Перемещение на dx,dy (рисунок 2) по осям координат } var i: integer; begin for i:=1 to N do begin x[i]:=x[i]+dx; y[i]:=y[i]+dy end end; Рисунок 2
dy dx
PROCEDURE ROTATE_C(xc,yc: integer; ug:real); { Поворот (рисунок 3) относительно точки xc,yc на угол ug (град) } var i: integer; xx,yy: real; begin ug:=ug*pi/180; { угол в радианах } ug for i:=1 to N do begin xx:=xc +(x[i]-xc)*cos(ug) c -(y[i]-yc)*sin(ug); yy:=yc +(y[i]-yc)*cos(ug) +(x[i]-xc)*sin(ug); x[i]:=xx; y[i]:=yy end end; Рисунок 3 PROCEDURE ROTATE( ug:real); { Поворот относительно своего центра угол ug (град) } var i:integer; xx,yy,xc,yc: real; begin ug:=ug*pi/180; { перевод угла в радианы } { нахождение центра} xc:=0; yc:=0; for i:=1 to N do begin xc:=xc+x[i]; yc:=yc+y[i] end; xc:=xc/N; yc:=yc/N; for i:=1 to N do begin xx:=xc +(x[i]-xc)*cos(ug) -(y[i]-yc)*sin(ug); yy:=yc +(y[i]-yc)*cos(ug) +(x[i]-xc)*sin(ug); x[i]:=xx; y[i]:=yy end end;
19 PROCEDURE MAS( kx,ky:real); { Масштабирование фигуры (рисунок 4) относительно своего центра } var i: integer; xc,yc: real; begin xc:=0; yc:=0; for i:=1 to N do begin kx xc:=xc+x[i]; yc:=yc+y[i] end; xc:=xc/N; yc:=yc/N; ky for i:=1 to N do begin x[i]:=xc+kx * (x[i]-xc); Рисунок 4 y[i]:=yc+ky * (y[i]-yc) end end; BEGIN { Примеры моделирования движения с использованием процедур } gd:=0; initgraph(gd,gm,''); Gx:=getmaxx; Gy:=getmaxy; x[1]:=gx div 3; y[1]:=gy div 2; x[2]:=x[1]+90; y[2]:=y[1]; x[3]:=x[2]; y[3]:=y[1]+90; x[4]:=x[1]; y[4]:=y[3]; { Плоскопараллельное движение } repeat DRAW(0); { стирание } MOVE(10,1); { изменение координат } DRAW(12); { вывод по новым координатам } delay(300); until (KeyPressed)or(x[1]>(gx-80)); readkey; repeat
{ Двойное вращение с масштабированием }
DRAW(0); ROTATE_C(Gx div 2, Gy div 2, 3); ROTATE(-3-random(8)); if x[1]>300 then MAS(1.02, 1.02) else MAS(0.98, 0.98); DRAW(11); delay(300); until KeyPressed; CloseGraph end.
20 3 Практическое задание по отображению сложного движения 3.1 Колесо с 8 спицами (рисунок 5) катится равномерно без проскальзывания по наклонной плоскости, при достижении горизонтальной плоскости оно равномерно замедляется с остановкой у правого края. Рисунок 5 3.2 Мяч циклически движется без проскальзывания и потерь на трение по внутренней поверхности полукруга. Угловая скорость движения центра мяча равноускоренная: от нуля в крайних положениях мяча до максимальной в нижней точке траектории. Рисунок 6 3.3 Ведомая шестерня вращается по внутренней поверхности корпуса под действием вращения ведущей шестерни ( рисунок 7). Диаметры шестерен одинаковы, угловая скорость центра ведомой шестерни в 3 раза меньше скорости ее собственного вращения. Рисунок 7 4 Отслеживание положения и ориентации объекта При моделировании движения часто возникает необходимость непрерывно отслеживать текущее положение объекта в случаях, когда оно непосредственно определяет сам ход процесса. Определение координат объекта обычно сложности не представляет, так как всегда известны координаты узловых точек. Несколько сложнее определить ориентацию объекта. Опишем функцию, возвращающую угол ориентации вектора, построенного на двух узловых точках объекта Y FUNCTION UGOL(x1,y1, x2,y2: real):real; 2 { угол между вектором от точки x1,y1 dy к точке x2,y2 и осью абсцисс} var u, d_x, d_y: real; 1 begin d_x:=x2-x1; dx X d_y:=y2-y1; Рисунок 8 if d_x<>0 then u:=arctan(d_y/d_x) else u:=0;
21 if d_x< 0 then u:=u+pi; UGOL:=u end; Особенностью этой функции является то, что арктангенс отношения разности ординат точек к разности абсцисс корректно работает лишь при d_x>0, т.е. для углов от - π /2 до π /2. При d_x<0 получаемое по арктангенсу значение угла необходимо смещать на пол-оборота. При необходимости получить нужную ориентацию движущегося объекта определяют текущий угол ориентации, нужный угол, а затем вызывается функция ROTATE по разности этих углов. 5 Практическое задание по моделированию движения с отслеживанием ориентации объекта 5.1 Составить программу случайного перемещения стрелки по экрану, причем стрелка не должна выходить за края экрана и всегда указывать на центр экрана. 5.2 Составить программу перемещения окружности по экрану с отражением от его краев. В центре экрана поместить стрелку-указатель, ориентирующийся на центр движущейся окружности. 5.3 Брусок соскальзывает от вертикального до горизонтального положения, касаясь двумя своими вершинами сторон прямого угла ( рисунок 9). Точка касания вертикали движется равноускоренно, при достижении горизонтали движение прекращается. Рисунок 9 5.4 Полая рейка вращается на оси с постоянной угловой скоростью ( рисунок 10). Затем центр рейки начинает равномерно смещаться от оси вращения ( соскальзывает), что сопровождается снижением угловой скорости вращения на 50% к концу соскальзывания. Рисунок 10
22 6 Модификация контурного изображения В производстве мультфильмов широко используется следующий метод анимации: а) задается массив координат узловых точек исходного контурного изображения ( X1[1..N],Y1[1..N] ); б) задается массив координат узловых точек целевого контурного изображения ( X2[1..N],Y2[1..N] ). Количество точек одинаково для обоих массивов; в) плавной модификацией исходного образа получаем целевое изображение. Для этого последовательно находятся наборы координат X[1..N],Y[1..N] промежуточных образов ( рисунок 11). Каждую iточку промежуточного образа выбирают на отрезке прямой между соответствующими точками исходного и целевого контуров, т. е. между точкой X1[i],Y1[i] и точкой X2[i],Y2[i]. Таким образом отрезок делится на m частей - по количеству промежуточных образов, включая целевой. Промежуточные образы перерисовывают, постепенно удаляясь от исходного образа.
X1[i] Y1[i]
X[i] Y[i] Рисунок 11
X2[i] Y2[i]
В случае равномерного деления отрезков координаты узловых точек промежуточных образов можно рассчитать по формулам x[i]:= x1[i] +(x2[i] -x1[i]) * k/m; y[i]:= y1[i] +(y2[i] -y1[i]) * k/m; где k - номер промежуточного образа, m - количество делений. Перерисовку образов удобно делать двойным рисованием в режиме SetWriteMode(1), или используя процедуры работы с видеопамятью в режиме XorPut. Задержка видимости образа определяет скорость преобразования. В приведенной ниже демонстрационной программе задается исходный контур из 12 точек X1[i],Y1[i] - координаты узлов на квадрате, а целевой контур из 12 точек X2[i],Y2[i] - координаты вершин звезды ( рисунок 12). uses Graph,Crt; var Gd,Gm, i,j ,k,n, xc,yc, r,m: integer; x,y, x1,y1, x2,y2: array[1..12] of integer; alfa: real; begin Gd:=0; InitGraph(Gd, Gm, 'c:\tp7\bgi');
23 SetWriteMode(1); { координаты квадрата, преобразующегося в звезду } for i:=7 to 10 do begin x1[i]:= 10; y1[ i]:= 10+(i-7)*40 end; for i:=1 to 4 do begin x1[i]:=130; y1[i]:=130-(i-1)*40 end; x1[11]:=50; x1[12]:= 90; y1[11]:=130; x1[ 6]:=50; x1[ 5]:= 90; y1[ 5]:= 10;
y1[12]:=130; y1[ 6]:= 10;
{ координаты звезды - целевой фигуры. Центр: } xc:=500; yc:=300; for i:=1 to 12 do begin alfa:=(1-i)*pi/6; if i mod 2 =0 then r:= 30 else r:=100; x2[i]:=xc+round(r*cos(alfa)); y2[i]:=yc+round(r*sin(alfa)) end; m:=50; { количество промежуточных образов} for k:=1 to m do begin for i:=1 to 12 do begin { координаты промежуточных образов } x[i]:=x1[i]+round((x2[i]-x1[i])*k/m); y[i]:=y1[i]+round((y2[i]-y1[i])*k/m) end; { перерисовка по промежуточным точкам } for j:=1 to 2 do begin Moveto( x[12],y[12]); for n:=1 to 12 do LineTo( x[ n],y[ n]);
Рисунок 12
if(k=1)and(j=1) then readkey; { задержка до начала движения } if j=1 then delay(100) { время видимости очередного образа } end end; readkey; CloseGraph end. Координаты точек промежуточных образов можно определять не только равномерным разбиением прямых линий между исходным и целевым изображениями, но и соединяя точки исходного и целевого контуров по кривым линиям с неравномерной разбивкой. 7 Практическое задание Модификацией контурного изображения запрограммировать один из динамических образов:
24 -
раскрывающийся парашют; растущий гриб; распускающийся цветок; сгорающая свеча; тающий снеговик; улетающий вдаль (или приближающийся) космический объект; сгибающаяся под тяжестью растущего плода ветка.
8 Мультипликация с чередованием видеостраниц Для качественных графических адаптеров можно установить режимы работы с несколькими графическими страницами. При этом во время просмотра кадра на одной видеостранице на другой можно организовать процесс рисования следующего кадра. Затем страницы переключаются, невидимая страница активизируется для рисования и процесс повторяется. Переключение страниц производится достаточно быстро, что важно при создании качественных движущихся образов. Для сложных сцен с большим временем перерисовки кадров метод чередования видеостраниц является единственным приемлемым. Страницы переключаются для просмотра на экране процедурой SetVisualPage( N), где N - номер страницы. По умолчанию видна и активна страница с N=0. Страница активизируется для рисования процедурой SetActivePage( N) Пример фрагмента программы - мультипликации с чередованием видеостраниц. r:=50; x:=100; y:=100; dx:=5; dy:=3; { размеры, положение и скорость образа } Gd:=Ega; Gm:=EgaHi; { режим с двумя кодовыми страницами } InitGraph(Gd,Gm,'c:\tp7\bgi'); k:=2; { количество кодовых страниц } i:=0; { счетчик смены страниц } Repeat inc(i); j:=i mod k; { j - номер кодовой страницы } SetActivePage(j); { активизируем страницу без ее показа } ClearDevice; { стираем старый рисунок } inc(x,dx); inc(y,dy); FillEllipse(x,y, R, 2*R-i); SetVisualPage(j); delay(80)
{ смена координат рисунка } { строим новый рисунок } { показываем страницу }
Until(y>300)or(KeyPressed);
25 9 Практическое задание С использованием чередования двух видеостраниц составить программу вывода на экран образов: - приближение гор разного цвета ( увеличивать размер гор ). - имитация движения в тоннеле. - взрыв (например, набором ломаных с заполнением промежутков и увеличением размеров). - создать один из динамических образов, предлагаемых в задании п.7 ( стр. 24), с построением заполненных фигур.
26 Лабораторная работа № 4 МУЛЬТИПЛИКАЦИЯ С ЗАПОМИНАНИЕМ ЧАСТИ ЭКРАНА 1 Цель работы Практическое освоение принципов и приемов работы с двумерными динамическими образами, создаваемыми с использованием процедур GetImage/PutImage. 2 Мультипликация чередованием набора образов Универсальный прием создания движущихся изображений - последовательный вывод в нужных областях экрана заранее созданных наборов образов. Обычно эти образы запоминаются непосредственно как фрагменты экрана в виде прямоугольных массивов пикселей. Этот метод наиболее удобен для моделирования циклически повторяющегося движения, что на практике встречается довольно часто. При запоминании фрагмента экрана под него нужно отвести память, размер которой можно определить с помощью функции ImageSize( X1, Y1, X2, Y2). Ее параметры определяют границу прямоугольной области графического экрана подобно процедуре Rectangle. Функция определяет число байт для хранения фрагмента. Размер отводимой памяти должен быть меньше 64 Кбайт. Далее определяется параметр P (типа pointer), который будет содержать начальный адрес области памяти ( буфера), отводимый для хранения двоичного образа прямоугольной области экрана процедурой GetMem( P, Size). Двоичный образ прямоугольной области сохраняется в буфере процедурой GetImage( X1, Y1, X2, Y2, P^) Сохраненный массив пикселов можно выводить на экран из буфера процедурой PutImage( X, Y, P^, N), где X,Y - позиция вывода верхнего левого угла области, N - режим вывода N = 0 (CopyPut) - замена изображения на экране буферным. N = 1 ( XorPut) - "исключающее ИЛИ" ( результат равен 1, если значения битов различны), N = 2 ( OrPut) - "ИЛИ" ( результат 1, если один из битов 1 ), N = 3 ( AndPut) - " И " ( результат 1, если оба бита равны 1 ), N = 4 ( NotPut) - " НЕ" ( замена изображения на экране инверсным изображением из буфера ). Цвет пикселов изображения из буфера не изменяется, если рисунок выводится в область, залитую фоном. Вывод в режиме XorPut удобен для создания движущихся изображе-
27 ний, поскольку при первом выводе получаем изображение из буфера, а при втором - восстанавливаем изображение на экране. В буфер помещают обычно несколько различных образов,. На экран выводится первый образ, затем после задержки этот вывод повторяют в том же месте - происходит восстановление изображения на экране. Далее (обычно в другой позиции) подобная процедура двойного вывода проводится с остальными образами. Пример фрагмента классической анимационной программы с использованием процедур GetImage/PutImage в режиме вывода XorPut: dx:=20; dy:=100; { размер прямоугольных областей для образов } Size:=ImageSize(0,0, dx,dy); { размер памяти для их хранения } rx:=dx div 2; ry:=(dy-3*dx) div 2; d:=2*dx; { размеры элементов рисунков } SetLineStyle(0,0,3); SetFillStyle(11,8); { первый образ } FillEllipse( rx,rx, rx,rx); FillEllipse( rx,dx+ry, rx,ry); Line( rx div 2, dy-2*dx, 0, dy) ; Line(3*rx div 2, dy-2*dx, dx,dy); { второй образ } FillEllipse(d+rx,rx, rx,rx); FillEllipse(d+rx, dx+ry, rx, ry); Line(d+rx, dy-2*dx, d+rx,dy); GetMem(P1, Size); { P1 - для хранения первого образа } GetImage(0,0, dx,dy, P1^); GetMem(P2, Size); { P2 - для хранения второго образа } GetImage(d, 0, d+dx, dy, P2^); x:=0; y:=200; { координаты начальной позиции вывода образов } ReadKey; ClearDevice; Line( 0,y+dy, 600,y+dy); { "дорога"} REPEAT { чередованием образов со смещением их позиции } PutImage(x,y, P1^, 1); { вывод первого образа } delay(300); PutImage(x,y, P1^, 1); { стирание первого образа } inc(x,10); { смещение позиции вывода } PutImage(x,y, P2^, 1); delay(300); PutImage(x,y, P2^, 1); inc(x,10); until(x>GetmaxX-dx)or(KeyPressed);
{ { { {
вывод второго образа } стирание второго образа } смещение позиции вывода } условие остановки }
28 3 Практическое задание 3.1 Создать модель перемещающейся фигурки чередованием трех образов с озвучиванием перемещения. Варианты фигурок: -
катящееся колесо со спицами; шагающий ослик; летящая со взмахами крыльев птица; гребец в лодке; прыгающий мяч, деформирующийся при ударе; летящий вертолет (вид сверху).
3.2 Создать управляемую с клавиатуры стрелку. При перемещении стрелки по экрану она должна указывать направление своего перемещения. 4 Работа с набором взаимодействующих образов Процедуры GetImage/PutImage работают весьма быстро, что можно использовать для создания сложных динамичных двумерных сцен. При этом хорошие результаты удается получить лишь при условии достаточно быстрого анализа условий, определяющих характер самого моделируемого процесса. Рассмотрим пример программы, моделирующей поведение однородной сыпучей среды в поле силы тяжести. uses Graph,Crt; const M=50; { число объектов } d=12; { размер объектов } var x,y: array[1..M] of integer; { центры объектов } stop,udar: array[1..M] of boolean; P: Pointer; Gd,Gm, i,r, Size : Integer; PROCEDURE DOWN(i: integer); { Пошаговое перемещение объекта вниз } var dx,dy: integer; begin dx:=0; dy:=r; { планируемое смещение координат объекта } udar[i]:=true; { признак удара объекта о преграду } { случай перемещения без препятствий } if GetPixel( x[i], y[i]+d-1)=0 then udar[i]:=false else { внизу преграда, но слева свободно } if ( GetPixel( x[i]-d, y[i] )=0 ) and( GetPixel( x[i]-d, y[i]+r)=0 ) then dx:=-d else { внизу преграда, но справа свободно }
29 if ( GetPixel( x[i]+d, y[i] )=0 ) and( GetPixel( x[i]+d, y[i]+r)=0 ) then dx:=d else dy:= 0; { смещение невозможно } if dy > 0 then begin PutImage( x[i]-r,y[i]-r, P^, 1); { стирание образа } inc( x[i],dx); inc( y[i],dy); { смещение позиции вывода } PutImage( x[i]-r,y[i]-r, P^, 1) { вывод образа } end; { если объект не двигался на предыдущем шаге } if stop[i]=true then udar[i]:=false; { генерация звука при ударе и задержка видимости образа } if udar[i] then sound(300); delay(2); NoSound; { если объект не сместился, то ставим признак его остановки } if dy=0 then stop[i]:=true else stop[i]:=false
end;
begin
Gd:=0; InitGraph(Gd,Gm,''); Size:=ImageSize(0,0, d,d); { размер памяти для образов } r:=d div 2;
FillEllipse( r,r, r-1,r); { образ объекта } GetMem(P, Size); { P - для хранения образа } GetImage(0,0, d,d, P^);
{ Генерация начальных координат и свойств образов } for i:=1 to M do begin x[i]:=10*d + d*(i mod 6); y[i]:= 4*d+2*d*(i div 6); udar[i]:=false; stop[i]:=false; PutImage(x[i]-r,y[i]-r, P^,0) end; { Рисование преград } For i:=1 to d do line (10*d, d*26+i, 18*d, d*30+i); Bar(0, d*35, 400, d*36); ReadKey; { Процесс смещения объектов ( рисунок 1) } Repeat for i:=1 to M do DOWN(i); Until KeyPressed; readKey; CloseGraph end.
30
Рисунок 1 - Моделирование поведения сыпучей среды. Описанная выше методика содержит весьма нестрогие логические условия моделирования процесса, например, толщина преграды для объектов должна быть не менее радиуса этих объектов. Однако усложнение условий моделирования подобных процессов приводит к ухудшению динамических характеристик модели. Поэтому необходим разумный компромисс по точности моделирования и, например, числу рассматриваемых объектов. 3 Практическое задание Создать следующие динамические образы с использованием множества однотипных объектов: - песочные часы; - обвал подмываемого берега; - шарообразные детали на конвейере.
31 Список литературы 1. Боресков А.В., Шикин Е.В., Шикина Г.Е. Компьютерная графика: первое знакомство. - М.: Финансы и статистика, 1996. 2. Епанешников А.М., Епанешников В.А. Программирование в среде Turbo Pascal 7.0. - М.: Диалог - МИФИ, 1995. 3. Иванов В. М., Батраков А. С. Трехмерная компьютерная графика. М.: Радио и связь, 1995. 4. Лапшин Е. Графика для IBM PC. - М.: СОЛОН, 1995. 5. Котов Ю. В. Как рисует машина. - М.: Наука, 1988. - 224 с. 6. Котов В.Ю., Павлова А.А. Основы машинной графики. - М.: Просвещение, 1993. 7. Дж. Корриган. Компьютерная графика: Секреты и решения. - М.: Диалог - МИФИ, 1995. 8 Д. Хирн, М. Бейкер. Микрокомпьютерная графика. Пер. с англ. М.: Мир, 1987. 9. Фаронов В.В. Турбо Паскаль ( в 3-х книгах ). Практика программирования. - М.: УНЦ ”МВТУ ФЕСТО ДИДАКТИК”, 1993. 10. Шикин Е.В., Боресков А.В. Компьютерная графика. Динамика, реалистические изображения. - М.: Диалог - МИФИ, 1995. 11. Шикин Е.В., Боресков А.В., Зайцев А.А. Начала компьютерной графики. - М.: Диалог- МИФИ, 1993.
32 ПРИЛОЖЕНИЕ А Типовые графические функции BGI При реализации приведенных в пособии типовых алгоритмов графики использованы следующие типовые графические процедуры и функции Borland Graphics Interface: InitGraph(Gd, Gm, 'way')
- переход к графическому режиму (инициализация графики), где Gd - имя графического драйвера, Gm - номер графического режима монитора , 'way' - дорожка DOS к файлам с графическими драйверами (*.bgi). Обычно драйверы подключаются в режиме автоопределения используемого монитора ПК. Для этого перед инициализацией графики задается Gd:= Detect (или Gd:= 0). В этом случае по умолчанию устанавливается режим с наибольшим числом точек на экране, а значение параметра "Gm" игнорируется. Номер наибольшего режима для текущего драйвера возвращает функция GetMaxMode. Изменить режим можно процедурой SetGraphMode( Gm). Экран при этом очищается. Разрешающую способность для текущего графического режима можно определить функциями, возвращающими максимальные значения координат экрана GetMaxX - по оси Х; GetMaxY - по оси Y. Для возврата из графического режима в текстовый можно использовать операторы: CloseGraph
- полное прекращение работы графической системы;
RestoreCrtMode
- переключение в текстовый режим с возможностью возврата к текущим установкам графического режима (оператором SetGraphMode). Очистить графический экран можно процедурой ClearDevice (без изменения установленных параметров) либо GraphDefaults ( устанавливаются параметры, принятые по умолчанию). Процедуры рисования: SetBkColor( N) SetColor( N)
- установить цвет N для пикселов фона; - установить цвет N для выводимых линий;
PutPixel( X, Y, N) - высветить цветом N пиксель с координатами X,Y; GetPixel( X, Y)
- определить цвет пиксела с координатами X, Y;
33 Circle( X, Y, R)
- окружность с центром X, Y радиуса R;
Arc( X,Y, A1,A2, R) Ellipse( X,Y, A1,A2, RX,RY)
- дуга окружности; - сектор эллипса с полуосями RX,RY;
A1, A2 - начальный и конечный углы (в градусах), отсчитываемые против часовой стрелки относительно оси Х; Line( X1,Y1, X2,Y2) - отрезок прямой от точки с координатами X1,Y1 к точке с координатами X2,Y2; LineTo( X, Y) - отрезок прямой от текущего положения курсора до точки X,Y; LineRel( dX, dY)
- отрезок прямой от текущего положения курсора до точки, смещенной на расстояние dX,dY.
В отличие от процедуры Line процедуры LineTo и LineRel при своем исполнении перемещают текущий указатель. Перемещать курсор без рисования можно процедурами MoveTo(X, Y) и MoveRel(dX,dY). В графическом режиме курсор невидим, а его положение можно определить функциями, возвращающими значения координат GetX - по оси Х, GetY - по оси Y. Rectangle( X1,Y1, X2,Y2) - прямоугольник с левым верхним углом в точке X1,Y1 и правым нижним углом в точке X2,Y2 (стороны параллельны краям экрана ). Для заполняемых фигур граница рисуется текущим цветом для линий. Цвет N и стиль заполнения P (орнамент) можно устанавливать из стандартного набора BGI или определять самим процедурой SetFillStyle( P, N). Bar( X1,Y1, X2,Y2) - заполненный прямоугольник; Bar3d( X1,Y1, X2,Y2, d, t) - параллелепипед с заполненной передней гранью (координаты углов грани X1,Y1, X2,Y2), глубиной d. Переменная t типа boolean задает вывод верхней грани. При t=TopOn (true) верхняя грань показывается, при t=TopOff (false) - нет. FillEllipse( X,Y, RX,RY) - заполненный эллипс; Sector( X,Y, A1,A2, RX,RY) - заполненный сектор эллипса; PieSlice( X,Y, A1,A2, R)
- заполненный сектор круга.
34 Составитель: ТРУШИН Олег Владимирович
МЕТОДИЧЕСКИЕ УКАЗАНИЯ к лабораторным работам по курсу "Интерактивная машинная графика" для подготовки инженеров по специальности 220200 "Автоматизированные системы обработки информации и управления" Часть 1 "Синтез графических образов простыми средствами"
Редактор
Г.Р. Орлова
ЛБ № 01 92 от 16.10.96
Подписано к печати
Формат 60 Х 84 1/16.
Бумага оберточная. Печать плоская. Усл. печ. л. 2,1 Усл. кр. – отт. 2,0 Заказ №
Уч.-изд. л. 2,0. .
Тираж 100 экз. Бесплатно
Уфимский государственный авиационный технический университет Уфимская типография № 2 Министерства печати и массовой информации Республики Башкортостан 450000, Уфа – центр, ул. К. Маркса, 12