Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

1102

.pdf
Скачиваний:
2
Добавлен:
15.11.2022
Размер:
9.54 Mб
Скачать

Пример 11.7

g lB e g in (GL_POLYGON);

f o r ( in t i = 0 ; i<=6; i++)

{

glColor3f(Random(), Random() , Random()); g l V e r t e x 2 f ( 0 . 7*cos(2*M_PI*i/6) ,

0 . 7*sin(2*M_PI*i/6) ) ;

}

g lE n d ();

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

Замечание. Для воспроизведения треугольников и четырех­ угольников лучше не использовать примитив GL_P0LYG0N, в та­ ких случаях оптимальным будет использование примитивов, спе­ циально предназначенных для этих фигур.

11.3.Преобразования

11.3.1.Масштабирование

Мы уже знаем, что границы области вывода лежат в пределах от - 1 до 1. Это может привести к неудобству при подготовке изо­ бражений. К счастью, OpenGL предоставляет удобное средство на этот случай - масштабирование. Для изменения масштаба исполь­ зуется команда g l S c a l e f с тремя аргументами, представляющи­ ми собой масштабные множители для каждой из осей:

glScalef(m x, my, mz)/

Например, если перед командными скобками вставим строку

g l S c a l e f ( 0 . 5 , 0 . 5 , 1 . 0 ) ;

то будет нарисована уменьшенная в два раза фигура. После ко­ манд рисования необходимо восстановить нормальный масштаб, т.е. в данном случае добавить строку:

g l S c a l e f ( 2 . 0 , 2 . 0 , 1 . 0 ) ;

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

11.3.2. Поворот

Для поворота системы координат используется команда g l R o t a t e f с четырьмя аргументами: угол поворота в градусах и вектор поворота (три вещественных числа). Для двумерных по­ строений наиболее нагляден поворот вокруг оси Z. Реализуйте в C++Builder следующий пример:

Пример 11.8

- В обработчик события O n P a in t формы добавьте следую­ щие строки:

g l R o t a t e f (10, 0 . 0 , 0 . 0 , 1 . 0 ) ; glBegin(GL_QUADS);

g l V e r t e x 2 f ( 0 . 0 , 0 . 0 ) ; g lV e r te x 2 f ( 0 . 8 , 0 . 0 ) ; g l V e r t e x 2 f ( 0 . 6 , 0 . 5 ) ; g l V e r t e x 2 f ( 0 . 0 , 0 . 5 ) ;

g l E n d ( ) ;

- Создайте обработчик события O nK eypress с единственной командой I n v a l i d a t e ()

Теперь при нажатии любой клавиши окно перерисовывается, при этом каждый раз прямоугольник поворачивается на 10 граду­ сов вокруг оси Z. Здесь надо обратить внимание на следующие моменты:

-при положительном значении компоненты вектора поворот осуществляется против часовой стрелки;

-важно не само значение компоненты вектора, а ее знак и равенство/неравенство ее нулю.

-Измените код программы, чтобы поворот осуществлялся вокруг оси X или Y.

Точно так же, как было с масштабом, поворот действует на все последующие команды воспроизведения, так что при необхо­ димости текущее состояние восстанавливается обратным поворо­ том.

-Чтобы вы могли оценить преимущества использования «низкоуровневых» приемов программирования измените обработ­ чик события O n K ey P ress формы.

void __fastcall T F o rm l: : FormKeyPress (TObject * S e n d e r, c h a r &Key)

{

switch (Key)

{

case VK_SPACE:

I n v a l i d a t e () ; break;

case VK_RETURN:

I n v a l i d a t e R e c t (H andle, NULL, f a ls e ) ;

}

Окно перерисовывается в этих случаях по-разному: в первом случае хорошо заметно мерцание формы, во втором случае проис­

ходит только перерисовка изображения и мерцание формы неза­ метно.

11.3.3. Перенос

Перенос системы координат осуществляется командой g l T r a n s l a t e f с тремя аргументами - величинами переноса для каждой из осей:

g l T r a n s l a t e f ( d x , dy,

d z ) ;

 

 

Ниже

приведен

пример

использования

команды

g l T r a n s l a t e f .

Пример 11.9

g l T r a n s l a t e f ( 0 . 2 , 0 . 3 , 0 . 0 ) ; glBegin(GL_QUADS);

g l V e r t e x 2 f (0 . 0 , 0 . 0 ) ; g l V e r t e x 2 f ( 0 . 6 , 0 . 0 ) ; g l V e r t e x 2 f ( 0 . 4 , 0 . 5 ) ; g l V e r t e x 2 f ( 0 . 0 , 0 . 5 ) ;

g l E n d ( ) ;

g l T r a n s l a t e f ( - 0 . 2 , - 0 . 3 , 0 . 0 ) ;

Все сказанное по поводу восстановления системы координат справедливо и в отношении переноса.

11.3.4. Сохранение и восстановление текущего положения

При повороте и переносе изображения приходится постоянно следить, чтобы после рисования система координат вернулась на прежнее место. Для этого мы пользовались обратными поворотами и перемещениями. Такой подход неэффективен и редко встречает­ ся в примерах и профессиональных программах, потому что функ­ ции g l R o t a t e f и g l T r a n s l a t e f реализуются как перемноже­ ние текущей матрицы на матрицы поворота и переноса соответст­ венно. Поэтому вместо обратных переносов и поворотов используются команды g l P u s h M a t r i x и g lP o p M a tr ix . Коман­

да g lP u s h M a tr ix запоминает значение текущей матрицы, а ко­ манда g lP o p M a tr ix восстанавливает матрицу. Эти команды оперируют со стеком. Использование этих функций делает код более понятным, а воспроизведение - более быстрым. Для боль­ шей ясности пример 11.9 из предыдущего раздела можно было бы записать следующим образом:

g lP u s h M a trix ( );

g l T r a n s l a t e f (0 .2 , 0 .3 , 0 .0 ); glBegin(GL_QUADS);

g lV e r te x 2 f (0 .0 , 0 . 0 ) ; g lV e r te x 2 f (0 .6 , 0 . 0 ) ; g lV e r te x 2 f (0 .4 , 0 . 5 ) ; g lV e r te x 2 f (0 .0 , 0 . 5 ) ;

g l E n d ();

g lP o p M a trix ( );

Перед операцией переноса запоминаем текущую систем)’ ко­ ординат (g lP u s h M a trix ), а после рисования четырехугольника - восстанавливаем ее (g lP o p M a trix ).

