C++Builder. Учебный курс
.pdf11.4.4. Освещение
OpenGL использует модель освещенности, в которой свет приходит из нескольких источников, каждый из которых может быть включен или выключен. Для использования в программе ис точника света необходимо командой
glE nable(G L _L IG H T IN G );
разрешить работу с освещенностью и командой
g l E n a b l e (GL_LIGHT0) ;
включить источник света. Это минимальные действия для включения источника света. При необходимости можно «устано вить» несколько источников, например:
g l E n a b l e (GL_LIGHT1) ; / / включаем источник света 1
Все добавляемые источники света используют установки, принятые по умолчанию, и ничем не отличаются друг от друга. Источник света по умолчанию располагается в пространстве в точке с координатами (0, 0, 1). При построениях необходимо зада вать вектор нормали, используемый для расчета цветовых пара метров каждого пиксела.
Предыдущие примеры вряд ли могут удовлетворить коголибо в силу своей невыразительности. Рисуемый кубик скорее угадывается, все грани покрыты монотонным цветом, за которым теряется пространство. В следующем примере кубик рисуется бо лее реалистично.
Пример 11.15
- В секции p r i v a t e определения класса формы объявите переменные:
HDC DC;
HGLRC h r e ;
- Создайте обработчик события OnCreate.
v o id __f a s t c a l l T Form l: : FormCreate (TObject *Sender)
{
DC = G e tD C ( H a n d l e ) ;
S e t D C P i x e lF o r m a t ( D C ) ;
h r c = w g l C r e a t e C o n t e x t ( D C ) ;
w glM akeC urrent(D C , |
h r c ) ; |
|
|
g l C l e a r C o l o r ( 0 . 5 , 0 . 5 , 0 . 7 5 , 1 . 0 ) ; |
|||
g l C o l o r 3 f ( 0 . 0 , 0 . 5 , 0 . 0 ) ; |
|||
glEnable(G L _ LIG H TIN G ); |
|
||
g lE n a b le (G L _ L IG H T 0 ); |
|
|
|
glEnable(GL_DEPTH_TEST); |
|
||
} |
|
|
|
При создании окна включается источник света: |
|||
g l E n a b l e (GL__LIGHTING) ; |
/ / |
разрешаем р а б о т у |
|
|
|
/ / |
с освещенностью |
glE nable(G L _ L IG H T 0) ; |
/ / |
включаем источник с в е т а |
Это минимальные действия для включения источника света. Теперь в сцене присутствует один источник света с номером 0.
- Создайте обработчик события O n D e s tr o y .
v o id __f a s t c a l l T F o r m l : : F o r m D e s t r o y ( T O b j e c t * S ender)
{
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 s e D C ( H a n d le , |
DC); |
D e le te D C (D C ); |
|
}
- Создайте обработчик события O n P a in t .
v o id __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 e n d e r )
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) ;
glBegin(GL_QUADS);
g l N o r m a l 3 f ( 0 . 0 , 0 . 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 V e r t ex 3 f ( 1 . 0 , - 1 . 0 , 1 . 0 ) ;
g l E n d ( ) ;
g l B e g i n (Gli_QUADS) ;
g l N o r m a l 3 f ( - 1 . 0 , 0 . 0 , 0 . 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 V e r t e x 3 f ( - 1 . 0 , - 1 . 0 , 1 . 0 ) ;
g l E n d ( ) ;
glBegin(GL_QUADS) ;
g l N o r m a l 3 f (0 . 0 , 1 . 0 , 0 . 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 V e r t e x 3 f (1 . 0 , 1 . 0 , - 1 . 0 ) ; g l E n d ( ) ;
SwapBuffers(DC) ;
}
Для сокращения кода из шести сторон куба остаются только три непосредственно видимые наблюдателю. При рисовании каж дой стороны куба задается вектор нормали, используемый для расчета цветовых параметров каждого пиксела. Вектора нормалей строятся перпендикулярно каждой стороне куба. В силу того, что наш кубик строится вокруг точки (0, 0, 0), аргументы g lN o rm a l3 f в данном случае совпадают с точкой пересечения диагоналей каждой грани куба. Вектор нормали не обязательно должен исходить именно из середины площадки, достаточно того, чтобы он был параллелен действительному вектору нормали к площадке.
- Создайте обработчик события OnResize.
Если режим GL_COLOR_MATERlAL не включен, то текущие цветовые установки не влияют на цвет поверхности куба, поэтому он выглядит серым, хотя текущий цвет задан зеленоватым. Попут но обращу ваше внимание на то, что если объект приближается чересчур близко к глазу наблюдателя и пересекает ближнюю плоскость отсечения, в нем появляется дырка, сквозь которую можно заглянуть внутрь объекта. Кроме того, существует еще об щее фоновое (am bient) освещение.
Для правильного освещения объектов необходимо для каждой грани задать материал, обладающий определенными свойствами. Материал может испускать свой собственный свет, рассеивать па дающий свет во всех направлениях (диффузное отражение) или подобно зеркалу отражать свет в определенных направлениях. Пользователь может определить до восьми источников света и их свойства, такие, как цвет, положение и направление. Большинство параметров источника света задается с помощью, например ко манды g l L i g h t f v .
glLicjhtfv(GL _LIGHT0, GL_POSITION, p o s i t i o n ) ;
Первый параметр команды - идентификатор источника света; второй аргумент - символическая константа, указывающая, какой атрибут устанавливается. Последний аргумент - имя массива, со держащего задаваемые значения. Для задания позиции использу ется символическая константа GL_P0SITI0N, указываемый мас сив определяет позицию источника света в текущей системе коор динат, например:
G L f lO a t p o s i t i o n [4] = {0 .0, 0 . 0 , 1 . 5, 1.0} ;
В некоторых ситуациях необходимо, чтобы при определен ных положениях точки зрения наблюдателя примитив не отобра жался вообще, например, при воспроизведении объектов, обра зующих замкнутый объем, нет необходимости тратить время на воспроизведение примитивов, заведомо нам не видимых, раз они
повернуты к нам задней стороной. Для этого необходимо вклю чить отсечения задних сторон многоугольников:
g l E n a b l e (GL_CULL_FACE) ;
11.5. Надстройки над OpenGL
Существует несколько надстроек над OpenGL, представляю щих собой набор готовых команд для упрощения кодирования. Стандартной надстройкой, поставляемой вместе с OpenGL, явля ется библиотека g lu , физически располагающаяся в файле g lu 3 2 . d l l . Мы уже изучили несколько команд этой библиотеки, и в дальнейшем продолжим ее изучение. Помимо этой стандарт ной надстройки наиболее популярной является библиотека g lu t . Для программистов, пишущих на языке С, эта библиотека особен но привлекательна, поскольку является независимой от операци онной системы. Ее применение значительно упрощает кодирова ние программ, поскольку, например, для рисования куба с единич ной длиной ребра вместо двух десятков строк теперь достаточно одной:
g l u t S o l i d C u b e ( 1 .0) ;
Помимо куба, модуль (и библиотека) содержит команды вос произведения сферы, тора, конуса и некоторых правильных много гранников, таких как тетраэдр и додекаэдр. Есть здесь и команда для рисования классического объекта для тестовых программ ма шинной графики - чайника. Команды из этой библиотеки начина ются с префикса g l u t . Ниже приводятся примеры для рисования других геометрических фигур:
g l u t S o l i d S p h e r e ( 1 . 5 , 20, |
2 0 ) ; |
||
g l u tS o l id C o n e ( 0 . 5 , |
1 . 5 , |
20, |
2 0 ) ; |
g l u t S o l i d T o r u s ( 0 . 5 , |
1 . 5 , |
20, |
2 0 ) ; |
g lu tS o lid D o d e c a h e d r o n (); g l u t S o l i d l c o s a h e d r o n (); g l u t S o l i d T e t r a h e d r o n ()
g l u t S o l i d T e a p o t ( 1 . 5 ) ;
Для подключения библиотеки g l u t необходимо выполнить
следующие действия:
-Поместить в заголовочном файле модуля команду препро цессора:
# in c lu d e < g l \ g l u t . h>
|
- Скопировать в папку С : \P r o g r a m |
F i l e s \ C o d e G e a r \ |
|||||||
RAD |
S t u d i o \ 5 . 0 \ i n c l u d e \ g l файл g l u t |
.h . |
|||||||
|
-Скопировать |
в |
папку |
C : \ P r o g r a m |
F i l e s \ C o d e G e a r \ |
||||
RAD |
S t u d i o \ 5 . 0 \ l i b файл g l u t 3 2 . l i b . |
|
|||||||
|
-Скопировать |
в |
папку |
C :\W in d o w s \s y s te m 3 2 файл |
|||||
g l u t 3 2 . d l l . |
|
|
|
|
|
|
|
||
|
- В |
секции |
p r i v a t e |
определения |
класса формы объявите |
||||
переменные: |
|
|
|
|
|
|
|
||
HDC DC; |
|
|
|
|
|
|
|
||
HGLRC |
h r с ; |
|
|
|
|
|
|
|
|
|
-Создайте |
обработчик |
события O n C reate формы. Само |
стоятельно разберитесь с назначением каждого оператора обра ботчика.
v o id __f a s t c a l l |
T Form l: : F o rm C reate(T O b ject *Sender) |
{ |
|
C lie n tW id th = |
C lie n tH e ig h t+ P a n e ll- > W id th ; |
R a d io G ro u p l-> lte m ln d e x = 2; DC = G etD C (H andle);
SetD C P ixelF orm at(D C );
h rc = w g lC re a te C o n te x t(D C );
wglM akeCurrent(DC, |
h r c ) ; |
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 ) ; g lL in e W id th ( 1 . 5 ) ;
g l P o i n t S i z e (5) ;
g lE n a b le (GL_POINT__SMOOTH) ; g l E n a b l e (GL_LIGHTING);
glEnable(GL_LIGHTO) ; glEnable(GL_DEPTH_TEST) ;
g l N o r m a l 3 f ( - 1 . 0 , 0 . 0 , 0 . 0 ) ;
- Создайте обработчик события O nD e stroy .
v o i d __ f a s t c a l l T F orm 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 );
}
- Создайте обработчик события O n P a in t .
v o id __f a s t c a l l T F orm l:: FormPaint (TObject ^Sender)
{
g l C l e a r (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ; g l u t S o l i d C u b e (1 .5) ;
S w a p B u f f e r s ( D C ) ;
}
- Создайте обработчик события OnResize.
v o id __f a s t c a l l T F orm l:: FormResize (TObject ‘ Sender)
{
g l V i e w p o r t (0, 0, C lie n tW id th - P a n e ll - > W id th / C l i e n t H e i g h t );
glMatrixMode(GL_PROJECTION) ;
g l L o a d l d e n t i t y ( ) ; |
|
|
|
g l F r u s t u m f - l , 1, |
-1, 1, |
4, |
15); |
g lM atrix M o d e (GL__MODELVIEW) ; |
|
||
g l L o a d l d e n t i t y () ; |
|
|
|
/ / э т о т фрагмент |
нужен |
для |
придания трёхмерности |
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 ) ; |
-Создайте обработчик события O n C lic k компонента R a
d i o g r o u p l .
void __fastcall T F o r m l : : R a d i o G r o u p l C l i c k ( T O b j e c t * S e n d e r )
{
switch ( R a d i o G r o u p l - > l t e m l n d e x )
{
case 0:
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break;
case 1:
glPolygonM ode (GL_FRONT_AND_BACK, GL_LINE) ; break;
case 2:
glPolygonMode(GL_FRONT_AND_BACK, GL _FILL);
}
I n v a l i d a t e R e c t ( H a n d l e , NULL, false);
}
- Запустите приложение и проверьте правильность его работы. Для того, чтобы можно было вращать куб с помощью мыши
доработайте программу следующим образом. - Объявите глобальные переменные:
int x l , у1 ,*
B o o le a n Down = false;
- Создайте обработчик события OnMouseDown формы.
void __fastcall T F o r m l : : FormMouseDown(TObject
* S e n d e r , TM ouseButton B u t t o n , T S h i f t S t a t e S h i f t , int X, int Y)
{
Down = true; x l = X;