Міністерство освіти України
Національний університет «Львівська політехніка»
Кафедра автоматизованих систем управління
Методичка до лабораторних з ООП
Лабораторна робота №6з курсу
«Об'єктно-орієнтоване програмування»
Львів 2011
Лабораторна робота №6
Створення анімаційного проекту
Мета роботи: Вивчення можливостей графічної бібліотеки OpenGL по створенню анімаційних проектів.
Порядок роботи:
Ознайомитись з теоретичними відомостями по роботі.
Створити проект Delphi, який реалізує наведений у тексті приклад.
Змінити текст програми так, щоб він відповідав індивідуальному завданню.
Оформити звіт для захисту лабораторної роботи за зразком
назва роботи
мета роботи
порядок роботи
короткі теоретичні відомості
алгоритм розв’язку задачі
тексти відповідних модулів проекту
аналіз отриманих результатів та висновки
Питання для самоконтролю
1. Які призначення та склад графічної бібліотеки OpenGL?
2. На які категорії поділяються функції OpenGL?
3. Якою є структура програми на Delphi, що використовує OpenGL?
4. Що таке графічні примітиви та атрибути?
5. Які системи координат використовуються в OpenGL?
6. Як відбувається перетворення об'єктів у OpenGL?
Теоретичні відомості
1. Основи OpenGL
1.1. Призначення
OpenGL (Open Graphics Library – відкрита графічна бібліотека) - це прикладний програмний інтерфейс (API – Application Programming Interface) для розробки програм у галузі двовимірної та тривимірної графіки.
Характерними рисами OpenGL, що забезпечили поширення та розвиток цього графічного стандарту є стабільність, надійність і незалежність від платформи, легкість застосування.
1.2. Склад OpenGL
OpenGL складається з набору бібліотек. Усі базові функції зберігаються в основній бібліотеці, яка нараховує близько 120 різних команд. Ці команди програміст може використовувати для реалізації об'єктів і операцій, необхідних для написання інтерактивних графічних додатків.
Крім основної, OpenGL містить кілька додаткових бібліотек.
Перша з них – бібліотека утиліт GLU (GL Utility). За допомогою GLU є можливою реалізація більш складних функцій, таких як створення основних геометричних примітивів (куб, сфера, циліндр, диск), побудова сплайнів, виконання додаткових операцій над матрицями і т.п.
OpenGL не містить у собі ніяких спеціальних команд для роботи з вікнами або введення інформації від користувача. Тому були створені спеціальні бібліотеки для забезпечення необхідних функцій взаємодії з користувачем і для відображення інформації за допомогою віконної підсистеми. Найбільш популярними є бібліотеки GLUT (GL Utility Toolkit) та GLAUX (GLAuxillary).
1.3. Основні функції
Описувати можливості OpenGL будемо через функції його бібліотеки. Усі функції можна розділити на п'ять категорій:
Функції опису примітивів визначають об'єкти нижнього рівня ієрархії (примітиви), які здатна відображати графічна підсистема, тобто, що з'явиться на екрані. У OpenGL як примітиви виступають точки, лінії, багатокутники і т.д.
Функції опису джерел світла служать для опису положення та параметрів джерел світла, розташованих у тривимірній сцені.
Функції визначення атрибутів. За їхньою допомогою програміст визначає, як будуть виглядати об'єкти на екрані. У якості атрибутів OpenGL дозволяє задавати колір, характеристики матеріалу, текстури, параметри освітлення.
Функції візуалізації дозволяють задати положення спостерігача у віртуальному просторі, параметри об'єктива камери. Знаючи ці параметри, система зможе не тільки правильно побудувати зображення, але і відсікти об'єкти, що опинилися поза полем зору.
Функції геометричних перетворень дозволяють програмісту виконувати поворот, перенесення, та масштабування об'єктів.
Визначення команд OpenGL знаходяться у файлі opengl.pas, для підключення якого потрібно написати
uses OpenGL;
Для роботи з бібліотеками GLUT та GLAUX потрібно підключити файли Dglut.pas та GLAux.pas, а також переписати файл GLAux.dll у системний каталог Windows або у каталог із проектом, що розробляється.
Усі команди (процедури та функції) бібліотеки OpenGL починаються з префікса gl, усі константи – із префікса GL_. Відповідні команди та константи бібліотек GLU, GLUT та GLAux мають префікси glu (GLU_), glut (GLUT_), aux (AUX_)
Крім того, у назви команд входять суфікси, що несуть інформацію про число та тип переданих параметрів. У OpenGL повне ім'я команди має вигляд:
type glCommand_name[1 2 3 4][b s i f d ub us ui][v] (type1 arg1,…,typeN argN)
Таким чином, ім'я складається з декількох частин:
Gl - це ім'я бібліотеки, у якій описана ця функція: для базових функцій OpenGL, функцій з бібліотек GLU, GLUT, GLAUX це gl, glu, glut, glaux відповідно
Command_name - ім'я команди
[1 2 3 4] - число аргументів команди
[b s і f d ub us ui] - тип аргументу: символ b означає тип GLbyte (аналог byte у Object Pascal), символ f – тип GLfloat (аналог float), символ і – тип GLint (аналог integer) і так далі. Повний список типів і їхній опис можна подивитися у файлі OpenGL.pas
[v] - наявність цього символу показує, що як параметри функції використовується вказівник на масив значень
Символи у квадратних дужках у деяких назвах не використовуються. Наприклад, команда glColor3d() використовує як параметри 3 дійсних числа.
2. Приклад програми
Типова програма, що використовує OpenGL, починається з визначення вікна, у якому буде відбуватися відображення. Потім створюється контекст (клієнт) OpenGL і асоціюється з цим вікном. Далі програміст може вільно використовувати команди та операції OpenGL API.
Нижче наведений текст програми, написаної з використанням бібліотек GLUT та GLAux. Програма малює освітлений синій куб, який обертається навколо власної осі на жовтому фоні.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, OpenGL, Glaux, DGlut; // підключаємо бібліотеки OpenGL, GLAux, GlUt
type
// множина геометричних фігур
GLObject = (SolidCUBE, SolidBOX, SolidSPHERE, SolidCONE, SolidTORUS, SolidDODECAHEDRON,
SolidICOSAHEDRON, SolidTETRAHEDRON, SolidTEAPOT, SolidCYLINDER, SolidOCTAHEDRON,
WireCUBE, WireBOX, WireSPHERE, WireCONE, WireTORUS, WireDODECAHEDRON,
WireICOSAHEDRON, WireTETRAHEDRON, WireTEAPOT, WireCYLINDER, WireOCTAHEDRON);
TfrmGL = class(TForm)
Timer1: TTimer;
//Timer1: TTimer;
procedure FormCreate(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
private
DC : HDC;
hrc: HGLRC;
Angle : GLfloat;
i: integer;
procedure DrawScene(Tx, Ty, Tz, Angle, Rx, Ry, Rz,
Red, Green, Blue : GLdouble; MyObject : GLObject);
procedure SetDCPixelFormat;
end;
var
frmGL: TfrmGL;
MyObject : GLObject;
implementation
{$R *.DFM}
// Малювання геометричної фігури
procedure TfrmGL.DrawScene(Tx, Ty, Tz, Angle, Rx, Ry, Rz,
Red, Green, Blue : GLdouble; MyObject : GLObject);
begin
glRotatef(Angle, Rx, Ry, Rz); // обертаємо на кут Angle навколо (Rx, Ry, Rz)
glTranslated(Tx,Ty,Tz); // переміщуємо об'єкт до нового початку координат
glColor3d(Red,Green,Blue); // задаємо колір об'єкта
case MyObject of
SolidCUBE : glutSolidCube (2); // малюємо куб - процедура бібліотеки GLUt або
// auxSolidCube(1); // процедура бібліотеки GLAux
// тут можуть бути інші фігури
end;
end;
{=======================================================================}
// Виведення на екран
procedure TfrmGL.FormPaint(Sender: TObject);
begin
// колір фону в системі RGB (межі зміни від 0 до 1,
// 4-й параметр - альфа (коефіцієнт непрозорості)
glClearColor (1, 1, 0, 1);
// очистка фону - буферів кольору і глибини
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glPushMatrix; // зберігаємо поточну матрицю у стеку
// малювання фігури
// переміщуємо об'єкт у точку (0, 0.5, 0)
// і обертаємо проти годинникової стрілки на кут Angle навколо вектора (0,1,0) - вісь Y
// малюємо кольором R=0, G=0.5, B=1
// фігура - куб
DrawScene(0, 0.5, 0, // переміщуємо об'єкт у точку (0, 0.5, 0)
Angle, 0, 1, 0,
0, 0.5, 1,
SolidCube);
// відновлюємо матрицю зі стека
glPopMatrix;
// вміст буфера - на екран
SwapBuffers(DC); // функція Win32 API
end;
{=======================================================================}
// Задання формату пікселів
procedure TfrmGL.SetDCPixelFormat;
var
pfd : TPixelFormatDescriptor;
nPixelFormat : Integer;
begin
FillChar (pfd, SizeOf (pfd), 0);
pfd.dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;
nPixelFormat := ChoosePixelFormat (DC, @pfd); // функція Win32 API
SetPixelFormat (DC, nPixelFormat, @pfd); // функція Win32 API
end;
{=======================================================================}
// Створення форми
procedure TfrmGL.FormCreate(Sender: TObject);
const
pos : Array [0..3] of GLFloat = (3.0, 3.0, 3.0, 1.0);
dir : Array [0..2] of GLFloat = (-1.0, -1.0, -1.0);
begin
Angle := 0;
DC := GetDC (Handle); // отримуємо графічний контекст (функція Win32 API)
SetDCPixelFormat;
hrc := wglCreateContext (DC); // створюємо контекст OpenGL
wglMakeCurrent (DC, hrc); // призначаємо контекст DC для виведення через OpenGL
// Режими роботи
glEnable(GL_DEPTH_TEST); // вилучення невидимих ліній та поверхонь
glEnable(GL_COLOR_MATERIAL); // матеріал об'єктів відрізняється лише кольором
// Задаємо параметри джерела світла
glLightfv(GL_LIGHT0, GL_POSITION, @pos); // розташування джерела
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, @dir); // напрямок світла
glEnable(GL_LIGHTING); // дозволяємо роботу з освітленням
glEnable(GL_LIGHT0); // вмикаємо джерело світла 0
Timer1.Interval := 25;
Timer1.Enabled := True;
end;
{=======================================================================}
// Завершення роботи програми
procedure TfrmGL.FormDestroy(Sender: TObject);
begin
Timer1.Enabled:=False;
wglMakeCurrent(0, 0);
wglDeleteContext(hrc); // знищуємо контекст OpenGL
ReleaseDC (Handle, DC); // звільняємо графічний контекст (функція Win32 API)
DeleteDC (DC); // знищуємо графічний контекст (функція Win32 API)
end;
{=======================================================================}
// Зміна розмірів вікна
procedure TfrmGL.FormResize(Sender: TObject);
begin
// розміри області відображення (у пікселах)
glViewport(0,0,ClientWidth,ClientHeight);
// працюємо з матрицею проекцій
glMatrixMode(GL_PROJECTION);
glLoadIdentity; // завантажуємо одиничну матрицю
// ортографiчна проекція
glOrtho(-5,5, -5,5, 2,12); // межі видимої частини
// по x від -5 до 5, по у від -5 до 5, по z від 2 до 12
// тут може бути перспективна проекція
// gluPerspective(90.0, // кут видимості в напрямку осі Y
// ClientWidth / ClientHeight, // кут видимості в напрямку осі X
// 2, // відстань від спостерігача до ближньої площини відсікання
// 12); // відстань від спостерігача до дальньої площини відсікання
// задаємо положення спостерігача
gluLookAt( 0,2,5, 0,0,0, 0,1,0 );
// 0,1,5 - точка спостереження,
// 0,0,0 - центр сцени
// 0,1,0 - напрямок вертикальної осі - додатній
// працюємо з модельно-видовою матрицею
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
// перемальовуємо графічний контекст (функція Win32 API)
InvalidateRect(Handle, nil, False);
end;
procedure TfrmGL.Timer1Timer(Sender: TObject);
begin
// Кожен такт змінюється значення кута
Angle := Angle + 1.0;
If (Angle >= 360.0) then
Angle := 0.0;
// перемальовуємо графічний контекст (функція Win32 API)
InvalidateRect(Handle, nil, False);
end;
procedure TfrmGL.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
If Key = VK_ESCAPE then Close;
InvalidateRect(Handle, nil, False);
end;
end.
3. Малювання геометричних об'єктів
Як правило, задачею програми, що використовує OpenGL, є обробка тривимірної сцени та її інтерактивне відображення в буфері кадру. Сцена складається з набору тривимірних об'єктів, джерел світла і віртуальної камери, що визначає поточне положення спостерігача.
Звичайний додаток OpenGL у нескінченому циклі викликає процедуру відновлення зображення у вікні (FormPaint). У цієї функції і зосереджені виклики основних команд OpenGL. GL викликає цю функцію, коли операційна система інформує додаток про те, що вміст вікна необхідно перемалювати (наприклад, якщо вікно було перекрито іншим). Створюване зображення може бути як статичним, так і анімованим, тобто залежати від яких-небудь параметрів, що змінюються з часом. У цьому випадку краще викликати процедуру відновлення самостійно (наприклад, за допомогою функції InvalidateRect).
Типова функція відновлення зображення, як правило складається з трьох кроків:
- очищення буферів OpenGL;
- визначення положення спостерігача;
- перетворення та малювання геометричних об'єктів.
Визначення положення спостерігача та перетворення тривимірних об'єктів (поворот, переміщення і т.д.) задається за допомогою матриць перетворення координат у дво-, три-, чи чотиривимірному (x, y, z, w) просторі.
Найпростішим графічним примітивом OpenGL є вершина, яка визначає точку, кінець відрізка, кут багатокутника і т.д. Усі інші примітиви формуються за допомогою визначення вершин, що входять у даний примітив, наприклад, відрізок має дві вершини, що є кінцями відрізка. Визнаачення координат вершин реалізується за допомогою декількох варіантів команди glVertex. Щоб об'єднати вершини в єдине ціле, визначивши необхідні властивості, використовуються операторні дужки, що є викликами спеціальних команд OpenGL Визначення примітива чи послідовності примітивів відбувається між викликами команд glBegin та glEnd. Наприклад, наступна послідовність команд
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glColor3ub(255,0,0);
glBegin(GL_QUADS); // для чотирикутників
glVertex2f(-1,-1);
glVertex2f(-1,1);
glVertex2f(1,1);
glVertex2f(1,-1);
glEnd;
очищає вікно і виводить на екран квадрат через координати чотирьох кутових вершин і колір.
4. Перетворення об'єктів
У OpenGL використовуються три основні системи координат: лівостороння, правостороння і віконна. Перші дві системи є тривимірними і відрізняються друг від друга напрямком осі Z: у правосторонньої вона спрямована на спостерігача, у лівосторонньої – у глибину екрана. Вісь X спрямована вправо щодо спостерігача, вісь Y – нагору. Основною системою координат OpenGL є правостороння система. Відображення тривимірної інформації на екрані відбувається у двовимірній віконній системі координат (одиниці виміру - пікселі).
а) правостороння
б) лівостороння
в) віконна
Рис. 1 Системи координат у OpenGL
Для завдання різних перетворень об'єктів сцени в OpenGL використовуються операції над матрицями, при цьому розрізняють три типи матриць: модельно-видова, матриця проекцій і матриця текстури. Усі вони мають розмір 4x4. Видова матриця визначає перетворення об'єкта у світових координатах, такі як рівнобіжний перенос, зміна масштабу та поворот. Матриця проекцій визначає, як будуть проектуватися тривимірні об'єкти на площину екрана (у віконних координатах), а матриця текстури визначає накладення текстури на об'єкт. Для виклику команд, що задають матриці того чи іншого типу, необхідно спочатку установити потрібний режим за допомогою команди glMatrixMode із відповідним параметром - GL_MODELVIEW, GL_PROJECTION або GL_TEXTURE.
Щоб зберегти вміст поточної матриці для подальшого використання, застосовуються команди glPushMatrix() та glPopMatrix(), які записують і відновлюють поточну матрицю зі стека.
Усі перетворення об'єктів і камери в OpenGL здійснюються за допомогою множення векторів координат на матриці.
До модельно-видових перетворень будемо відносити перенос, поворот і зміну масштабу уздовж координатних осей. Для цього використовуються наступні команди:
glTranlsate*() - виконує перенос об'єкта, додаючи до координат його вершин значення своїх параметрів.
glRotate*() - виконує поворот об'єкта проти годинникової стрілки на заданий кут (виміряється в градусах) навколо вектора (x,y,z).
glScale*() - виконує масштабування об'єкта (стиск чи розтягання) уздовж вектора (x,y,z), перемножуючи відповідні координати його вершин на значення параметрів.
Усі ці перетворення змінюють поточну матрицю, а тому застосовуються до примітивів, що визначаються пізніше. У випадку, якщо треба, наприклад, повернути один об'єкт сцени, а іншої залишити нерухомим, зручно спочатку зберегти поточну видову матрицю у стеку командою glPushMatrix(), потім викликати glRotate() із потрібними параметрами, описати примітиви, із яких складається цей об'єкт, а потім відновити поточну матрицю командою glPopMatrix().
Для створення реалістичних зображень необхідно визначити як властивості самого об'єкта, так і властивості середовища, у якому він знаходиться. Перша група властивостей містить у собі параметри матеріалу, із якого зроблений об'єкт, способи нанесення текстури на його поверхню, ступінь прозорості об'єкта. До другої групи відносять кількість і властивості джерел світла, рівень прозорості середовища, а також модель освітлення. Усі ці властивості можна задавати, викликаючи відповідні команди OpenGL.
Завдання
I. Реалізувати за допомогою функцій бібліотеки OpenGL вивід на екран і перетворення геометричної фігури та її каркасу. Тип фігури та перетворення вибрати згідно з варіантом індивідуального завдання:
Конус збільшення розмірів
Тор зменшення розмірів
Сфера рух по прямій від спостерігача
Циліндр обертання навколо осі X за годинниковою стрілкою
Коробка рух по діагоналі площини XY
Ікосаедр обертання навколо осі Y проти годинникової стрілки
Тетраедр рух по прямій до спостерігача
Октаедр обертання навколо осі Z за годинниковою стрілкою
Чайник рух по діагоналі площини XZ
Додекаедр обертання навколо діагоналі простору XYZ проти годинникової стрілки
Конус обертання навколо діагоналі простору XYZ за годинниковою стрілкою
Тор рух по діагоналі площини YZ
Сфера обертання навколо осі Z проти годинникової стрілки
Циліндр рух по прямій від спостерігача
Коробка обертання навколо осі Y за годинниковою стрілкою
Ікосаедр рух по діагоналі площини XZ
Тетраедр обертання навколо осі X проти годинникової стрілки
Октаедр рух по прямій до спостерігача
Чайник збільшення розмірів
Додекаедр зменшення розмірів
Опис функцій для малювання фігур та їхніх параметрів можна знайти у файлах DGlut.pas та Glaux.pas. Для керування процесом перетворення використати клавіатуру та мишку.
II. Створити за допомогою функцій бібліотеки OpenGL тривимірні зображення перших літер Вашого прізвища та імені. Передбачити зміну кольорів літер і розташування спостерігача у часі.