11.4. Построения в пространстве

Главной темой этого раздела является трехмерная графика. Начнем мы с обзора методов, позволяющих достичь объемности получаемых образов, а в конце раздела будут описаны методы по­ строения анимационных программ. Раздел завершает базовый курс изучения основ OpenGL, и после его изучения вы сможете созда­ вать высококачественные трехмерные изображения. По умолча­ нию объем сцены ограничен кубом с координатами точек вершин по диагоналям (-1, -1, -1) и (1,1,1).

11.4.1.Параметры вида

Впроцессе построения изображения координаты вершин подвергаются определенным преобразованиям. Подобным преоб­ разованиям подвергаются заданные векторы нормали. В OpenGL

существуют две матрицы, последовательно применяющиеся в пре­

образовании координат.

Одна из них -

матрица

моделирования

(m o d e lv ie w

m a tr ix ) ,

а другая -

матрица

проектирования

( p r o j e c t i o n

m a tr ix ) .

Первая служит для задания положения

объекта и его ориентации, вторая отвечает за выбранный способ проектирования. OpenGL поддерживает два типа проектирования - параллельное и перспективное.

Существует набор различных процедур, умножающих теку­ щую матрицу (моделирования или проектирования) на матрицу выбранного геометрического преобразования. Текущая матрица задается при помощи команды g lM a trix M o d e , имеющей один параметр, который может принимать значения GL__MODELVIEW, GL_PROJECTION или GL__TEXTURE, позволяя выбирать в качест­ ве текущей матрицы матрицу моделирования (видовую матрицу), матрицу проектирования или матрицу преобразования текстуры. Процедура g l L o a d l d e n t i t y устанавливает единичную теку­ щую матрицу. Обычно задание соответствующей матрицы начи­ нается с установки единичной и последовательного применения матриц геометрических преобразований.

11.4.1.1. Использование функции glFrustum

Для задания перспективного преобразования в OpenGL слу­ жит команда:

v o i d g lF r u s tr u m (G L d o u b le

l e f t ,

G Ldoubie

r i g h t ,

G Ldouble

b o tto m , G Ldouble

to p /

G Ldouble

n e a r ,

G Ldouble

f a r ) ;

 

 

 

Смысл передаваемых параметров ясен из рис. 11.2. Изначаль­ но камера находится в начале координат и направлена вдоль отри­ цательного направления оси Z. Обратите внимание на то, что в момент применения матрицы проектирования координаты объек­ тов уже переведены в систему координат камеры. Величины n e a r и f a r должны быть неотрицательными.

Дальнее

Рис. 11.2. К использованию команды g lF r u s tu m

Для задания параметров вида, в частности, определяющих об­ ласть воспроизведения в пространстве используется функция g lF ru s tu m . Все, что выходит за пределы этой области, будет от­ секаться при воспроизведении. Первые 2 аргумента задают коор­ динаты плоскостей отсечения слева и справа, третий и четвертый параметры определяют координаты плоскостей отсечения снизу и сверху. Последние аргументы задают расстояния до ближней и дальней плоскостей отсечения. Значения этих двух параметров должны быть положительными - это не координаты плоскостей, а расстояния от глаза наблюдателя до плоскостей отсечения.

Устанавливать видовые параметры не обязательно при каж­ дой перерисовке экрана, достаточно делать это лишь при измене­ нии размеров окна.

Пример 11.10

Попробуем нарисовать что-нибудь объемное, например, куб. Для придания трехмерности сцене поворачиваем ее по осям:

void __fastcall T F o rm l: : FormResize (TObject *Sender)

