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

kniga

.pdf
Скачиваний:
224
Добавлен:
17.05.2015
Размер:
29.65 Mб
Скачать

//відображається правий синій многокутник glColor3f (1.0, 0.0, 0.0);

glTranslatef (300.0, 50.0, 0.0); //задаються параметри зсуву glRecti (100, 100, 200, 150);

//відображається червоний зсунутий прямокутник

Якщо після цього в приладі 16.3 захочемо вихідний прямокутник повернути відносно осі z, то поточну матрицю потрібно зробити одиничною і створити матрицю повороту за допомогою команди

glRotatef (90.0, 0.0, 0.0, 1.0);.

 

 

 

 

y

 

 

 

 

 

 

 

 

 

150

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

100

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

50

 

 

 

 

x

 

 

 

 

 

 

 

 

–200

–100

O

100

200

 

Рис. 16.2. Зсув прямокутника

Далі виконується згортка цієї матриці з поточною одиничною матрицею, і якщо тепер викликати процедуру побудови вихідного прямокутника, то одержимо вже повернутий на 900 прямокутник.

Якщо поточну матрицю не робити одиничною, а викликати процедуру glRotatef (90.0, 0.0, 0.0, 1.0);, то повернеться вже зсунутий прямокутник, тобто перетворення об’єднаються.

Отже, складні перетворення формуються множенням матриць зміщення, повороту, масштабування та інших перетворень. При цьому варто пам’ятати, що множення матриць некомутативне.

OpenGL містить стек матриць для кожного з трьох типів перетворень, при цьому поточну матрицю можна помістити в стек або зняти матрицю з вершини стека і зробити її поточною. Існують процедури для обробки стеків. Для розміщення поточної матриці в стек служить процедура

void glPushMatrix( );,

для зняття матриці зі стека – процедура void glPopMatrix( );.

311

Перетворення проектування визначає, як саме будуть проектуватися об’єкти на екран і які частини об’єкта будуть відсікатись як такі, що не попадають у поле зору. OpenGL підтримує декілька різновидів проекцій.

У випадку паралельного проектування видимим об’ємом є прямокутний паралелепіпед, який обмежується межами відсікання. Для задання паралельного проектування служить процедура

void glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far).

Параметри left і right визначають координати лівої і правої (вертикальних), bottom і top – нижньої і верхньої (горизонтальних), а near, far

– передньої і задньої площин відсікання.

Поле зору при перспективному проектуванні є зрізаною пірамідою

(рис. 16.3).

Рис. 16.3. Піраміда видимості при центральному проектуванні

Для задання перспективного проектування в OpenGL створено ряд процедур, наприклад

void gluPerspective (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);.

Ця процедура створює матрицю для задання симетричного поля зору і множить поточну матрицю на неї. Значення параметрів процедури: fovy – кут зору камери в площині Oxz (лежить у діапазоні від 00 до 1800), aspect – відношення ширини області до її висоти (aspect = w/n), параметри zNear і zFar – відстань уздовж від’ємного напряму осі Oz, що визначає ближню і дальню площини відсікання.

В OpenGL точка огляду спочатку автоматично розташовується в центрі світових координат. Напрямок зору – вздовж від’ємного напряму

312

осі z. Щоб зробити можливим огляд об’єктів сцени з будь-якої точки, необхідно сформувати видову матрицю. Матрицю видового перстворення можна сформувати за допомогою функцій glTranslate, glRotate. Найпростіший спосіб змоделювати камеру, що розташована в точці (x, y, z) і направлена на точку (xp, yp, zp) – це використати функцію gluLookAt:

glMatrixMode (GL_MODELVIEV);//визначаємо видову матрицю glLoadIdentity();//спочатку одинична матриця

gluLookAt (x,y,z,xp,yp,zp,1,0,0); //формуємо видову матрицю Тепер точка огляду знаходиться в центрі видової системи координат.

16.4. Функції виведення тривимірних об’єктів

Функції для створення правильних многогранників передбачені в процедурах бібліотеки GLUT. Ця бібліотека пропонує 10 функцій генерування платонових тіл: 5 функцій виводять каркасні об’єкти, а інших 5

