Opengl основи
Ми вже говорили, що в більшості випадків в тривимірних іграх за одну секунду кілька разів повністю будується кадр. Іншими словами, завжди, коли програма вільна від обробки повідомлень системи, потрібно викликати якусь функцію, назвемо її DrawFrame (), яка буде кожен раз виводити всі об'єкти в кадрі.
Дотримуючись нашого прикладу побудови програми, видно, що ця функція повинна викликатися з функції OnIdle ().
Які спільні дії повинні відбутися в функції DrawFrame ()? Перш за все, потрібно очистити невидимий буфер (Back buffer), вивести всі об'єкти в цей буфер і зробити невидимий буфер - видимим.
Для очищення використовується функція glClear (). Цією функцією очищають кілька типів буферів, нас цікавить той, в якому зберігається колірне зображення (color buffer). Тому функцію glClear будемо викликати з параметром GL_COLOR_BUFFER_BIT.
Реалізація функції DrawFrame () (додати в OpenGL.cpp):
Функцію DrawObjects () залиште поки з порожнім тілом, після будемо її використовувати в наших прикладах з виведення графічних примітивів.
графічні примітиви
Існує кілька типів примітивів: точки, лінійні сегменти і полігони.
У функціях, що відповідають за виведення примітивів, потрібно вказувати, які саме примітиви будуть виводитися, вказуючи відповідний режим. Наприклад, для виведення точок, виставляється режим GL_POINTS, для виведення ліній - GL_LINES, а для трикутників - GL_TRIANGLES. Крім цього, є спеціальні режими, які використовуються для зручності і оптимізації. Наприклад, GL_QUADS - виводяться чотирьох вершинні примітиви, GL_TRIANGLE_STRIP - виводиться ланцюжок трикутників, у якій кожен наступний трикутник має загальне ребро з попереднім і т.д.
Всі примітиви описуються вершинами.
Вершина є дані, що використовуються для виведення примітивів. Ними можуть бути вершинні координати, колір вершини, нормаль, текстурні координати і реберні прапори.
Висновок примітивів послідовністю вершинних функцій
Це найстаріший спосіб виведення вершин, реалізований в OpenGL.
Примітив задається окремими функціями для кожної вершини між функціональними дужками glBegin () і glEnd ().
Режим, який відповідає за тип примітиву, виставляється в функції glBegin (). наприклад:
означає, що ми будемо виводити трикутники, задаючи кожен з них трьома вершинами.
Функції glVertex * - задають координати вершини, які в свою чергу описують форму геометричного об'єкта. При виконанні такої функції, інші дані вершини, такі як вектор нормалі і колір, беруться з встановлених раніше "поточних" значень.
Приклад. Задаємо три (3) координати типу GLfloat (f) для вершини:
Ця функція виведе найпростіший полігон - трикутник, кожна вершина якого задається glVertex3f (). Ще раз зверніть увагу, що всі функції glVertex * знаходяться між glBegin () і glEnd ().
Поточні значення деяких даних для вершин можна виставити наступними функціями:
glColor * - задає колір RGBA вершини разом з умовами освітленості.
glNormal * - задає вектор нормалі, відповідний окремої вершині.
glTexCoord * - задає поточні текстурні координати для вершини.
Поточні значення для вершини виставляються до виклику glVertex *.
Ця функція малює трикутник з двома червоними вершинами і однієї синьої.
Висновок примітивів, використовуючи масиви
Цей метод відправляє на прорахунок відразу пачку вершинних даних. Тобто вершинні параметри, такі як координати, нормалізує обмін речовин і кольору вершин, задаються не окремими функціями OpenGL для кожної вершини, а окремими масивами координат, нормалей і ін. Цей метод зазвичай працює швидше і більш зручний, коли ви працюєте з об'єктами з великою кількістю вершин .
Вказівка OpenGL на масиви відбувається окремими функціями, сам висновок теж відбувається окремою функцією.
Наприклад, виведемо знову той самий трикутник.
Маємо масив вершин:
тут послідовно розташовано по три координати для трьох вершин.
Установка масиву для вершинних координат відбувається функцією glVertexPointer ():
Перший параметр в цій функції говорить, скільки координат йде на одну вершину, можливі значення - 2,3,4. Другий параметр відповідає за тип координат. Третій параметр дорівнює кроку в байтах між даними з координатами для кожної вершини. 0 в нашому випадку означає, що координати лежать щільно один за одним. Четвертий параметр - власне сам покажчик на масив з координатами.
Крім того, що ми виставили покажчик на масив, необхідно виставити стан для OpenGL, що означає, що ми будемо використовувати покажчик на масив вершин. Цей стан виставляється функцією glEnableClientState ().
Аналогічним чином ви можете виставляти покажчики на масиви для інших вершинних даних. І не забувайте включати відповідний стан. Якщо вам не потрібен для якогось об'єкта, якийсь із встановлених масивів, ви можете його просто відключити, прибравши стан функцією glDisableClientState ().
Включене стан залишається включеним, до тих пір, поки ви його не вимкнете. Тобто, якщо у вас послідовно йде висновок декількох об'єктів, що містять свої, наприклад, вершинні масиви, досить одного включення стан для всіх об'єктів перед виведенням першого об'єкта.
Якщо ми хочемо, щоб об'єкт виводився, використовуючи координати з масиву, але мав, наприклад, один загальний колір для всіх вершин, то не потрібно будувати масив з однаковими значеннями кольору. Користуйтеся вже відомої вам функцією glColor * ().
Розглянемо тепер одну з функцій, що відповідають за виведення примітиву з використанням виставлених масивів.
Виводить примітиви за даними в масивах.
mode - режим, який відповідає за тип примітиву,
first - індекс вершини, з якої ми будемо виводити об'єкт,
count - кількість вершин.
У нашому випадку - для одного трикутника використовуємо 3 вершини.
Зверніть увагу, що ця функція повинна викликатися поза пари glBegin () і glEnd ().
індексні примітиви
Пізніше, в OpenGL в версії 1.1 ввели додатковий метод для виведення на екран. Цей метод дозволяє працювати з індексним завданням геометричних об'єктів для виведення на прорахунок адаптера.
Що це означає? Майже всі полігональні моделі мають трикутники із загальними вершинами. І звичайно, таких вершин велика кількість. Ясно, що зберігати і використовувати копії однакових вершин марнотратно.
Розглянемо найпростіший приклад.
Маємо три сусідніх трикутника із загальними вершинами. Для першого і другого трикутника - загальні вершини 1 і 2, для другого та третього - 2,3. Вершина 2 загальна для всіх трикутників.
Якби ми не використовували індексний спосіб завдання об'єкта, то нам знадобилося б задати для виведення цих трикутників 9-ть вершин (по три для кожного трикутника).
Однак можна задати тільки 5-ть вершин, використовуючи масиви для координат і інших вершинних даних, а самі трикутники виводити, вказуючи індекси, відповідні розташуванню вершинних даних в масивах.
Тобто
для першого трикутника індекси будуть - 0,1,2
для другого - 1,3,2
для третього - 2,3,4
Розглянемо одну з функцій для роботи з індексами.
Ця функція використовується всередині пари glBegin () і glEnd (). Власне їй ми і ставимо індекси. А масиви з даними про самих вершинах встановлюються раніше.
Цей приклад виводить три кольорових трикутника.
Однак індекси також можна задавати масивом і виводити об'єкт одним викликом без пари glBegin () і glEnd ().
Це можна зробити функцією:
тут
mode - як завжди виставляє режим типу полігонів,
count - кількість індексів, що беруться з масиву,
type - тип елементів в індексному масиві, може приймати значення: GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT або GL_UNSIGNED_INT. Зазвичай під індекси використовують unsigned short.
indices - покажчик на масив з індексами. Зауважте, що цей покажчик можна розцінити, як покажчик на елемент, з якого відбуватиметься розрахунок об'єкта. Тобто ви можете поставити покажчик на будь-який елемент в масиві.
Для ясності новий приклад:
Приклад виводить ті ж самі трикутники, оскільки колір не виставляється, то все трикутники будуть білими.