ZX Spectrum графика 1994 г.

Ортогональные проекции - Исходное положение; Фактическое положение; Наблюдаемое положение; Ортогональная проекция; Вычисление матрицы Q, переводящей объект из фактического положения в наблюдаемое; Как задавать объект; Конструирующие подпрограммы и метод построения блоков; Тела вращения.


ГЛАВА 9 Ортогональные проекции

Теперь мы можем перейти к проблеме изображения трёхмерных объектов на нашем двумерном экране. Простейший метод, описанный здесь, является естественным обобщением метода главы 4, в которой рассматривается изображение двумерных объектов. Нам опять придется использовать до трёх положений объекта. Для иллюстрации этих идей мы сначала даём сжатое описание метода, а затем приводим множество поясняющих примеров. Мы начинаем с введения произвольной, но фиксированной тройки осей в пространстве, которую мы называем абсолютной системой. После этого мы рассмотрим 3 положения предмета: (1) исходное, (2) фактическое, (3) наблюдаемое.

(1) Исходное положение

Большая часть рисунков состоит из простых предметов, расположенных в пространстве определенным образом. Вычислять координаты каждой вершины и вносить их в программу является неэффективным. Вместо этого мы вначале задаем информацию об объекте в абсолютной системе координат, располагая его наиболее удобным образом - как правило, возле начала координат. В эту информацию входит: информация о вершинах (X-координата, Y-координата, Z-координата), возможно, информация о линиях (соединяющих вершины) или (после того как мы познакомимся с алгоритмами удаления невидимых линий и поверхностей) информация о видимых поверхностях, которые являются плоскими многоугольниками, ограниченными заданными линиями. Положение объекта, в котором он определяется, называется исходным. Нам может потребоваться дополнительная информация об объекте, например, его цвет.

(2) Фактическое положение

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

(3) Наблюдаемое положение

Понятие наблюдения предполагает наличие наблюдателя (глаза наблюдателя и, заметьте, не только глаза!), находящегося в точке (EX, EY, EZ) относительно системы координат абсолютная, который смотрит в направлении, задаваемом любой точкой, находящейся на прямой, определяющей направление взгляда. Кроме того, голова может быть наклонена, но об этом позже. Воспринимаемое глазом изображение объекта есть не что иное, как проекция вершин, линий и поверхностей на двумерную плоскость (визуальную плоскость), перпендикулярную линии взгляда. Для того, чтобы строить подобные проекции, нам необходимо разработать соответствующие методы. Мы используем матричный метод для преобразования точек пространства таким образом, чтобы глаз располагался в начале координат, а направление взгляда было параллельно оси Z. Мы будем называть такое положение наблюдаемым, а матрицу, переводящую фактическое положение в наблюдаемое, мы всюду в этой книге обозначаем Q. Метод вычисления матрицы Q будет приведен позже, а пока мы считаем, что глаз наблюдателя уже находится в начале координат, а взгляд направлен параллельно оси Z: в этом простейшем случае матрица Q равна тождественной.

Когда все точки пространства переведены в наблюдаемое положение, то визуальной плоскостью является плоскость, параллельная плоскости X/Y. Поместив глаз в параллельное положение, мы готовы к построению проекции объекта на визуальную плоскость. Но обратите внимание, что мы пока что не определили ни положение плоскости проекции (нам задана только её нормаль), ни тип проекции трёхмерного пространства в двухмерное. Эти два требования взаимосвязаны. В данной книге рассматриваются два типа проекций: в дальнейших главах мы познакомимся с перспективной проекцией, а пока ограничимся случаем ортогональной проекции.

Ортогональная проекция

Это простейший вид проекций, и в этом случае положение визуальной плоскости не играет роли, лишь бы она была перпендикулярна направлению взгляда. После перевода объекта в наблюдаемое положение, визуальной плоскостью может служить любая плоскость, параллельная плоскости X/Y, задаваемой уравнением Z=0. Для простоты мы выбираем в качестве визуальной плоскости плоскость, проходящую через начало координат. Для того, чтобы получить проекцию вершины объекта на визуальную плоскость, следует всего лишь отбросить координату Z этой вершины. Таким образом, любые две точки объекта в наблюдаемом положении с координатами (X,Y,Z), (X',Y',Z'), (Z=Z'), проектируются в одну и ту же точку визуальной плоскости с координатами (X,Y,Z). Используя методы главы 2, мы ставим в соответствие с точками X/Y плоскости точки системы координат, связанной с экраном (как правило, начало координат этой системы находится в центре экрана). Как только вершины спроецированы на визуальную плоскость, мы можем построить проекции линий и поверхностей объекта. Последние находятся в таком же отношении к спроецированным вершинам, в каком они были в самом объекте.

Прежде чем перейти к общему случаю, продемонстрируем сказанное на простом примере.

Пример 9.А

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

В исходном положении куб можно задавать с помощью восьми вершин (1,1,1), (1,1,-1), (1,-1,-1), (1,-1,1), (1,1,1), (-1,1,-1), (-1,-1,-1), (-1,-1,1); эти вершины нумеруются числами от 1 до 8. Двенадцать линий, составляющих каркас куба, соединяют вершины 1 и 2, 2 и 3, 3 и 4, 4 и 1, 5 и 6, 6 и 7, 7 и 8, 8 и 1, 1 и 5, 2 и 6, 3 и 7, 4 и 8.

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

На рисунке 33 приведено изображение куба, переведенного в фактическое положение при помощи следующих трёх преобразований:

1. Поворота относительно оси Z на ALFA=-0.92729518 рад - матрица A. Величина ALFA выбиралась с тем, чтобы COS(ALFA)=3/5, а SIN(ALFA)=-4/5, и матрица поворота имеет простой вид;