– зображають грані як зафарбовані об’єкти. Характеристики зафарбовуваної області визначаються властивостями матеріалу й умовами освітлення.

Наприклад, гексаедр (куб) виводиться за допомогою функцій glutWireCube(edgeLenght); // каркасний куб, glutSolidCube(edgeLenght); // куб із зафарбованими гранями.

Параметру edgeLengh може бути присвоєно будь-яке додатне значення подвійної точності з плаваючою точкою.

Щоб згенерувати поверхні другого порядку з використанням функцій Glu, необхідно присвоїти ім’я поверхні, активізувати процедуру візуалізації поверхні, задати значення параметрів поверхні.

Наприклад, наведемо оператори, які ілюструють стандартну послідовність функцій Glu для відображення каркасної сфери із центром у початку зовнішньої системи координат:

GLUquadricObj sphere; sphere1=gluNewQuadric(); gluQuadricDrawStyle (sphere1, GLU_LINE); gluSphere (sphere1, r, nLongitudes, nLatitudes);.

Перший оператор визначає назву об’єкта (в нашому випадку це sphere1). Потім це ім’я можна використовувати в інших функціях Glu для оперування цим об’єктом. За допомогою функції gluNewQuadric() активізується процедура візуалізації поверхні другого порядку, після чого за допомогою команди gluQuadricDrawStyle для поверхні sphere1 вибирається режим відображення GLU_LINE. В такий спосіб сфера виводиться на екран у каркасній формі з відрізками між кожною парою вершин поверхні. Функція gluSphere виконує побудову об’єкта sphere1 з параметрами: r – радіус сфери (число з плаваючою точкою подвійної

313

точності), nLongitudes – кількість ліній довготи, nLatitudes – кількість ліній широти. Ці лінії будуть використовуватися для апроксимації сферичної поверхні чотирикутною сіткою.

Для відображення поверхонь Glu другого порядку доступні три режими відображення. Якщо замість GLU_LINE використовувати символьну константу GLU_POINT як аргумент функції gluQuadricDrawStyle, то поверхня другого порядку відобразиться у вигляді точкового графіка. Якщо задати символьну константу GLU_FILL, то сфера буде зафарбованою.

16.5. Функції визначення видимих поверхонь

Усунення задніх граней виконується за допомогою функцій glEnable (GL_CULL_FACE); та glCullFace (mode);.

При активізації з glEnable () функція glCullFace () вказує, які грані (задні чи передні) будуть задіяні в операціях відбору. Для усунення задніх граней параметру mode присвоюють значення GL_BACK. Цю ж функцію можна використовувати і для усунення передніх граней, якщо параметру mode присвоїти значення GL_FRONT.

Для того, щоб використати процедури OpenGL усунення невидимих поверхонь за допомогою методу Z-буфера, спершу необхідно модифікувати функцію ініціалізації GLUT для режиму відображення, щоб вона включала запит до буфера глибини і буфера кадру. Це можна зробити за допомогою оператора

glutInitDisplayMode (GLUT_SINGLE | GLUT RGB | GLUT_DEPTH);.

Значення буфера глибини ініціалізуються за допомогою функції glClear (GL_DEPTH_BUFFER_BIT);

зі значенням 1.0 або іншим значенням, що задається функцією glClearDepth(maxDepth);.

Зауважимо, що в OpenGL значення глибини нормуються в діапазоні від 0 до 1.

Процедура визначення видимих поверхонь методом Z-буфера активізується функцією

glEnable(GL_DEPTH_TEST);.

Окрім цього, для буфера глибини можна задавати передню та задню площини відсікання.

16.6. Моделювання освітлення

Щоб створити фотореалістичне зображення, необхідно задати властивості поверхні й описати ефекти освітлення. В число цих ефектів входить відбиття світла, прозорість, текстура поверхні, тінь тощо.

314

Ми вже знаємо, що для розрахунку освітленості точки на поверхні використовують моделі освітлення.

OpenGL використовує модель освітлення, в якій освітлення здійснюється кількома джерелами світла. Окрім цього існує ще й амбітне світло.

