Лабораторна робота № 2. Примітиви OPENGL, основні прийоми побудови двовимірних об'єктів. Мета роботи. Знайомство з примітивами OPENGL, призначеними для виведення крапок, ліній і багатокутників. Визначення кольору об'єктів. Різні способи замальовування об'єктів. Необхідні теоретичні відомості. Для виконання роботи необхідно мати уявлення про основні принципи формування зображення на екрані ([7] – лекція 17), про моделювання об'єктів на плоскості ([7] – лекції 7, 8, 10); знати особливості представлення кольору в колірній моделі RGB ([7] – лекція 4); розуміти сенс терміну «антиелайзінг» ([7] – лекція 6). Область виводу в OPENGL задається командою glViewPort(0, 0, ClientWidth, ClientHeight) де перші два параметри задають положення лівого верхнього кута вікна виводу, параметри ClientWidth, ClientHeight визначають розмір вікна в екранних координатах. Центр отриманої області виводу має координати (0, 0). Координати змінюються в діапазоні [-1; 1] по кожній осі. Якщо при установці формату піксела був встановлений режим подвійної буферизації (прапор PFD_DOUBLEBUFFER), то зображення готується у позаекранному буфері, і необхідно забезпечити перезапис вмісту позаекранного буфера в основний. Зробити це можна командою BOOL SwapBuffers(HDC hdc); Всі зображення будуються з окремих примітивів, які описуються за допомогою набору вершин (Vertex). Примітивами OpenGl є крапки (одиночні вершини), лінії (пари вершин), трикутники (три вершини), чотирикутники (чотири вершини) і полігони (3 і більш за вершини). Командні дужки. Використання функцій glBegin і glEnd. Команди малювання полягають між командними дужками glBegin і glEnd. Командними дужками бібліотеки OpenGl є спеціальні функції (що не мають ніякого відношення до операторних дужок мов програмування). Помилка при використанні командних дужок не розпізнається компілятором, але може привести до непередбачуваних результатів роботи програми. Усередині командних дужок можуть знаходитися будь-які оператори мови і багато функцій OPENGL. Головне призначення командних дужок – завдання режиму (примітиву) для команд glVertex (вершина), що визначають координати вершин для малювання примітивів OPENGL. Команди, що встановлюють розмір крапки, товщину і типа лінії, включення і відключення режиму згладжування (антиелайзінг) повинні стояти поза командними дужками. Колір окремих вершин або примітивів може встановлюватися як поза командними дужками, так і усередині них. Для установки кольору використовується команда glColor3f(0.3f, 0.5f, 0.1f) де колір формується як сума компонент червоного, зеленого і синього кольорів у вказаній пропорції. Значення компонент задаються у вигляді дійсних чисел в інтервалі [0; 1]. Компоненти кольору можуть бути задані і в цілочисельній формі, граничним значенням в цьому випадку буде максимальне 8-бітове ціле без знаку, наприклад, білий колір буде записаний таким чином: glColor3i(214748647, 214748647, 214748647). Проте переважно використовувати команду в речовій формі, оскільки OPENGL зберігає дані саме в речовому форматі. Цифра 3 в назві команди означає число аргументів команди. Аргументи функції glBegin. Аргументами функції glBegin можуть бути стандартні константи OpenGl, що визначають примітиви бібліотеки: GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP, GL_POLYGON. У програмі імена констант мають бути записані саме так як це зроблено тут (все у верхньому регістрі). Включення і відключення режиму згладжування (антиелайзінг). Для установки режиму згладжування перед командними дужками повинна стояти команда glEnable() з відповідною константою як аргумент, а після командних дужок – команда glDisable() також з відповідною константою. Вибір константи визначається примітивом, згладжування якого має бути включене (або відключено): GL_POINT_SMOOTH (згладжування для крапок), GL_LINE_SMOOTH (згладжування ліній), GL_POLYGON_SMOOTH (згладжування для полігонів). Виведення крапок в OPENGL. Розгледимо малювання крапок. Крапками є одиночні вершини. Для малювання вершини використовується команда glVertex. Якщо крапка має бути змальована на плоскості, то для визначення її положення необхідно дві координати. В цьому випадку використовується функція з двома аргументами: glVertex2f(0, 0). Буква f в назві функції визначає типа аргументів – дійсні числа (float). Крапка в просторі визначається трьома координатами, отже повинна використовуватися команда з трьома аргументами: glVertex3f(0.5, 0.3,-0.7). Команди glVertex повинні розміщуватися між командними дужками. При цьому кількість крапок може бути будь-яким. Аргументом функції glBegin для малювання крапок є константа GL_POINTS. Аргументом команд glEnable() і glDisable() для включення/відключення режиму згладжування є константа GL_POINT_SMOOTH. Для завдання розміру крапки використовується команда glPointSize(). Аргументом є натуральне число, що визначає розмір крапки в пікселах. У режимі згладжування існує обмеження на розмір крапок. Визначите експериментально максимальний розмір крапки, що виводиться в режимі згладжування. Приклад: glColor3f(1.0, 0.0, 0.0); // Встановили червоний колір glEnable(GL_POINT_SMOOTH); // Включення режиму згладжування для // крапок glPointSize(3); // Встановили розмір крапки 3 піксели glBegin(GL_POINTS); // Режим малювання - крапки glVertex2f(-0.5, -0.7); glVertex2f(0.0, 0.0); glVertex2f(0.1, 0.9); glVertex2f(0.3, -0.5); glEnd(); // Кінець малювання glDisable(GL_POINT_SMOOTH); // Відключення режиму згладжування для // крапок Лінії: одиночні, ламані, замкнуті ламані. Для малювання ліній існує три режими: одиночні лінії, ламана, замкнута ламана. Одиночна лінія визначається двома вершинами. Якщо потрібно намалювати декілька одиночних ліній, то між командними дужками мають бути описані координати пар вершин, тобто кількість команд glVertex між командними дужками має бути парною. У випадку, якщо кількість вершин непарно – остання вершина ігнорується. Аргументом функції glBegin для малювання одиночних ліній є константа GL_LINES. Аргументом команд glEnable() і glDisable() для включення/відключення режиму згладжування є константа GL_LINE_SMOOTH. Для завдання товщини лінії використовується команда glLineWidth(). Аргументом є натуральне число, що визначає товщину в пікселах. Так само як і при установці розміру крапки команду установки товщини лінії записують за межами командних дужок. Для зміни типа лінії використовується команда glLineStipple(), що має два аргументи. Перший аргумент – масштабний множник, а другий є шістнадцятковою константою, що визначає шаблон штрихування (побітовим способом). Ця команда повинна стояти поза операторними дужками. ПРИКЛАД: glColor3f(1.0, 0.0, 0.0); // Встановили червоний колір glEnable(GL_LINE_SMOOTH); // Включення режиму згладжування для // ліній glLineWidth(3); // Встановили товщину лінії 3 піксели glLineStipple(1, 0xF0F0); // Тип лінії – пунктирна glEnable(GL_LINE_STIPPLE); // Вирішити зміну типа лінії glBegin(GL_LINES); // Режим малювання – одиночні лінії glVertex2f(-0.5, -0.7); // Початок першої лінії glVertex2f(0.0, 0.0); // Кінець першої лінії glVertex2f(0.1, 0.9); // Початок другої лінії glVertex2f(0.3, -0.5); // Кінець другої лінії glEnd(); // Кінець малювання glDisable(GL_LINE_SMOOTH); // Відключення режиму згладжування для // ліній Якщо потрібно намалювати ламану лінію, то в командних дужках використовують константу GL_LINE_STRIP. Вершини, перераховані між командними дужками, інтерпретуються таким чином: кінцева точка першої лінії є початковою точкою наступної ланки ламаної і так далі Кількість вершин може бути як парною, так і непарною. Ширина і тип ламаної лінії задаються так само як і для одиночних ліній. Для малювання замкнутої ламаної аргументом функції glBegin має бути встановлена константа GL_LINE_LOOP. Останній відрізок замкнутою ламаною як початок має останню вершину списку, а як кінець – першу вершину. Виведення трикутників: одиночні трикутники, стрічки трикутників, віяла трикутників. Для малювання окремих трикутників константа командних дужок: GL_TRIANGLES. Кількість вершин, перерахованих між командними дужками має бути кратне трем. Кожні три вершини визначають трикутник. Стрічка трикутників використовується, якщо зображення може бути побудоване за допомогою декількох трикутників, що мають суміжні сторони (Малюнок 1. Стрічка трикутників). Тут сторона a2a3 є загальною стороною для першого і другого трикутників, сторона a3a4 – загальною стороною другого і третього трикутників і так далі Якщо таку фігуру описувати за допомогою одиночних трикутників, то необхідно задавати координати всіх вершин всіх трикутників: a1, a2, a3, a2, a3, a4, a3, a4, a5, a4, a5, a6 – всього 12 вершин. Використання стрічки трикутників дозволяє не дублювати вершини при описі їх координат. Змальована на малюнку фігура може бути представлена стрічкою трикутників, координати вершин перераховуються в наступному порядку: a1, a2, a3, a4, a5, a6 – достатні 6 вершин. Константа командних дужок для примітиву «стрічка трикутників»: GL_TRIANGLE_STRIP. Інша можливість малювання за допомогою трикутників – використання «віяла трикутників» в тих випадках, коли декілька трикутників мають загальну вершину (Малюнок 2. Віяло трикутників). При описі вершин першою в списку повинна стояти загальна вершина. Т.ч. в списку з декількох вершин перші три вершини визначають перший трикутник; перша, третя і четверта – другий; перша, четверта і п'ята – третій; і так далі Якщо в списку є N вершин, то буде змальовано N-2 трикутника. Константа командних дужок для віяла трикутників: GL_TRIANGLE_FAN. Виведення чотирикутників. Константа командних дужок для малювання окремих чотирикутників: GL_QUADS. Чотирикутник визначається групою з 4-х вершин, отже, кількість вершин, записаних між командними дужками, має бути кратне 4. Зайві вершини ігноруються. Кожна четвірка вершин визначає окремий чотирикутник. Якщо зображення створюється із зв'язаних чотирикутників (кожна пара чотирикутників має загальну сторону), то використовується примітив «стрічка чотирикутників». Константа командних дужок: GL_QUAD_STRIP. Малювання полігонів, передні і задні грані полігонів. Для малювання багатокутників в командних дужках використовується константа GL_POLIGON. При цьому вершини, вказані між командними дужками визначають опуклий багатокутник. Багатокутник будується із зв'язаних трикутників із загальною вершиною, як загальна вершина береться перша вершина списку (малюнок 2. Віяло трикутників). Список вершин для даного багатокутника: a1, a2, a3, a4, a5, a6, a7. При малюванні багатокутників слід мати на увазі наявність лицьових (передніх) і зворотних (задніх) граней. Може виникнути питання, навіщо при побудові плоского зображення розрізняти лицьові і зворотні грані? Проте цю відмінність слід мати на увазі при виведенні закрашених полігонів і тим більше при тривимірних побудовах. Грань вважається за лицевою, якщо вершини перераховуються в напрямі проти годинникової стрілки, і зворотною, якщо обхід вершин проводиться за годинниковою стрілкою (у негативному напрямі). Побудова неопуклих полігонів. Якщо необхідно змалювати неопуклий багатокутник, то він має бути представлений як набір опуклих багатокутників, кожен з яких описується в своїх командних дужках (Малюнок 3. Представлення неопуклого полігону за допомогою набору опуклих полігонів). Дану фігуру можна розбити на 3 опуклих багатокутника: a1a2a3a4, a1a4a6a7 і a4a5a6. Отже фігура може бути описана як 3 примітиви типа GL_POLIGON. Проте відмітимо, що перша і друга фігури – суміжні чотирикутники, а третя фігура – трикутник. Для відтворення трикутників і чотирикутників бажано використовувати «рідні» примітиви, причому, якщо це можливо – зв'язані. Тобто для побудови змальованої фігури перші два чотирикутники ми опишемо в одних командних дужках як зв'язані чотирикутники із загальною стороною a1a4 (послідовність перерахування вершин: a2, a3, a4, a1, a7, a6) – використовуємо константу командних дужок GL_QUAD_STRIP. Трикутник a4a5a6 опишемо в своїх командних дужках з константою GL_TRIANGLES. Можна вирішити це завдання і іншими способами. Взагалі оптимальним буде розбиття неопуклої фігури на трикутники, оскільки побудова трикутників, як правило, реалізована на апаратному рівні. Для згладжування (антиэлайзинга) багатокутників використовується константа GL_POLYGON_SMOOTH. Команда використовується так само, як для крапок і ліній. Оскільки трикутники і чотирикутники є багатокутниками, те згладжування для них здійснюється як для багатокутників. Особливості режимів замалювання для багатокутників. До цих пір ви змальовували багатокутники з використанням заливки, причому, якщо для різних вершин примітивів були задані різні кольори, то фігури забарвлювалися градієнтний, з плавним переходом квітів від вершини до вершини. Це відбувається через те, що за умовчанням спосіб тонування заданий плавним. Щоб змінити спосіб тонування, необхідно перед командними дужками викликати функцію glShadeModel(GL_FLAT). В цьому випадку зв'язані фігури забарвлюються за правилом старшинства кольору другого примітиву. Для завдання режиму виведення багатокутників: у контурному вигляді (без заливки), із заливкою, - використовується команда glPolygonMode. Другий параметр команди указує спосіб зображення грані фігури за допомогою наступних констант: GL_FILL – виведення граней із заливкою; GL_LINE – каркасний вивід (тільки контури); GL_POINT - виводяться тільки вершини. Перший параметр визначає для яких граней встановлений режим: лицевые – GL_FRONT; зворотні – GL_BACK; лицевые і зворотні – GL_FRONT_AND_BACK. Описана команда поміщається перед командними дужками. Завдання до лабораторної роботи. Використовуючи програму-шаблон, створену при виконанні попередньої лабораторної роботи виконайте наступні завдання. Завдання 1. Побудувати крапки розташовані у вершинах правильного n-кутника. Встановити режим згладжування для крапок. Експериментально визначити максимальний розмір крапки, при якому можливе згладжування. Завдання 2. Використовуючи примітив для виведення ліній намалювати правильний n-кутник. Змінити типа і ширину ліній. Завдання 3. Використовуючи примітив для виведення ламаної лінії намалювати фігуру, змальовану на рис.1. Завдання 4. Використовуючи примітив для виводу замкнутою ламаною намалювати фігуру, змальовану на рис.2 Завдання 5. Побудувати фігуру, змальовану на рис.2, розбивши її на трикутники (кожен трикутник забарвлений випадковим кольором). Виконаєте три варіанти побудов з використанням примітивів: А) трикутник; Б) стрічка трикутників; В) віяло трикутників. Чим відрізняються результати при зміні способу тонування? Завдання 6. Використовуючи примітив для виведення багатокутників побудувати правильний n-кутник. Завдання 7. Побудувати неопуклий багатокутник, змальований на рис.3, представивши його у вигляді сукупності окремих багатокутників, призначивши кожному багатокутнику свій колір. Подивитися результат роботи програми для різних способів тонування. Завдання 8. Змінити програму попереднього завдання так, щоб А) лицьові грані змальовувалися тільки вершинами; Б) лицьові грані змальовувалися зафарбованими, а зворотні – лініями; В) лицьові і зворотні грані змальовувалися лініями (каркасне зображення). Варіанти до завдання. Варіант 1 N=5
Варіант 2 N=7
Варіант 3 N=6
Варіант 4 N=4
Варіант 5 N=8
Додаткові завдання. У встановленому графічному вікні побудувати N крапок, забарвлених випадковим чином і розподілених випадковим чином за всією площею вікна. Фонтан. У деякій околиці заданої точки з'являються і пропадають дана кількість точок різного розміру і кольору. При натисненні клавіш управління курсором (при русі миші) з'являються і гаснуть деяка дана кількість точок випадкового розміру і кольору. Для області розміром N*N крапок (розмір крапки заданий) реалізувати алгоритм дизерингу з використанням трьох заданих квітів. Бенгальський вогонь. У деякій околиці даної крапки малюються лінії випадкового розміру, кольору і напряму (довжина ліній обмежена). Бенгальський вогонь в русі. Картинка, побудована в результаті попереднього завдання, змінюється при натисненні клавіш управління курсором. Контрольні питання. Що таке командні дужки, яке їх призначення? Які константи бібліотеки OPENGL можуть бути параметрами функції glBegin? Що таке антиелайзінг, для чого він служить? Які режими існують для малювання ліній? Які режими існують для зображення трикутників, чим вони розрізняються? Що таке опуклі і неопуклі багатокутники? Яким чином можна побудувати неопуклий багатокутник? Чим відрізняються лицьові і зворотні грані? Яка команда змінює спосіб тонування? Які режими виведення багатокутників вам відомі? У якому місці програми має бути записана команда, що змінює режим виведення багатокутників?