2. Переноса на вектор (-1,0,0) - матрица B;

3. Поворота на угол -ALFA относительно оси Y - матрица C.

Матрица, переводящая куб из исходного положения в фактическое, есть P=C*B*A, где

A =

P =

( 3/5

4/5

0

01

(1

0

0

-11

( 3/5

0

4/5

01

- 4/5

3/5

0

0

0

1

0

0

0

1

0

0

B =

C =

0

0

1

0

0

0

1

0

- 4/5

0

3/5

0

v 0

0

0

1 У

v 0

0

0

0 У

v 0

0

0

1 У

и P равна:

(

9

12

20

151

1

20

15

0

0

25

12

-16

15

20

v

0

0

0

25 y

Перечисленные выше трёхмерные векторы, соответствующие вершинам куба в исходном положении, переходят в восемь векторов, соответствующие этим вершинам в фактическом положении: (26/25,-5/25,7/25), (-14/25,-5/25,-23/25), (-38/25,-35/25,9/25), (2/25,-35/25,39/25), (8/25,35/25,31/25), (-32/25,35/25,1/25), (-56/25,5/25,33/25), (16/25,5/25,63/26).

Например, точка (1,1,1) переходит в точку (26/25,-5/25,7/25) так как

(

9

12

20

151

(11

V 261

1

- 20

15

0

0

1

=1

- 5

*

25

-12

-16

15

20

1

= 25

7

v

0

0

0

25 У

Jy

V 25 y

Так как матрица Q, переводящая куб из фактического положения в наблюдаемое, единичная, то координаты проекций точек на визуальную плоскость есть (26/25,-5/25), (-14/25,5/25), (-32/25,-35/25), (2/25,-35/25), (8/25,35/25), (32/25,35/25), (56/25,5/25), (-16/25,5/25). Мы можем нанести эти точки на экран и соединить их в той же последовательности, в какой они определялись в исходном положении.

Рис. 33.

Вычисление матрицы Q, переводящей объект из фактического положения в наблюдаемое Предположим, что глаз наблюдателя находится в точке (EX,EY,EZ) относительно абсолютной оси координат, а направление взгляда - в точку (DX,DY,DZ). Тогда наблюдаемое положение получается так:

1. Матрица D осуществляет перенос точек пространства на вектор (-DX,-DY,-DZ) так, что глаз находится в точке (FX,FY,FZ), равной (EX-DX,EY-DY,EZ-DZ), а взгляд направлен в сторону начала координат.

D=

(1

0

0

- DX 1

0

1

0

- DY

0

0

1

- DZ

v 0

0

0

1y

2. Матрица E переводит (FX,FY,FZ) в (R,0,FZ) вращением пространства на угол ALPHA, где ALPHA=ARCTG(FY/FX), относительно оси Z. Здесь R**2=X**2+Y**2 и R>0

( FX FY 0 01 - FY FX 0 0

E =

0 R 0 0 0 R

v ~ ~ .vy

3. Матрица F переводит (R,0,FZ) в (0,0,-S) поворотом относительно оси Z на угол PI-TETA, где TETA=ARCTG(R/FZ); здесь S**2=R**2+FZ**2=FX**2+FY**2+FZ**2 при S>0

1 R

0 0

(- FZ 0 R 01

F = I

S

fl fl n cj

Матрицами D, E, F глаз помешается в (0,0,-S), направление взгляда - в сторону начала координат. Глаз находится на том же расстоянии от начала координат, на котором находятся относительно друг друга точки (EX,EY,EZ) и (DX,DY,DZ).

(1 0 0 01

G =

0 10 0 0 0 1 S 0 0 0 1

Теперь мы можем выписать матрицу, помещающую глаз в начало координат.

4. Если мы теперь умножим P=A*B*C на наше первое приближение матрицы Q (=G*F*E*D), переводящей фактическое положение в наблюдаемое, то мы получим матрицу R=Q*P=G*F*E*D*C*B*A, которая переводит объект из исходного положения в наблюдаемое. Изображение куба, полученное с помощью матрицы R, нельзя считать удовлетворительным, так как матрица Q помещает куб на плоскость так, что его ориентация оказывается случайной. Самым распространенным методом, позволяющим избежать этот эффект, является метод фиксации вертикали (или направления, параллельного оси Y), при котором прямая, вертикальная в фактическом положении, остается таковой после перевода объекта в наблюдаемое положение матрицей Q. Рассмотрим прямую, соединяющую точки (DX,DY+1,DZ) и (DX,DY,DZ). Мы знаем, что после преобразования эта прямая перейдет в прямую, соединяющую точки (К(1,2),К(2,2),К(3,2))=(Р^Д), так что если мы повернём объект относительно оси Z на угол BETA=ARCTG(К(1,2)/К(2,2))=ARCTG(P/Q)=ARCTG(-FY*FZ/(S*PX)), используя для этого поворота умножение на матрицу E (умножение производится перед умножением на матрицу G), то мы установим вертикаль в нужное положение:

0

S

0

0

-R

0

- FS

0

0

0

0

S

q

p

0

0

p

- q

0

0

0

0

1

0

0

0

0

1

h = 1

t

где T2=P2*Q2

и таким образом:

( P ^

(Q

P

0

0 1

(P1

( 01

Q

= 1

p

-Q

0

0

*

Q _

T

R

= T

vv 0

0

T

0

vv R

vvR

v 1 У

,0

0

0

T J

.1 j

v 1J

Преобразование (рис. 33) осуществляется с помощью матрицы P=Q*R=G*H*F*E*D*C*B*A. Проекцией прямой, соединяющей точки (DX,DY,DZ) с точкой (DX,DY+1,DZ) будет прямая, соединяющая точку экрана (0,0) с точкой (0,T), то есть вертикальная прямая. Матрица G не меняет значений координат X и Y. Обратите внимание на то, что предложенный нами метод применим во всех случаях, за исключением ситуации, когда точка (DX,DY,DZ) находится в точности над точкой (EX,EY,EZ); в этом случае фиксирование вертикали не имеет смысла. Подпрограмма "LOOK3" (листинг 9.1) генерирует матрицу преобразования, переводящего фактическое положение в наблюдаемое положение; эта генерация состоит из нескольких операций, в соответствии с приведенным выше описанием алгоритма; каждой из этих операций соответствует вычисление очередного сомножителя, участвующего в выражении для вычисления матрицы R, так что в конце процесса матрица R кажется домноженной на матрицу Q. Если мы хотим занести в память непосредственно значение матрицы Q, то для этого мы должны присвоить матрице R значение единичной матрицы (используя подпрограмму "IDR3"), затем вызвать "LOOK3" и, наконец, занести массив R в массив Q. Подпрограмму "LOOK3" можно существенно сократить, если условиться считать, что взгляд наблюдателя всегда направлен на начало координат (что эквивалентно DX=0, DY=0, DZ=0). В случае ортогональной проекции нет необходимости помещать глаз в начало координат в наблюдаемом положении, что также позволяет сократить программу. Мы приводим наиболее общий подход к задаче, что окажется весьма полезным при рассмотрении перспективной проекции.

LISTING 9.1 8200 REM LOOK3

8210 INPUT "(EX,EY,EZ) ";EX;",";EY;' 8220 INPUT "(DX,DY,DZ) ";DX;",";DY;'

8229 REM MOVE ORIGIN TO (DX,DY,DZ).

8230 LET TX=DX: LET TY=DY: LET TZ=DZ

H =

;EZ ;DZ

8240 GO SUB TRAN3: GO SUB MULT3

8249 REM MOVE EYE INTO NEGATIVE Z-AXIS, LOOKING AT THE ORIGIN.

8250 LET FX=EX-DX: LET FY=EY-DY: LET FZ=EZ-DZ

8260 LET AX=FX: LET AY=FY: GO SUB ANGLE

8270 LET AXIS=3: LET THETA=-THETA: GO SUB ROT3: GO SUB MULT3

8280 LET AX=FZ: LET AY=SQR(FX*FX+FY*FY): GO SUB ANGLE

8290 LET AXIS=2: LET THETA=PI-THETA: GO SUB ROT3: GO SUB MULT3

8299 REM MAINTAIN VERTICAL.

8300 LET TX=0: LET TY=0: LET TZ=SQR(FX*FX+FY*FY+FZ*FZ)

8310 LET AX=TZ*FX: LET AY=-FY*FZ: GO SUB ANGLE

8320 LET AXIS=3: GO SUB ROT3: GO SUB MULT3

8329 REM MOVE EYE TO THE ORIGIN. SPACE IS ROW IN THE OBSERVED POSITION.

8330 GO SUB TRAN3: GO SUB MULT3

8340 RETURN

При необходимости мы можем расширить нашу программу с тем, чтобы включить случай, когда голова наклонена на угол GAMMA относительно вертикали. Для этого необходимо дополнительное вращение пространства на угол GAMMA относительно оси Z, что означает, что матрица H должна повернуть пространство на угол BETA-GAMMA.

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

Как задавать объект

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

Для хранения больших объёмов информации об объекте мы используем массивы, и естественно, что чем больше информации требуется для описания объекта, тем больше памяти следует отводить для массивов; объявляя в программе величину массива, вы должны быть уверены, что он достаточно велик для того, чтобы хранить всю необходимую информацию, пусть он лучше будет большим, чем меньшим.

Нам потребуется хранить информацию о координатах точек в пространстве; для этой цели мы используем три массива X, Y, Z для каждой координаты. Когда число точек не указано явно, то мы полагаем, что оно равно величине Q. Таким образом, в каждом таком массиве должно содержаться не менее NOV элементов. Эти точки могут принадлежать объекту в исходном, фактическом или наблюдаемом положениях, что зависит от решаемой задачи. Нам также встретится ситуация (перспективная проекция, например), в которой будет необходимо хранить значения X и Y координат проекций этих NOV вершин. В случае ортогональной проекции такой проблемы не возникает, так как эти значения хранятся в массивах X и Y. Выбор структуры данных существенно зависит от типа проекции.

Пусть изображение объекта состоит из NOL отрезков. Эту формацию мы можем хранить в массиве L: первый отрезок определяется двумя индексами, принимающими значение от 1 до NOL и соответствующими номерами вершин, являющимися концами этого отрезка; эти числа мы храним как L(1,1), L(2,1). Координаты этих точек могут быть определены с помощью массивов X, Y, Z.

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

Каждая из NOF граней может быть определена с помощью индексов вершин, образующих эту грань, хранящихся в массиве F: F(I,J) - индекс I-ой вершины J-ой грани. Если грань не шестиугольная, то некоторые из элементов массива F, соответствующие грани, не несут никакой информации, в связи с этим мы должны ввести массив H, в котором записано количество вершин каждой грани.

Можно также хранить информацию о цвете каждой грани в массиве C. Однако будьте внимательны, так как в SPECTRUMe в каждом символьном блоке разрешается использовать не более двух цветов. Другой способ хранения информации о гранях - это хранить индексы прямых, образующих грань; в этом случае F(I,J) это индекс I-го ребра J-ой грани. Существует много способов хранения этих и других элементов трёхмерных объектов; определите сами, какой из них соответствует вашей задаче наилучшим образом.

Конструирующие подпрограммы и метод построения блоков

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

Мы можем сгенерировать изображение, состоящее из множества подобных объектов (в этом случае информация будет о фактическом или наблюдаемом положении). В этом случае нет необходимости создавать каждый из объектов заново, достаточно вычислять для каждого объекта свою матрицу R, соответствующую преобразованию, переводящему объект из исходного положения в фактическое (для фактического положения) или Q*F (для наблюдаемого положения) и вводить её в ту же подпрограмму. Для каждого нового типа объектов нам потребуется конструирующая подпрограмма.

Целиком рисунок генерируется с помощью основной программы (листинг 9.2), объявляющей метки всех подпрограмм, приготавливающей графический экран, используя входные параметры HORIZ и VERT и, наконец, вызывающей подпрограмму "SCENES", располагающую объекты в пространстве и вычисляющую их. Приведенная ниже подпрограмма используется во всех программах трёхмерной графики, которые приводятся ниже, так что не следует её менять без особой на то необходимости. LISTING 9.2

100 REM MAIN PROGRAM

110 LET START=9700: LET SETORIGIN=9600: LET MOVETO=9500: LET LINETO=9400: LET CLIP=8400

120 LET ROT3=8600: LET ANGLE=8800: LET SCALES=8900: LET TRAN3=9000: LET MULT3=9100: LET IDR3=9300

130 LET SCENE3=6000: LET LOOK3=8200

139 REM DIMENSION AND CENTRE THE GRAPHICS AREA.

140 INPUT "HORIZ=";HORIZ;" VERT=";VERT 150 GO SUB START

160 LET XMOVE=HORIZ*0.5: LET YMOVE=VERT*0.5 170 GO SUB SETORIGIN

179 REM SET THE SCENE.

180 GO SUB SCENE3 190 STOP

В подпрограмме "SCENES" объявляются все массивы, необходимые для хранения информации об изображении, а также матрицы A, B, R и (возможно) матрица Q, предназначенные для помещения объекта в необходимое положение. При необходимости переменным, которые изменяются в дальнейших конструирующих подпрограммах.

Для каждого объекта ("блока") подпрограмма "SCENES" должна вычислить матрицу P, помещающую блок в фактическое положение, а затем, вычисляя соответствующую матрицу P (переводящую исходное положение в фактическое или исходное положение в наблюдаемое). В результате из этих блоков складывается изображение. Иногда это изображение вычерчивается конструирующей подпрограммой, а иногда с помощью подпрограмм, предназначенных для вычерчивания объектов особого вида (таких, как объекты с удаленными невидимыми линиями или поверхностями) - все зависит от того, изображение чего создается и какого типа должно быть это изображение.

Как и раньше, мы не генерируем матрицы P и Q в явном виде, но вместо этого изменяем значение P, что связано с запретом на передачу подпрограмме массивов в качестве параметров. Если требуется матрица Q, то для этого достаточно вызвать подпрограмму "IDR3", которая делает матрицу R единичной; полезно иметь в виду, что все матричные операции производятся с помощью матриц A и R с использованием матрицы B для хранения промежуточных результатов.

В своих программах используйте вариант подпрограммы "LINETO", удаляющий части прямых, выходящие за рамки графического экрана. Часто встречается ситуация, когда выбранные значения HORIZ и VERT слишком малы для того, чтобы весь объект было возможно разместить на экране, и в этом случае немодифицированный вариант подпрограммы "LINETO" не сможет быть использован. Иногда значениям HORIZ и VERT умышленно задают заниженные значения, что позволяет с помощью последующего увеличения получать увеличенные изображения отдельных участков объекта.

Первый пример применения изложенного выше метода приведен на листинге 9.3, где приведена подпрограмма "SCENES". На листинге 9.4 приводится конструирующая подпрограмма "CUBE", генерирующая данные куба с длиной ребра, равной 2; координаты вершин заносятся в массивы X, Y, Z. В данном случае можно не хранить информацию о рёбрах куба: мы получаем необходимую информацию из оператора DATA, а затем чертим линии.

Входные данные для рис. 33 есть: HORIZ=9, VERT=6,

(EX,EY,EZ)=(-2,2,2), (DX,DY,DZ)=(-l,0,0). LISTING 9.3

6000 REM SCENES/EXAMPLE 1 6010 DIM X(8): DIM Y(8): DIM Z(8) 6020 DIM A(4,4): DIM B(4,4): DIM R(4,4) 6030 LET CUBE=6500

6039 REM CALCULATE THE SETUP TO ACTUAL MATRIX R.

6040 GO SUB IDR3

6050 LET THETA=-0.92729522: LET AXIS=3: GO SUB ROT3: GO SUB MULT3 6060 LET TX=-1: LET TY=0: LET TZ=0: GO SUB TRAN3: GO SUB MULT3 6070 LET THETA=-THETA: LET AXIS=2: GO SUB ROT3: GO SUB MULT3

6079 REM CHANGE R - PREMULTIPLY IT BY THE ACTUAL TO OBSERVED MATRIX.

6080 GO SUB LOOK3

6089 REM CALL CONSTRUCTION ROUTINE DRAW THE CUBE.

6090 GO SUB CUBE 6100 RETURN LISTING 9.4

6500 REM CUBE/LINES (NOT STORED)

6501 REM IN - R(3,3)

6510 DATA 1,1,1,1,1,-1,1,-1,-1,1,-1,1,-1,1,1,-1,1,-1,-1,-1,-1,-1,-1,1 6520 DATA 1,2,2,3,3,4,4,1,5,6,6,7,7,8,8,5,1,5,2,6,3,7,4,8 6530 RESTORE CUBE

6539 REM INPUT SETUP VERTICES OF CUBE AND MOVE THEM INTO OBSERVED POSITION.

6540 FOR I=1 TO 8 6550 READ XX,YY,ZZ

6560 LET X(I)=XX*R(1,1)+YY*R(1,2)+ZZ*R(1,3)+R(1,4) 6570 LET Y(I)=XX*R(2,1)+YY*R(2,2)+ZZ*R(2,3)+R(2,4) 6580 LET Z(I)=XX*R(3,1)+YY*R(3,2)+ZZ*R(3,3)+R(3,4) 6590 NEXT I

6599 REM INPUT LINE INFORMATION. DRAW LINES BY JOINING PAIRS OF VERTICES.

6600 FOR I=1 TO 12 6610 READ L1,L2

6620 LET XPT=X(L1): LET YPT=Y(L1): GO SUB MOVETO 6630 LET XPT=X(L2): LET YPT=Y(L2): GO SUB LINETO 6640 NEXT I 6650 RETURN

На одном рисунке можно поместить изображение более чем одного куба. Например, если мы перепишем подпрограмму "SCENES", как это показано на листинге 9.5, а все остальные подпрограммы оставим теми же, то в результате мы получим фигуру, изображенную на рисунке 34.

Обратите внимание на то, что значения X, Y, Z, вычисленные для первого куба, переписываются при повторном вызове программы "CUBE". Кроме того, так как матрица, соответствующая переводу объекта из фактического положения в наблюдаемое, в обоих случаях одна и та же (у них разные матрицы преобразований из исходного положения в фактическое), то мы заносим в память матрицу Q с тем, чтобы использовать её вторично. Помните, что матрица Q умножается на матрицу P, переводящую второй куб в фактическое положение. Параметры для рис. 34 таковы: HORIZ=9, VERT=6, (EX,EY,EZ)=(3,2,1) и (DX,DY,DZ)=(0,0,0).

Рис. 34.

LISTING 9.5

6000 REM SCENE3/EXAMPLE2

6010 DIM X(8):DIM Y(8): DIM Z(8)

6020 DIM A(4,4): DIM B(4,4): DIM R(4,4): DIM Q(4,4) 6030 LET CUBE=6500

6039 REM DRAW 1'ST CUBE IN OBSERVED POSITION.

6040 GO SUB IDR3: GO SUB LOOK3 6050 GO SUB CUBE

6059 REM DRAW 2'ND CUBE IN OBSERVED POSITION.

6060 FOR I=1 TO 4: FOR J=1 TO 4 6070 LET Q(I,J)=R(I,J)

6080 NEXT J: NEXT I 6090 GO SUB IDR3

6100 LET TX=3: LET TY=1.5: LET TZ=2: GO SUB TRAN3: GO SUB MULT3

6110 FOR I=1 TO 4: FOR J=1 TO 4

6120 LET A(I,J)=Q(I,J)

6130 NEXT J: NEXT I

6140 GO SUB MULT3

6150 GO SUB CUBE

6160 RETURN

Упражнение 9.1

Модифицируйте программу "CUBE" так, чтобы можно было вводить данные о прямоугольном параллелепипеде, что позволяло бы строить параллелепипед высоты HT, ширины BH и длины LH. Для этого умножьте значения X-координаты куба в исходном положении на LH/2, Y - на HT/2, и Z - на BH/2.

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

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

Пример 9.Б

Мы хотим осмотреть некоторую фигуру (например, ту, что на рис. 34) с нескольких различных точек. В этом случае удобнее запоминать координаты вершин фигуры в фактическом, а не в наблюдаемом положении, и занести информацию о линиях в массив. Программа "SCENES" (листинг 9.6) должна сначала присвоить переменным NOV и NOL нулевые значения, а затем, используя матрицу R=P, поместить объекты в их фактическое положение. Конструкционная подпрограмма "CUBE" (листинг 9.7) тогда должна быть изменена так, чтобы она могла менять значения данных (но обратите внимание, что та же программа могла бы хранить координаты вершин в наблюдаемом положении, что только потребовало бы другой R=Q*P).

Для каждой новой точки, из которой предмет рассматривается, и каждого направления взгляда подпрограмма "SCENES" должна очистить экран, присвоить P значение единичной матрицы, вызвать подпрограмму "LOOK3" и затем вызвать подпрограмму "DRAWIT" (листинг 9.8), использующую матрицу R (в этой матрице хранится значение матрицы Q, переводящей фактическое положение в наблюдаемое) для расположения точек в наблюдаемом положении и последующей ортогональной проекции их в массивы V и W (мы не можем использовать для этой цели массивы X и Y, так как это повлекло бы искажение информации об объекте в фактическом положении). Подпрограмма "DRAWIT" может использовать информацию, хранящуюся в массиве L, для генерации изображения на экране. LISTING 9.6

6000 REM SCENE3/EXAMPLE2 (VARIETY OF VIEWS) 6010 DIM X(16): DIM Y(16): DIM Z(16) 6020 DIM V(16): DIM W(16): DIM L(2,24) 6030 DIM A(4,4): DIM B(4,4): DIM R(4,4) 6040 LET CUBE=6500: LET DRAWIT=7000 6050 LET NOV=0: LET NOL=0

6059 REM STORE 1'ST CUBE IN ACTUAL (=SETUP) POSITION.

6060 GO SUB IDR3 6070 GO SUB CUBE

6079 REM STORE 2'ND CUBE IN ACTUAL POSITION.

6080 LET TX=3: LET TY=1.5: LET TZ=2: GO SUB TRAN3: GO SUB MULT3 6090 GO SUB CUBE

6099 REM LOOP THROUGH DIFFERENT VIEWING POSITIONS.

6100 GO SUB IDR3: GO SUB LOOK3

6109 REM DRAW THE TWO CUBES IN OBSERVED POSITION.

6110 CLS: GO SUB DRAWIT 6120 GO TO 6100

6130 RETURN LISTING 9.7

6500 REM CUBE/VERTICES AND LINES (STORED)

6501 REM IN - NOV,NOL,R(4,4),X(NOV),Y(NOV),Z(NOV),L(2,NOL)

6502 REM OUT- NOV,NOL,X(NOV),Y(NOV),Z(NOV),L(2,NOL)

6510 DATA 1,1,1,1,1,-1,1,-1,-1,1,-1,1,-1,1,1,-1,1,-1,-1,-1,-1,-1,-1,1 6520 DATA 1,2,2,3,3,4,4,1,5,6,6,7,7,8,8,5,1,5,2,6,3,7,4,8 6530 RESTORE CUBE 6540 LET NV=NOV

6549 REM INPUT AND STORE VERTICES IN POSITION (ACTUAL OR OBSERVED) USING R.

6550 FOR I=1 TO 8

6560 READ XX,YY,ZZ: LET NOV=NOV+1

6570 LET X(NOV)=XX*R(1,1)+YY*R(1,2)+ZZ*R(1,3)+R(1,4) 6580 LET Y(NOV)=XX*R(2,1)+YY*R(2,2)+ZZ*R(2,3)+R(2,4) 6590 LET Z(NOV)=XX*R(3,1)+YY*R(3,2)+ZZ*R(3,3)+R(3,4) 6600 NEXT I

6609 REM INPUT AND STORE LINE INFORMATION.

6610 FOR I=1 TO 12

6620 READ L1,L2: LET NOL=NOL+1

6630 LET L(1,NOL)=L1+NV: LET L(2,NOL)=L2+NV

6640 NEXT I

6650 RETURN

LISTING 9.8

7000 REM DRAWIT

7001 REM IN - NOV,NOL,R(4,4), X(NOV),Y(NOV), Z(NOV),L(2,NOL)

7009 REM MOVE VERTICES INTO OBSERVED POSITION AND DRAW OBJECT.

7010 FOR I=1 TO NOV

7020 LET V(I)=X(I)*R(1,1)+Y(I)*R(1,2)+Z(I)*R(1,3)+R(1,4) 7030 LET W(I)=X(I)*R(2,1)+Y(I)*R(2,2)+Z(I)*R(2,3)+R(2,4)

7040 NEXT I

7050 FOR I=1 TO NOL

7060 LET L1=L(1,I): LET L2=L(2,I)

7070 LET XPT=V(L1): LET YPT=W(L1): GO SUB MOVETO

7080 LET XPT=V(L2): LET YPT=W(L2): GO SUB LINETO

7090 NEXT I

7100 RETURN

Если наблюдатель перемещается по прямой линии и при этом смотрит в одном направлении, то нет необходимости каждый раз заново вычислять матрицу Q, достаточно произвести такое преобразование пространства, чтобы взгляд наблюдателя был направлен вдоль оси Z, а затем использовать подпрограмму "SETORIGIN" для того, чтобы перемещать наблюдателя, вместо того, чтобы перемещать объект. После того как вы освоитесь с методами построения проекций трёхмерных объектов, вам следует тщательно выбирать метод обзора и вычерчивания. Почти всегда существуют способы избежать использования общего метода построения проекций трёхмерных объектов и использовать более простые методы.

Упражнение 9.2

Составьте конструирующие программы для тетраэдра, пирамиды, и т.д.

Например,

(А) Тетраэдр: вершины - (1,1,1), (4,-1,-1), (-1,1,-1) и (-1,-1,1) + ребра - точка 1 соединяется с 2, 1 с 3, 1 с 4, 2 с 3, 2 с 4 и 3 с 4.

(Б) Пирамида с квадратом в основании и высотой HT: вершины (0,HT,0), (1,0,1), (1,0,-1), (-1,0,-1) и (-1,0,1); прямые соединяют 1 с 2, 1 с 3, 1 с 4, 1 с 5, 2 с 3, 3 с 4, 4 с 5 и 5 с 1.

Упражнение 9.3

Нанесите на плоскость X/Y изображение любого плоского объекта, например, букв алфавита, и получите изображение этого объекта с различных точек наблюдения. Вы можете поместить их на грани куба. Все, что вам надо сделать - это дополнить программу "CUBE", с тем, чтобы стало возможным хранить дополнительные вершины и линии, определяющие эти символы.

Пока что мы ограничились изображением простейшего куба. Это делалось для того, чтобы не загромождать наши примеры определением сложных объектов. Наши программы пригодны для любых объектов, лишь бы они не вызывали переполнения памяти. Для сложных объектов мы просто увеличиваем размеры наших массивов, хотя некоторые объекты будут обладать свойствами, позволяющими нам уменьшить количество требуемой памяти. Например, реактивный самолет, показанный на рис. 35, обладает зеркальной симметрией. Предположим, что плоскость симметрии совпадает с плоскостью Y/Z, тогда каждой точке самолета (X,Y,Z) соответствует точка самолёта (-X,Y,Z). Для получения изображения на рис. 35 мы используем листинг 9.1, 9.2 и 9.3 совместно с конструирующей подпрограммой "JET", генерирующей все вершины самолёта с положительными значениями координаты X; это позволяет хранить в памяти информацию только об одной половине самолёта.

Для того чтобы нарисовать самолёт, нам требуется подпрограмма "DRAWIT" (листинг 9.9), которая рисует одну половину самолета, а затем, сменив знак X координаты на противоположный, другую.

Строить подобные фигуры несложно. Нарисуйте интересующие вас фигуры на листе клетчатой бумаги. Пронумеруйте наиболее важные точки фигуры и отметьте, какие из точек соединены линиями. Значения координат легко подсчитать с помощью клеток. Входные данные для рис 35: H0RIZ=160, VERT=120, (EX,EY,EZ)=(1,2,3) и (DX,DY,DZ)=(0,0,0).

Тела вращения

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

Наш метод заключается в том, чтобы определить NUMV линий в плоскости X/Y, которые мы называем набором образующих отрезков. Затем мы вращаем эти отрезки относительно вертикальной оси (оси Y) NUMH-1 раз с тем, чтобы получить новые множества вертикальных отрезков. NUMV отрезков обращающего набора получаются последовательным соединением NUMV+1 вершин (S(I),T(D) (где 1<=I<=NUMV+1). Из этого набора M получаем NUMH различных вертикальных наборов, J-ый вертикальный набор получается вращением набора образующих отрезков на угол PHI+2*PI*(J-1)/NUMH вокруг оси Y, для некоторого значения PHI(0), являющегося входным параметром.

Рис. 36.

Наряду с NUMH*NUMV вертикальными отрезками мы вводим так же горизонтальные прямые. Рассмотрим одну из концевых точек (S(I),T(I),0) отрезка, принадлежащего множеству образующих отрезков: по мере того, как мы вращаем образующие отрезки вокруг оси, он занимает одно из NUMH положений (если только эта точка не расположена на оси вращения).

(S(I)*COS(TETA+0),T(I),S(I)*SIN(TETA+0)),

где TETA=2*PI*(J-1) и 1<=J<=NUMH.

Эти NUMH точек последовательно соединяются, а затем NUMH-ая точка соединяется с первой, что дает набор горизонталей. Всего получается (NUMH-N)*NUMV горизонтальных линий, где N-число вершин на оси вращения. На листинге 9.10 приведена программа "ROTBOD", рисующая тело вращения, если заданы NUMV, NUMH, PHI, первоначальный набор вершин в массивах T и S и матрица R, определяющая положение тела. На листинге 9.11 приведена программа "SCENES", генерирующая изображение сферы, приведенной на рис. 36; начальный набор точек состоит из восьми точек, расположенных на половине полной дуги окружности: HORIZ=3.2, VERT=2.2, PHI=PI/25, NUMH=10, NUMV=8, глаз наблюдателя расположен в точке (1,2,3), а взгляд направлен в точку (0,0,0). В подпрограмме на листинге 9.11 предполагается, что NUMV меньше или равен 15. LISTING 9.9

6000 REM SCENE3/JET

6010 DIM X(37): DIM Y(37): DIM Z(37) 6020 DIM V(37): DIM W(37): DIM L(2,46) 6030 DIM A(4,4): DIM B(4,4): DIM R(4,4) 6040 LET JET=6500: LET DRAWIT=7000 6050 GO SUB IDR3: GO SUB LOOK3 6060 GO SUB JET 6070 GO SUB DRAWIT 6080 RETURN 6500 REM JET

6502 REM OUT - NOV,NOL,X(NOV),Y(NOV),Z(NOV),L(2,NOL)

6510 DATA 0,0,80,0,0,64,0,8,32,4,8,32,8,4,32,8,0,32,4,-4,32,0,8,-32,4,8,-32,8, 4,-32,8,0,-32,4,-4,-32,0,-4,-32,8,0,24

6520 DATA 1,2,2,3,2,4,2,5,2,6,2,7,3,4,4,9,5,10,6,11,7,12,8,9,9,10,10,11,11,12, 12,13,14,15,15,10,15,16,14,16,17,18,17,19,18,19,20,21,21,22,22,23,23,24,24,25

6529 REM SETUP VERTEX AND LINE INFORMATION FOR HALF THE JET.

6530 LET NOV=37: LET NOL=46

6540 FOR I=1 TO NOV: READ X(I),Y(I),Z(I): NEXT I 6550 FOR I=1 TO NOL: READ L(1,I),L(2,I): NEXT I 6560 RETURN

7000 REM DRAWIT/TWO HALFES OF THE JET

7001 REM IN - NOV,NOL,R(4,4),X(NOV),Y(NOV),Z(NOV),L(2,NOL) 7010 LET IS=1

7019 REM LOOP THROUGH TWO HALFES OF THE JET.

7020 FOR J=1 TO 2 7030 FOR I=1 TO NOV

7040 LET XX=IS*X(I): LET YY=Y(I): LET ZZ=Z(I)

7049 REM PUT VERTICES IN OBSERVED POSITION.

7050 LET V(I)=XX*R(1,1)+YY*R(1,2)+ZZ*R(1,3)+R(1,4) 7060 LET W(I)=XX*R(2,1)+YY*R(2,2)+ZZ*R(2,3)+R(2,4) 7070 NEXT I

7080 FOR I=1 TO NOL

7090 LET L1=L(1,I): LET L2=L(2,I)

7100 LET XPT=V(L1): LET YPT=W(L1): GO SUB MOVETO

7110 LET XPT=V(L2): LET YPT=W(L2): GO SUB LINETO

7120 NEXT I

7130 LET IS=-1

7140 NEXT J

7150 RETURN

LISTING 9.10

6000 REM SCENE3/SPHEROID

6010 DIM X(32): DIM Y(32)

6020 DIM A(4,4): DIM В(4,4): DIM R(4,4)

6030 DIM S(16): DIM T(16)

6040 LET REVBOD=6500

6050 INPUT "NUMBER OF HORIZONTAL LINES=";NUMH 6060 INPUT "NUMBER OF VERTICAL LINES=";NUMV 6070 INPUT "ANGLE PHI=";PHI 6080 LET THETA=PI/2: LET TD=PI/NUMV

6089 REM GENERATE DEFINITION SET

6090 FOR I=1 TO NUMV+1

6100 LET S(I)=COS THETA: LET T(I)=SIN THETA 6110 LET THETA=THETA+TD 6120 NEXT I

6130 GO SUB IDR3: GO SUB LOOK3 6140 GO SUB REVBOD 6150 RETURN Упражнение 9.4

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

LISTING 9.11

6500 REM REVBOD/BODY OF REVOLUTION

6501 REM IN - PHI,NUMH,NUMV,S(NUMV+1),T(NUMV+1),R(4,4)

6509 REM CREATE FIRST VERTICAL SET.

6510 LET THETA=PHI: LET TD=PI*2/NUMH

6520 LET N1=NUMV+1: LET C=COS PHI: LET S=SIN PHI 6530 FOR I=1 TO N1

6540 LET XX=S(I)*C: LET YY=T(I): LET ZZ=S(I)*S 6550 LET X(I)=XX*R(1,1)+YY*R(1,2)+ZZ*R(1,3)+R(1,4) 6560 LET Y(I)=XX*R(2,1)+YY*R(2,2)+ZZ*R(2,3)+R(2,4) 6570 NEXT I

6579 REM LOOP THROUGH SECOND VERTICAL SET.

6580 FOR J=1 TO NUMH

6590 LET THETA=THETA+TD: LET C=COS THETA: LET S=SIN THETA 6600 FOR I=1 TO N1

6610 LET XX=S(I)*C: LET YY=T(I): LET ZZ=S(I)*S 6620 LET X(I+N1)=XX*R(1,1)+YY*R(1,2)+ZZ*R(1,3)+R(1,4) 6630 LET Y(I+N1)=XX*R(2,1)+YY*R(2,2)+ZZ*R(2,3)+R(2,4) 6640 NEXT I

6649 REM DRAW LINES IN FIRST VERTICAL SET.

6650 LET XPT=X(1): LET YPT=Y(1): GO SUB MOVETO 6660 FOR I=2 TO N1

6670 LET XPT=X(I): LET YPT=Y(I): GO SUB LINETO 6680 NEXT I

6689 REM JOIN CORRESPONDING HORIZONTAL ON THE TWO VERTICAL SETS.

6690 FOR I=1 TO N1

6700 LET XPT=X(I): LET YPT=Y(I): GO SUB MOVETO 6710 LET XPT=X(I+N1): LET YPT=Y(I+N1): GO SUB LINETO

6719 REM COPY SECOND VERTICAL SET INTO FIRST REPIAT PROCESS.

6720 LET X(I)=XPT: LET Y(I)=YPT 6730 NEXT I

6740 NEXT J 6750 RETURN

Можно предложить следующее обобщение нашего метода: по мере вращения вокруг центральной оси Y-координаты точек, не остаются постоянными, а изменяются по определенному закону; например, уменьшаются на некоторую величину при каждом вращении на 2PI/NUMH. Теперь имеет смысл позволить точке совершать более одного оборота вокруг оси.

Список программ

С настоящего момента мы будем именовать листинги 3.4 ("ANGLE"), 8.1 ("MULT3" и "IDR3"), 8.2 ("TRAN3"), 8.3 ("SCALE3"), 8.4 ГКОТЗ"), 9.1 ("L00K3") и 9.2 ("MAIN PROGRAM") как "LIB3".

1. "LIB1", "LIB3" и листинги 9.3 ("SCENE3") и 9.4 ("CUBE"). Необходимые данные: HORIZ, VERT, (EX,EY,EZ) и (DX,DY,DZ). Попробуйте задать значения 9, 6, (1,2,3), (-1,0,1).

2. "LIB1", "LIB3" и листинги 9.5 ("SCENES") и 9.4 ("CUBE"). Необходимые данные: HORIZ, VERT, (EX,EY,EZ) и (DX,DY,DZ). Попробуйте значения 9, 6, (1,2,3), (-1,0,1). Последовательно изменяйте один из параметров при фиксированных остальных параметрах.

3. "LIB1", "LIB3" и листинг 9.6 ("SCENES"), 9.7 ("CUBE") и 9.8 ("DRAWIT"). Необходимая информация: HORIZ, VERT, и затем повторный ввод величин (EX,EY,EZ), (DX,DY,DZ). Попробуйте ввести 9, 6, затем (1,2,3), (1,0,1), (3,2,1), (0,0,1). Проведите систематическое изменение величин параметров.

4. "LIB1", "LIB3" и листинги 9.10 ("SCENES") и 9.11 ("REVBOD"). Необходимая информация: HORIZ, VERT, NUMV (<=15), PHI, (EX,EY,EZ) и (DX,DY,DZ). Попробуйте ввести 3.2, 2.2, 10, 10, 1, (1,2,3), (0,0,0); (3,2,1), (0,0,0).




СОДЕРЖАНИЕ:
  1. Трёхмерная декартова геометрия - Определение прямой; Угол между двумя направляющими векторами; Определение плоскости70 Точка пересечения прямой и плоскости; Расстояние от точки до прямой; Точка пересечения двух прямых; Плоскость, проходящая через три неколлинеарные точки; Точка пересечения трёх плоскостей; Линия пересечения двух плоскостей; Функциональное представление поверхности; Лежит ли точка по ту же сторону от плоскости, что и начало координат?; Каково направление обхода двумерного многоугольника, заданного последовательностью своих вершин?


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
В гостях у сказки - Сказка о рыбаке и рыбке (в компьютерном изложении).
7 Origins - Семерка лучших origin'ов-мудрых и не очень выражений.
От автора - С новым 2000 годом...
Windows' 95 info - Сообщение о Microsoft Windows BS extra.
ГонЫ - Лесом Схожу: прогон от Ironman'a.

В этот день...   29 марта