Програміст може визначити до восьми джерел світла (в деяких версіях OpenGL і більше восьми) та їх властивості. Для задання цих властивостей використовують процедуру

void glLight{if}[v](GLenum lightName, GLenum lightProperty, Type param);,

яка задає параметри для джерела світла lightName, що може набувати значення GL_LIGHT0, GL_LIGHT1, …, GL_LIGHT7, тобто кожне джере-

ло світла ідентифікується й налаштовується окремо.

Параметру lightProperty присвоюється значення однієї з десяти символьних констант (табл. 16.2).

 

 

Таблиця 16.2

Значення

Значення за

Коментарі

 

замовчуванням

 

GL_AMBIENT

(0, 0, 0, 1)

фонова RGBA-освітленість

GL_DIFFUSE

(1, 1, 1, 1)

дифузна RGBA-освітленість

GL_SPECULAR

(1, 1, 1, 1)

блікова (Фонга) RGBA-освіт-

 

 

леність

GL_POSITION

(0, 0, 1, 0)

(x, y, z, w) – координати дже-

 

 

рел світла

GL_SPOT_DIRECTION

(0, 0, –1)

(x, y, z) – напрям для конічних

 

 

джерел світла

GL_SPOT_EXPONENT

(0)

показник степеня у формулі

 

 

Фонга

Джерело світла можна розглядати як таке, що має визначені координати (локальне світло) та світить у всіх напрямках, і як направлене джерело, що знаходиться в нескінченній точці та світить у заданому напрямку. Для ідентифікації джерела світла, тобто для знаходження місцерозміщення джерела світла в OpenGL, використовується символьна константа GL_POSITION. При цьому в масив param потрібно записати однорідні світові координати джерел світла у вигляді (x, y, z, w).

Якщо в команді GL_POSITION параметр w = 0, то джерело світла направлене і світить у напрямку (x, y, z). Якщо w 0, то джерело світла локальне і знаходиться в точці з координатами (x/w, y/w, z/w).

Для того щоб активізувати процедури освітлення OpenGL використовується команда

glEnable (GL_LIGHTING);.

315

Після того, як для джерела світла будуть задані всі властивості, i-те джерело світла вмикається командою glEnable (GL_LIGHTі);, а вими-

кається функцією glDisable (GL_LIGHTі);.

Поверхні об’єктів візуалізуються, використовуючи розрахунок освітлення з урахуванням усіх увімкнутих джерел світла.

У наступному прикладі світло 1 іде від локального джерела, розміщеного в точці (2.0, 0.0, 3.0), а світло 2 – від направленого джерела, що випромінює світло вздовж від’ємного напрямку осі у:

GLfloat light1Type [ ] = {2.0, 0.0, 3.0, 1.0}; GLfloat light2Type [ ] = {0.0, 1.0, 0.0, 0.0}; glLightfv(GL_LIGHT1, GL_POSITION, light1Type); glEnable(GL_LIGHT1);

glLightfv(GL_LIGHT2, GL_POSITION, light2Type); glEnable(GL_LIGHT2);.

Якщо тип і координати джерела світла не задаються, то установлюється значення за замовчуванням (0.0, 0.0, 1.0, 0.0), яке вказує на віддалене джерело світла, промені якого рухаються вздовж від’ємного напрямку осі z.

Параметри GL_SPOT_DIRECTION, GL_SPOT_CUTOFF задають джерела світла з конічною направленістю. Наприклад, команди

GLfloat dirVector [ ] = {1.0, 0.0, 0.0}; glLightfv(GL_LIGHT3, GL_SPOT_DIRECTION, dirVector); glLightfv(GL_LIGHT3, GL_SPOT_CUTOFF, 30.0); glLightf(GL_LIGHT3, GL_SPOT_EXPONENT, 2.5);

для джерела 3 задають направлене конічне світло так, що вісь конуса проходить уздовж додатного напрямку осі х. Кут конуса дорівнює 30ο і параметр затухання становить 2,5.

За замовчуванням задається точкове джерело світла, яке випускає промені в усіх напрямках із нульовим коефіцієнтом затухання.