{

g l V i e w p o r t (0,

0,

C l ie n tW i d th , C lie n tH e ig h t) ;

g l L o a d l d e n t i t y () ;

 

g l F r u s t u m ( - l ,

1,

- 1 , 1, 3, 10);

g l T r a n s l a t e f (0 . 0 , 0 . 0 , - 8 . 0 ) ;

g l R o t a t e f

( 3 0 . 0 ,

1 . 0 ,

0 . 0 ,

0 . 0 ) ;

g l R o t a t e f

( 7 0 . 0 ,

0 . 0 ,

1 . 0 ,

0 . 0 ) ;

}

Построение куба сводится к построению шести квадратов, от­ дельно для каждой стороны фигуры:

v o i d __ f a s t c a l l T F o r m l : : F o r m P a i n t ( T O b j e c t *S ender)

{

glClear(GL_COLOR_BUFFER_BIT);

glBegin(GL_QUADS);

g l V e r t e x 3 f ( 1 . 0 , 1 . 0 , 1 . 0 ) ; g l V e r t e x 3 f ( - 1 . 0 , 1 . 0 , 1 . 0 ) ;

g l V e r t e x 3 f ( - 1 . 0 , - 1 . 0 , 1 . 0 ) ; g l V e r t e x 3 f ( 1 . 0 , - 1 . 0 , 1 . 0 ) ;

g l E n d ( ) ;

glBegin(GL_ QUADS);

g l V e r t e x 3 f ( 1 . 0 , 1 . 0 , - 1 . 0 ) ;

g l V e r t e x 3 f ( 1 . 0 , - 1 . 0 ,

- 1 . 0 ) ;

g l V e r t e x 3 f ( - 1 . 0 , - 1 . 0 ,

- 1 . 0 ) ;

g l V e r t e x 3 f ( - 1 . 0 , 1 . 0 ,

- 1 . 0 ) ;

g l E n d ( ) ;

 

glBegin(GL_ QUADS);

g l V e r t e x 3 f ( - 1 . 0 , 1 . 0 , 1 . 0 ) ;

g l V e r t e x 3 f ( - 1 . 0 , 1 . 0 ,

- 1 . 0 ) ;

g l V e r t e x 3 f ( - 1 . 0 ,

- 1 . 0 ,

- 1 . 0 ) ;

g l V e r t e x 3 f ( - 1 . 0 ,

- 1 . 0 , 1 . 0 ) ;

g l E n d ( ) ;

 

 

glBegin(GL_QUADS);

g l V e r t e x 3 f ( 1 . 0 ,

1 . 0 , 1 . 0 ) ;

g l V e r t e x 3 f ( 1 . 0 ,

- 1 . 0 , 1 . 0 ) ;

g l V e r t e x 3 f ( 1 . 0 ,

- 1 . 0 ,

- 1 . 0 ) ;

g l V e r t e x 3 f ( 1 . 0 ,

1 . 0 ,

- 1 . 0 ) ;

g l E n d ( ) ;

glBegin(GL_QUADS);

 

 

g l V e r t e x 3

f

(- 1. 0,

1.0,

- 1 . 0);

g l V e r t e x 3

f

( - 1.0,

1.0,

1. 0);

g l V e r t e x 3 f

(1.0,

1.0,

1. 0);

g l V e r t e x 3 f (1.0, 1.0, - 1 . 0) ;

g l E n d ;

 

 

 

 

glBegin(GL_QUADS);

 

 

g l V e r t e x 3 f ( - 1 . 0,

- 1.0,

- 1 . 0);

g l V e r t e x 3 f ( 1 . 0 , - 1 . 0 , - 1 . 0 ) ; g l V e r t e x 3 f ( 1 . 0 , - 1 . 0 , 1 . 0 ) ; g l V e r t e x 3 f ( - 1 . 0 , - 1 . 0 , 1 . 0 ) ;

g l E n d ( ) ;

S w a p B u f f e r s ( D C ) ;

}

- Создайте обработчики событий O nC reate и OnDestroy.

void __fastcall T F o rm l: :FormCreate (TObject *Sender)

{

DC = G e tD C ( H a n d le ) ;

 

S e tD C P ix e lF o r m a t( D C ) ;

 

h r c

= w g lC re a te C o n te x t(D C )

;

wglM akeCurrent(DC,

h rc ) ;

 

g l C l e a r C o l o r ( 1 . 0 , 1 . 0 , 1 . 0 , 1 . 0 ) ;

/ /

g l C l e a r C o l o r (0 . 5 , 0 . 5 ,

0 .75, 1 . 0 ) ;

g l C o l o r 3 f ( 1 . 0 , 0 . 0 , 0 . 5 ) ;

 

}

 

 

 

v o i d

__ f a s t c a l l T F o rm l:: FormDestroy (TObject *Sender)

{

 

 

 

w g l M a k e C u r r e n t (0,

0 ) ;

 

w g l D e l e t e C o n t e x t ( h r c ) ;

 

R e le a se D C (H a n d le ,

DC);

 

D e le te D C (D C );

 

 

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]