Затухання інтенсивності можна застосувати до локальних джерел. Для цього використовуються три константи радіального затухання світ-

ла: GL_CONSTANT_ATTENUATION, GL_LINEAR_ATTENUATION, GL_QUADRATIC_ATTENUATION.

Наприклад,

glLightf (GL_LIGHT4, GL_LINEAR_ATTENUATION, 0.75);.

За замовчуванням радіального затухання немає. Фонове освітлення можна задати за допомогою команди

glLightModel{if}[v] (GL_LIGHT_MODEL_AMBIENT, ambientColor);.

Наприклад,

GLfloat ambientColor [ ] = {0.0, 0.0, 0.3, 1.0};

316

glLightModel{if}[v] (GL_LIGHT_MODEL_AMBIENT, ambientColor);.

За замовчуванням у цій команді використовується слабо інтенсивний білий колір (0.2, 0.2, 0.2, 1.0).

Розрахунок дзеркального відображення вимагає знання кількох векторів, в тому числі й вектора V від точки поверхні до точки спостерігача.

У процедурах OpenGL використовується постійний напрям вектора V незалежно від положення точки поверхні відносно спостерігача. Це вектор (0.0, 0.0, 1.0), що йде в додатному напрямі осі z (це значення вектора V за замовчуванням). Тобто вважається, що спостерігач знаходиться в нескінченності й напрям на спостерігача постійний для кожної вершини. Водночас для використання реальної точки спостереження (початок системи координат) для обчислення вектора V використовується команда

glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);.

Хоча розрахунок дзеркального відображення при використанні реальної точки спостереження вимагає більше часу, в результаті одержується більш реалістичне зображення.

При виведенні зображення кожного об’єкта OpenGL визначає взаємну орієнтацію вектора напрямку джерела світла й поточного вектора нормалі. Напрям поточного вектора нормалі не змінюється доти, поки не буде викликана функція нормалі glNormal3f (nx, ny, nz);

Оптичні властивості матеріалу, з якого зроблений об’єкт задаються за допомогою процедури

void glMaterial{if}[v] (GLenum face, GLenum property, Type param);.

Параметр face вказує, для якої зі сторін граней буде застосовуватися ця властивість. Йому присвоюється одна із символьних констант

GL_FRONT, GL_BACK, або GL_FRONT_AND_BACK. Параметр property вказує на властивості оптичної поверхні, а параметру param присвоюються відповідні значення коефіцієнтів відображення (табл. 16.3).

 

 

Таблиця 16.3

Значення

Значення за

Коментарій

 

замовчуванням

 

GL_AMBIENT

(0.2, 0.2, 0.2, 1.0)

фоновий колір матеріалу

GL_DIFFUSE

(0.8, 0.8, 0.8, 1.0)

дифузний колір матеріалу

GL_AMBIENT_

 

фоновий і дифузний кольори мате-

AND_DIFFUSE

 

ріалу

GL_EMISSION

(0, 0, 0, 1)

колір свічення матеріалу

317

Наприклад,

GLfloat EmissionColor [ ] = {0.8, 0.8, 0.8, 1.0}; void glMaterialfv (GL_FRONT, GL_EMISSION, EmissionColor);,

задає світло-сірий колір випромінювання з передніх граней. Зауважимо, що це випромінювання поверхні не буде освітлювати інші об’єкти сцени.

Щоб зображення виглядало реалістичним, коефіцієнтам фонового і дифузного освітлення необхідно присвоїти однакові векторні значення. Це можна зробити, використовуючи символьну константу

GL_AMBIENT_AND_DIFFUSE.

Метод візуалізації поверхні OpenGL задається за допомогою функції glShadeModel (Rendering Metod);.

Якщо параметру Rendering Metod присвоїти значення GL_FLAT, то матимемо метод постійного зафарбовування, а якщо GL_SMOOTH – зафарбовування за методом Гуро (встановлюється за замовчуванням). Зауважимо, що в OpenGL нема процедур зафарбовування за Фонгом.

OpenGL пропонує широкий набір текстурних формул, підтримує одно- і двовимірні текстури і різні способи накладання текстури. Для задання двовимірної текстури використовують функцію glTexImage2D.

Це лише короткий опис основних можливостей OpenGL. Більш ґрунтовні знання можна почерпнути з [16],[35],[36],[40].

16.7. Область виведення

Наступним кроком після вибору паралельного або перспективного перетворення є задання області у вікні, в якій буде розміщене побудоване зображення. Для цього створена процедура

void glViewport (GLint x, GLint y, GLsizeі width, GLsizeі height);

де (x, y) задає лівий нижній кут прямокутної області у вікні, а width і height є її шириною і висотою.

OpenGL – універсальна бібліотека, яка може бути реалізована в будь-якому віконному середовищі. Для роботи OpenGL у Windows використовується поняття контексту відтворення, який зв’язує OpenGL з віконною системою координат (контекст пристрою стосується графічних компонент GDI). Щоб почати роботу з командами OpenGL, додаток повинен створити як мінімум один контекст відтворення і зробити його поточним.

Перед створенням контексту відтворення необхідно установити формат пікселів. Для установки формату пікселів використовують функцію int ChoosePixelFormat (HDC, const PIXELFORMATDESCRIPTOR);,

яка знайде найбільш підходящий формат. Далі необхідно установити цей формат у контексті пристрою за допомогою функції

318

BOOL SetPixelFormat (HDC hDC, int pixelFormat, const PIXELFORMATDESCRIPTOR);.

Для роботи з контекстом відтворення у Windows існують дві функції:

HGLRC wglCreateContext(HDC hdc);

і

BOOL wglMakeCurrent (HDC, HGLRChGLRC);.

Перша з них створює контекст відтворення OpenGL для відтворення на пристрої, що задається контекстом hDC, друга встановлює поточний контроль відтворення.

Після закінчення роботи з OpenGL створений контекст відтворення необхідно знищити. Для цього використовують функцію

BOOL wglDeleteContext(HGLRChGLRC);.

Приклад 16.4. Створити проект у середовищі Cbuilder 6.0 для реалізації сфери, що обертається.

Файл Unit 1.сср

//Програма розроблена Стратійчук Н. О.

#include <vcl.h> #pragma hdrstop

//Підключаємо потрібні бібліотеки.

#include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> #include "Unit1.h"

//---------------------------------------------------------------------------

#pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1;

/*

Після підключення всіх файлів необхідно встановити формат пікселів. Це виконає така функція:

*/

BOOL bSetupPixelFormat(HDC hdc)

{

PIXELFORMATDESCRIPTOR pfd, *ppfd; //Змінювати в цій функції нічого не потрібно.

int pixelformat; ppfd = &pfd;

ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);

319

ppfd->nVersion = 1;

ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;

ppfd->dwLayerMask = PFD_MAIN_PLANE; ppfd->iPixelType = PFD_TYPE_RGBA;

/*

iPixelType – формат задання кольору. Він може набувати значення PFD_TYPE_RGBA (колір вказується чотирма параметрами: червоний, зелений, синій і альфа) і PDF_TYPE_COLORINDEX (колір вказується індексом у палітрі);

cColorBits – глибина кольору;

cDepthBits – розмір буфера глибини (Z -буфера);

cStencilBits – розмір буфера трафарета (в програмі не використовується)

*/

ppfd->cColorBits = 16; ppfd->cDepthBits = 16; ppfd->cAccumBits = 0; ppfd->cStencilBits = 0;

/*

Функція ChoosePixelFormat() підбирає формат пікселів згідно із заданими вище умовами і повертає його дескриптор.

Якщо не вдалось підібрати формат відповідно до введених умов, видається повідомлення про помилку.

*/

if ((pixelformat = ChoosePixelFormat(hdc, ppfd)) == 0)

{

MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK); return FALSE;

}

/*

Функція SetPixelFormat() встановлює формат пікселів. Якщо не вдалось встановити вибраний формат – помилка. */

if (SetPixelFormat(hdc, pixelformat, ppfd) == FALSE)

{

MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK); return FALSE;

}

return TRUE;

320

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