Програмування з використанням бібліотеки opengl

Ви читаєте мій перший урок з OpenGL!

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

Що потрібно знати

Ці уроки орієнтуються на читача без особливих знань у програмуванні. Звичайно, знання будь-якої мови програмування (C, Java, Lisp, JavaSript) буде величезним плюсом, але це не обов'язково, просто вам доведеться вивчати два предмети одночасно – 3д графіку та програмування.

Весь код у цих уроках написано на C++ у максимально простому стилі. Жодних шаблонів, класів та арифметики з покажчиками. Тому дивлячись на код ви зможете зрозуміти, що він робить, навіть якщо знайомі лише з JavaSript.

Забудьте все, що знали про OpenGL 1/2

Ці уроки припускають, що ви нічого не знаєте про 3д графіку. Але якщо ви читали уроки з OpenGL і зустрічали щось на кшталт glBegin(), то забудьте це. Тут ми вивчатимемо OpenGL 3 і 4, а те, що ви читали ставитися до OpenGL 1 або 2. Тому рекомендую вам забути все, що ви знали раніше, інакше ваші мізки почнуть плавитися від нестиковок.

Складання проекту

Код даних уроків можна скомпілювати під Windows, Linux. Щоб почати компілювати код під будь-яку із платформ, потрібно зробити таке:

  1. Оновіть драйвера на вашу відеокарту! Я вас попередив :)
  2. Завантажте компілятор, якщо у вас ще немає.
  3. Встановіть CMake
  4. Завантажте готові вихідні уроки.
  5. Згенеруйте проект за допомогою CMake
  6. Зберіть проект.
  7. Поекспериментуйте із кодом для кращого розуміння, що там відбувається.

Нижче я навів детальніший опис складання проектів під кожну з платформ. Але в залежності від версії ОС скріншоти можуть трохи відрізнятися від того, що буде у вас на екрані, але в цілому, все має бути приблизно таким.

Складання під Windows


Складання під Linux

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

  1. Встановіть останні драйверана вашу відеокарту. Дуже рекомендую не опенсорсні драйвери. Вони не входять до складу GNU, але вони часто працюють набагато краще. Якщо ваше складання лінукса не надає автоматичного інсталятораспробуйте почитати Ubuntu's guide.
  2. Поставте компілятор із усіма необхідними бібліотекамита інструментами. Ось список того, що вам потрібно: cmake make g++ libx11-dev libgl1-mesa-dev libglu1-mesa-dev libxrandr-dev libxext-dev. Використовуйте sudo apt-get install ***** або su /yum install ******
  3. Завантажте вихідні приклади та розархівуйте їх у папку, наприклад ~/Projects/OpenGLTutorials/
  4. Зайдіть у папку ~/Projects /OpenGLTutorials / і введіть такі команди:
  • mkdir build
  • cd build
  • cmake ..
  1. Якщо попередні команди були виконані успішно, то в папці build/ буде створено makefile
  2. введіть "make all" і після цього будуть скомпільовані всі приклади та їх залежності. Якщо не буде жодних помилок, то готові виконувані файлибудуть розміщені в папці ~/Projects/OpenGLTutorials/

Мені дуже подобається використовувати IDE QtCreator. Дана IDE вміє з коробки працювати з CMake і надає купу інших плюшок, таких як налагодження автодоповнення ітд.

Інструкція зі збирання проекту в QtCreator:

1. У QtCreator натисніть File->Tools->Options->Compile&Execute->CMake

2. Вкажіть шлях до CMake. Швидше за все це буде /usr/bin/cmake

3. File->Open Project і виберіть tutorials/CMakeLists.txt

4. Вкажіть build папку, папка бажано повинна бути поза папкою tutorials.

5. Опційно встановіть –DCMAKE_BUILD_TYPE=Debug у полі параметрів.

6. Клацніть на молоток унизу.Після цього приклади можна буде запустити з папки tutorials/

7. Щоб запустити приклади з QtCreator, виберіть Projects ->Execution parameters ->Working Directory , і виберіть каталог де лежать шейдери текстури та моделі. Для уроку 2 це буде ~/opengl -tutorial /tutorial02_red_triangle/

Запуск прикладів

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

Як проходити ці уроки

Кожен урок йде разом з вихідним кодомта даними. Всі ці файли можна знайти у відповідному каталозі tutorialXX/.

Але я рекомендую вам не змінювати в цих файлах нічого, вони лише для довідки. Краще грайте в playground/playground.cpp та змінюйте там все, що захочете. Якщо ви щось зламали і не можете відновити назад, можна повернути цей файл просто скопіювавши його з будь-якого іншого уроку.

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

Відчиняємо вікно

Нарешті! OpenGL!

Хоча доведеться ще трохи почекати. У всіх уроках 3д операції будуть виконуватися на дуже низькому рівні, тому там не буде ніякої магії. Однак робота з вікнами та повідомленнями системи не цікава та нудна, тому ми дозволимо бібліотеці GLFW зробити всю брудну роботу за нас. Якщо вам звичайно дуже хочеться, ви можете використовувати Win32 Api для Windows або X11 API для Linux, або використати щось інше, типу SFML, FreeGLUT, SDL, … почитайте сторінку посилання.

Гаразд, давайте вже почнемо. Почнемо із того, що нам потрібно підключити залежності. Оскільки нам необхідно виводити повідомлення на консоль, ми напишемо таке:

// Підключаємо стандартні заголовки

#include

#include

Потім підключаємо GLEW

// Потрібно не забувати, що GLEW обов'язково необхідно підключати перед gl . h або glfw . h

#include

Потім підключаємо GLFW. Ця бібліотека робитиме всю магію керування вікнами.

#include

на даному етапінам не потрібна ця бібліотека, але вона містить математичні функції і незабаром нам знадобиться. Ніякої магії в GLM немає, і якщо вам дуже хочеться, ви можете використовувати будь-яку іншу бібліотеку для роботи з матрицями та векторами. Ми підключаємо "using namespace" для того, щоб писати "vec3", а не "glm::vec3"

#include

using namespace glm;

Якщо ви скопіюєте ці шматки коду в playground.cpp, компілятор почне обурюватися, що ні функції main(). Тому давайте додамо:

int main()(

Спочатку краще б ініціалізувати GLFW:

// Ініціалізуємо GLFW

if(!glfwInit())

{

fprintf(stderr, "Failed to initialize GLFW\n");

return -1;

}

А тепер створимо наше OpenGL віконце:

glfwOpenWindowHint( GLFW_ FSAA_ SAMPLES, 4); // 4 xзгладжування

glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3); //нам потрібен OpenGL 3.3

glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 3);

glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // нам не потрібен старий OpenGL

// Відкриємо вікно та створимо контекст

if(!glfwOpenWindow(1024, 768, 0,0,0,0, 32,0, GLFW_WINDOW))

{

fprintf(stderr, "Failed to open GLFW window\n");

У цьому розділі розглянемо рендеринг тривимірної графікиза допомогою бібліотеки OpenGL, вивчимо бібліотеки GLU та GLUT (замість останньої йод Linux використовується бібліотека FreeGLUT), розберемо процес завантаження текстур за допомогою бібліотек SOIL та DevIL.

Як зазначалося в гол. 9, програмісти графіки зазвичай не працюють безпосередньо з GPU. Це пов'язано як з тим, що існує багато різних GPU, так і з тим, що низькорівнева робота з GPU є досить складною і зазвичай нею займаються розробники драйверів. Натомість використовують різні API, що надають деякий інтерфейс. високого рівнядля роботи з GPU. Цей інтерфейс абстрагується від конкретного GPU (вся робота з яким йде через драйвер, що зазвичай постачається виробником GPU), що дозволяє писати переносний код, який працюватиме з різними GPU. Також подібний API приховує від програміста низку низькорівневих деталей роботи з GPU.

Основними API для програмування тривимірної графіки Наразіє OpenGL та Dircct3D. Останній орієнтований лише на платформу Microsoft Windows. У цій книзі розглянуто основи роботи із OpenGL. Це кросплатформний API, що підтримує всі основні операційні системи (Windows, Linux, Mac OS X) і дозволяє працювати з великою кількістюрізних GPU.

Існує версія API – OpenGL ES, призначена для роботи на мобільних пристроях. З її допомогою можна робити тривимірну графіку для платформ iOSта Android. Крім того, існує WebGL - бібліотека, що дозволяє використовувати OpenGL ES у вікні браузера, застосовуючи для цього JavaScript. Існують також прив'язки для OpenGL, що дозволяють працювати з усіма основними мовами програмування, завдяки чому можна легко використовувати OpenGL практично з будь-якої мови програмування.

Основне завдання OpenGL – рендеринг дво- та тривимірної графіки. При цьому даний APIвзагалі не займається створенням вікон для рендерингу, читанням введення від користувача та іншої подібної та сильно залежної від конкретної операційної системи роботи, тому ми будемо для цих цілей використовувати кроссплатформенну бібліотеку GLUT. Ця бібліотеканадає простий і зручний спосібдля створення вікон, рендерингу в них за допомогою OpenGL та отримання повідомлень від миші та клавіатури.

З точки зору архітектури OpenGLпобудований на моделі клієнт-сервер.При цьому сама програма, що використовує OpenGL, виступає в ролі клієнта, а GPU та його драйвер – у ролі сервера. Зазвичай програма виконується на тому самому комп'ютері, де встановлено GPU, але це не обов'язково.

На практиці всі команди OpenGL буферизуються і вже потім надходять у чергу для передачі на GPU. Таким чином, виконання CPU команди говорить лише про те, що дана командапотрапила до буфера або була додана в чергу; Цілком можливо, що GPU її ще не почав виконувати. Водночас OpenGL можна розглядати як кінцевий автомат- має свій стан. Єдиний спосібзмінити цей стан – використовувати команди OpenGL. Між командами стан OpenGL не змінюється.

Важливим поняттям у OpenGL є буфери (рис. 10.1). Для того, щоб здійснювати рендеринг, мають бути створені необхідні буфери. Буфер кольорувикористовується завжди і для кожного пікселя зберігає його колір як 24-бітове число в форматі RGB(по 8 біт на кожен з базових кольорів - червоний, зелений і синій) або як 32-бітове в форматі RGBA(До стандартних трьох компонентів додається четверта компонента - альфа, що задає непрозорість).

При використанні методу г-буфера для видалення невидимих ​​поверхонь потрібно для кожного пікселя зберігати відповідне значення глибини (зазвичай значення глибини зберігається як 16-, 24- і 32-бітове ціле число). Відповідно всі значення глибини, взяті разом, утворюють буфер глибини.Також можна використовувати буфер трафарету, буфер накопичення.

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

Обробка даних OpenGL заснована на конвеєрі рендерингу (див. рис. 9.1). Конвеєр визначає основні стадії обробки даних, що надходять. Як саме дані будуть оброблятися, залежить від параметрів стану OpenGL, але самі ці стадії та порядок їх проходження суворо зафіксовано.

Мал. 10.1.

Для сучасних GPU дві частини цього конвеєра представлені за допомогою програм, що виконуються на GPU, – шейдерів. Далі будемо розглядати OpenGL версії 2, в якій ці програми необов'язково ставити явно: існують шейдери, які працюють за замовчуванням (тобто у випадку, коли програміст явно не поставив відповідні шейдери). Починаючи з версії 3 OpenGL вимагає обов'язкового завдання шейдерів і частково порушує сумісність з попередніми версіямиСаме тому ми будемо розглядати версію OpenGL 2.

Геометрія задається як набір вершин, що утворюють різні примітиви (крапки, відрізки, трикутники). У кожній вершині, крім її координат, можна задати також ряд додаткових атрибутів, таких як колір, нормаль, текстурні координати. Дані кожної вершині надходять на вхід вершинного шейдера: кожної вершини виконується вершинний шейдер і генерує деякі вихідні значення. Обов'язковим вихідним значенням є однорідні координати вершини після всіх перетворень.

OpenGL використовує матриці 4x4 для перетворення вершин – модельно-видову матрицю проектування (рис. 10.2). Якщо вершинний шейдер не заданий явно, то використовується вершинний шейдер за умовчанням, який множить координати вершини (у вигляді вектора в однорідних координатах) спочатку модельновидову матрицю, а потім - на матрицю проектування.

Після цього відбувається складання примітивів та їх відсікання: всі частини кожного примітиву, що виходять за межі видимої області (viewing frustum)автоматично обрізаються так, що на наступну стадію конвеєра переходять примітиви, що повністю містяться в області видимості. Далі фіксована частина конвеєра виконує перспективний поділ - вектор однорідних координатах ділиться на свою четверту компоненту.


Мал. 10.2.

Якщо спочатку координати були задані у системі координат, то множення на модельно-видовую матрицю переводить в систему координат камери. Далі множення на матрицю проектування наводить координати простір відсікання (clip space).Після виконання перспективного поділу отримуємо нормалізовані координати пристрою (Normalized device coordinates).

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

Перед перспективним розподілом відбувається складання примітивів і подальше відсікання: все, що не потрапляє в область видимості, відсікається. Далі кожен примітив розтеризується, тобто. перетворюється на набір фрагментів. Ряд значень, заданих у вершинах, інтерполюється, і кожен фрагмент набуває відповідного йому значення. Після цього кожного фрагмента виконується фрагментний шейдер, завданням якого є обчислення кольору кожного фрагмента. При цьому використовуються інтерполовані значення, можливе звернення до текстур - заздалегідь підготовлених зображень, які накладаються на примітиви, що виводяться. Зазначимо, що кожен фрагмент має свої координати на екрані і отримане шляхом інтерполяції значення глибини р. Також фрагментний шейдер замість обчислення кольору фрагмента може явно відкинути весь фрагмент.

На наступному етапі конвеєра для кожного фрагмента виконується група перевірок, кожна з яких може відкинути цей фрагмент. Перша з цих перевірок вивчає, чи цей піксел відповідає видимій частині вікна. Якщо ні, цей фрагмент відразу ж відкидається. Наступний тест перевіряє, чи міститься фрагмент усередині заданого прямокутника (у координатах вікна). Також є тести трафарету та глибини. Тест трафарету витягує з буфера трафарету групу бітів, відповідних даному фрагменту, та перевіряє виконання умови для цих бітів. Тест глибини виконує порівняння глибини фрагмента з відповідним значенням буфера глибини. Кожен із цих тестів може призвести до відкидання відповідного фрагмента. Крім того, є альфа-тест, що дозволяє відкидати фрагменти, виходячи зі значення альфа-компоненти її кольору.

Після цього виконується крок змішування кольору фрагмента з кольором, який відповідає даному фрагменту в буфері кольору. Ця операціяпотрібна для підтримки напівпрозорого™.

Обчислення значення кольору може бути з набагато більшою точністю, ніж можна зберегти в буфері кольору. Зазвичай у цьому випадку відбувається просто заокруглення кольору. Використання растрування (dithering)надає інший варіант: колір змінюють таким чином, щоб середній показник по ряду пікселів, що стоять, дав потрібне значення.

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

Якщо ви пишете програму, що використовує OpenGL на С (або C++), то перш за все необхідно включити наступний файл заголовка:

Для забезпечення сумісності та переносимості коду OpenGL вводить ряд своїх типів даних, ім'я кожного з цих типів починається з префікса GL. GLint відповідає стандартного типуцілих чисел, тип GLuint – стандартного типу беззнакових цілих чисел, a GLfloat – типу float. Також OpenGL використовує кілька спеціальних типів, таких як GLsizei, що позначає тип, що використовується для завдання розміру, і GLclampf, що використовується для завдання значень плаваючою точкою, що лежать на відрізку .

Також вводиться спеціальний тип GLenum для позначення типу значень, які відповідають різним константам.

У бібліотеці OpenGL (а також у бібліотеках GLU і GLUT, що йдуть з нею в комплекті) прийнято використовувати досить просту угоду про іменування констант і функцій. Імена всіх команд (функцій) OpenGL починаються з префікса gl (для функцій з бібліотек GLU та GLUT – з glu та glut відповідно).

Імена всіх констант починаються з GL_ (відповідно до GLU_ і GLUTJ.

Багато команд OpenGL мають декілька різних варіантів, що відрізняються числом переданих аргументів та їх типами. У цьому випадку в ім'я команди також входить спеціальний суфікс, що містить число параметрів, і суфікс, що задає їх тин. Таким чином, ім'я команди в OpenGL зазвичай має такий вигляд:

glCommand(1 2 3 4)(b s i f d ub us ui)(v)

Необов'язкова цифра служить для завдання кількості аргументів, що передаються (у тому випадку, коли є версії цієї команди з різним числомаргументів). Далі йде необов'язковий суфікс з однієї або двох літер, що задає тип аргументів, що передаються (у тому випадку, коли існують версії цієї команди, що приймають вхідні значення різних типів). Суфікс v повідомляє про те, що ряд параметрів (зазвичай набір останніх параметрів) переданий у вигляді масиву - насправді функція замість цих параметрів отримує покажчик на цей масив.

Так, у команді glVertex2i два цілих аргументи, у команді glColor3f - три аргументи типу float, а в команді glColor4ubv - чотири аргументи типу unsigned byte, переданих у вигляді масиву (тобто функція при виклику отримує лише один аргумент - адресу масиву).

OpenGL є на даний момент одним з найпопулярніших програмних інтерфейсів (API) для розробки додатків у галузі двовимірної та тривимірної графіки. Стандарт OpenGL було розроблено та затверджено у 1992 році провідними фірмами в галузі розробки програмного забезпечення, а його основою стала бібліотека IRIS GL, розроблена Silicon Graphics.

На даний момент реалізація OpenGL включає декілька бібліотек (опис базових функцій OpenGL, GLU, GLUT, GLAUX та інші), призначення яких буде описано нижче.

Характерними особливостями OpenGL, які забезпечили поширення та розвиток цього графічного стандарту, є:

Стабільність - доповнення та зміни у стандарті реалізуються таким чином, щоб зберегти сумісність із розробленим раніше програмним забезпеченням.

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

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

Основні можливості OpenGL

    Набір базових примітивів: крапки, лінії, багатокутники тощо.

    Видові та координатні перетворення

    Видалення невидимих ​​ліній та поверхонь (z-буфер)

    Використання сплайнів для побудови ліній та поверхонь

    Накладання текстури та застосування освітлення

    Додавання спеціальних ефектів: туману, зміна прозорості, сполучення кольорів (blending), усунення ступінчастості (anti-aliasing).

Як було сказано, існує реалізація OpenGL для різних платформ, для чого було зручно розділити базові функції графічної системи та функції для відображення графічної інформаціїта взаємодії з користувачем. Було створено бібліотеки для відображення інформації за допомогою віконної підсистеми для операційних систем Windowsта Unix (WGL та GLX відповідно), а також бібліотеки GLAUX та GLUT, які використовуються для створення так званих консольних додатків.

Бібліотека GLAUX поступається за популярністю написаній пізніше бібліотеці GLUT, хоча вони надають приблизно однакові можливості. До складу бібліотеки GLU увійшла реалізація складніших функцій, таких як набір популярних геометричних примітивів (куб, куля, циліндр, диск), функції побудови сплайнів, реалізація додаткових операцій над матрицями тощо. Усі вони реалізовані через базові функції OpenGL.

Архітектура та особливості синтаксису

З погляду архітектури, графічна система OpenGL є конвеєром, що складається з кількох етапів обробки даних:

    Апроксимація кривих та поверхонь

    Обробка вершин та складання примітивів

    Розтеризація та обробка фрагментів

    Операції над пікселями

    Підготовка текстури

    Передача даних у буфер кадру

Взагалі OpenGL можна порівняти з кінцевим автоматом, стан якого визначається безліччю значень спеціальних змінних (їхні імена зазвичай починаються з символів GL_) і значеннями поточної нормалі, кольору та координат текстури. Усе це буде використано під час вступу до системи координат вершини для побудови фігури, куди вона входить. Зміна станів відбувається за допомогою команд, які оформлюються як дзвінки функцій.

ІНІЦІАЛІЗАЦІЯ БІБЛІОТЕКИ OpenGL У C++

Насамперед потрібно підключити заголовні файли:

#include

#include

#include

· gl.h і glu.h містять прототипи основних функцій OpenGL, визначених в opengl32.dll і glu32.dll.

· glaux.h містить допоміжні (auxiliary) функції (glaux.dll).

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

BOOL bSetupPixelFormat(HDC hdc)

PIXELFORMATDESCRIPTOR pfd, *ppfd;

int pixelformat;

ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);

ppfd->nVersion = 1;

ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;

ppfd->dwLayerMask = PFD_MAIN_PLANE;

ppfd->iPixelType = PFD_TYPE_RGBA;

ppfd->cColorBits = 16;

ppfd->cDepthBits = 16;

ppfd->cAccumBits = 0;

ppfd->cStencilBits = 0;

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

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

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

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

Структура PIXELFORMATDESCRIPTOR сказати треба.

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

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

cStencilBits - розмір буфера трафарету (ми поки що не використовуємо)

iPixelType – формат вказівки кольору. Може приймати значення PFD_TYPE_RGBA (колір вказується чотирма параметрами RGBA - червоний, чорний, синій та альфа) та PFD_TYPE_COLORINDEX (колір вказується індексом у палітрі).

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

Після того, як у контексті пристрою встановлено формат пікселів, потрібно створити контекст відтворення (Rendering Context) для цього в OpenGL визначено такі функції:

HGLRC wglCreateContext(HDC hdc);

BOOL wglMakeCurrent(HDC hdc, HGLRC hglrc);

У оголошенні класу форми в області private необхідно додати наступне:

ghRC - покажчик на контекст відтворення (Rendering Context)

ghDC - дескриптор пристрою (для нас - просто вказівник на вікно)

Процедура Draw відповідатиме за малювання.

void __fastcall TForm1::FormCreate(TObject *Sender)

ghDC = GetDC(Handle);

if (!bSetupPixelFormat(ghDC))

ghRC = wglCreateContext(ghDC);

wglMakeCurrent(ghDC, ghRC);

glClearColor(0.0, 0.0, 0.0, 0.0);

FormResize(Sender);

glEnable(GL_COLOR_MATERIAL);

glEnable(GL_DEPTH_TEST);

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

float p=(3,3,3,1),

glLightfv(GL_LIGHT0,GL_POSITION,p);

glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,d);

glViewport(0, 0, Width, Height);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

glOrtho(-5,5, -5,5, 2,12);

gluLookAt(0,0,5, 0,0,0, 0,1,0);

glMatrixMode(GL_MODELVIEW);

glClearColor() встановлює колір, яким заповнюватиметься екран під час очищення. Ця процедура має 4 параметри, що відповідає RGBA. Замість неї можна написати glClearIndex(0.0). Ця процедура встановлює індекс кольору на панелі.

glViewport() встановлює область виводу - область, в яку OpenGL виводитиме зображення.

glMatrixMode() встановлює режим матриці видового перетворення.

glLoadIdentity() замінює поточну матрицю видового перетворення на одиничну.

glOrtho() встановлює режим ортогонального (прямокутного) проектування. Це означає, що зображення буде малюватись як в ізометрії. 6 параметрів типу GLdouble (або просто double): left, right, bottom, top, near, far визначають координати відповідно лівої, правої, нижньої, верхньої, ближньої та далекої площин відсікання, тобто. все, що виявиться за цими межами, малюватись не буде. Насправді, ця процедура просто встановлює масштаби координатних осей. Для того щоб встановити перспективне проектування, використовуються процедури glFrustum() та gluPerspective().

gluLookAt() встановлює параметри камери: перша трійка – її координати, друга – вектор напряму, третя – напрямок осі Y.

В OpenGL все включається та вимикається (дозволяється та забороняється) процедурами glEnable() та glDisable().

glLightfv() встановлює властивості "лампочек": позицію та напрямок світла.

Після завершення роботи з OpenGL потрібно звільнити зайняті ресурси: звільнити контекст, викликавши wglMakeCurrent з параметром нуль для ідентифікатора контексту OpenGL і зруйнувати цей контекст функцією wglDeleteContext. Крім того, потрібно видалити дескриптор ghDC. Так як зазвичай роботу з OpenGL завершується при завершенні роботи програми, то відповідний код потрібно помістити у FormClose:

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)

wglMakeCurrent(ghDC,0);

wglDeleteContext(ghRC);

ReleaseDC(Handle, ghDC);

ВИСНОВОК

За час проходження виробничої практики з 5 липня до 31 липня 2011 р. у ЗАТ «Транзас», Авіаційний напрямок у відділі програмування, я ознайомився з роботою відділу програмування. Ознайомився з улаштуванням та функціонуванням комплексних авіа тренажерів, що розробляються у ЗАТ «Транзас». Я дізнався про таку систему візуалізації ландшафтів та різних об'єктів, як «Аврора». Я отримав початкові практичні навички та вміння, необхідні для розробки програм та програмного забезпечення за допомогою сучасної високорівневої мови програмування та графічної бібліотеки.

Зазвичай область, де необхідно визначити наявність об'єктів (область вибору об'єктів), визначається як фрагмент проекції сцени. Наприклад, користувач на зображенні проекції виділяє за допомогою маніпулятора (наприклад, покажчика типу "миша") прямокутну область або просто клацає кнопкою "миші", визначаючи таким чином область вибору.

Так як у цих випадках область вибору визначається на проекції тривимірної сцени, необхідно визначити відповідну їй область тривимірної сцени (сцена вибору). Сцена вибору залежатиме від кількох факторів: використовуваної проекції, розмірів сцени та області виведення.

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

У бібліотеці OpenTK функції бібліотеки GLUT знаходяться у класі Glu у просторі імен Tao .OpenGL(C#). У Object Pascal всі функції та процедури бібліотеки GLUT мають префікс "glu", що дозволяє їх відрізняти від процедур та функцій OpenGL.

Для формування матриці проекції на основі вибраного фрагмента проекції сцени можна використовувати команду PickMatrix бібліотеки GLUT:

C#: void gluPickMatrix(double x, double y, double width, double height, int viewport); Object Pascal: procedure gluPickMatrix (x, y, width, height: GLdouble; viewport: PGLint);

Команда PickMatrix GLUT бібліотеки змінює поточну матрицю таким чином, щоб розмір області сцени відповідав області вибору, визначеної в координатах проекції цієї сцени. Команди має такі параметри:

  • x, y – горизонтальна та вертикальна координати області вибору у координатах вікна, в якому відображається проекція тривимірної сцени.
  • width, height – ширина та висота обраної прямокутної області проекції тривимірної сцени в координатах вікна.
  • viewport – масив чотирьох цілих елементів. У C# передається безпосередньо масив як параметр, в Object Pascal як параметр передається покажчик на масив. Масив визначає область виведення проекції тривимірної сцени. Значення масиву повинні відповідати координатам виводу, визначеним за допомогою команди ViewPort . Елементи цього масиву повинні мати наступні значення: 1й та 2й елементи – координати x та у лівого верхнього кутавиділеної області в координатах екрана, 3 та 4 елементи – ширина та висота цієї області.

Команда повинна бути виконана перед виконанням команд Ortho або Frushtum, за допомогою яких формується матриця проекції.

Переведення бібліотеки OpenGL у режим вибору

Для переведення бібліотеки в режим вибору використовується команда RenderMode:

C#: int RenderMode(RenderingMode mode); Object Pascal: функція glRenderMode(mode: GLenum): GLint;

Параметр mode визначає режим роботи бібліотеки OpenGL і може набувати одного з трьох значень:

Таблиця 10.1. Можливі значення параметра mode команди RenderMode
Опис Значення
Бібліотека OpenTK, C# Object Pascal
Режим вибору дане значеннявикористовується для переведення бібліотеки в режим вибору. RenderingMode.Select GL_SELECT
Режим формування зображення сцени. Цей режим використовується за замовчуванням після ініціалізації бібліотеки OpenGL. Саме в цьому режимі виконується формування зображення бібліотекою OpenGL. RenderingMode.Render GL_RENDER
Режим зворотний зв'язок. RenderingMode.Feedback GL_FEEDBACK

Після перемикання в режим вибору бібліотека OpenGL не формує зображення доти, доки режим не буде змінено на режим формування зображення сцени за допомогою команди RenderMode зі значенням параметра RenderingMode.Render C# і GL_RENDER на Object Pascal.

Найменування та формування об'єктів сцени

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

Так як об'єкти, з якими працює користувач, зазвичай формуються з різних примітивів, то для визначення обраного об'єкта використовується стек імен. Імена є цілочисленними значеннями. Перед початком виведення чергового об'єкта в стек імен міститься ім'я (номер) цього об'єкта. Якщо під час формування об'єкта бібліотека виявляє, що примітиви цього об'єкта потрапляють у область вибору, то зміст стека імен копіюється в буфер вибору (разом із деякою додатковою інформацією), ініціалізованого за допомогою команди SelectBuffer. При попаданні в область сцени примітивів іншого іменованого об'єкта зміст стека імен так само буде скопійовано в буфер вибору. Таким чином можуть бути отримані імена (номери) об'єктів, які повністю або частково потрапили в область вибору. Необхідно враховувати, що для коректного визначення вибраних об'єктів необхідно, щоб координатні перетворення об'єктів збігалися з тими, які виконувалися при формуванні зображення сцени.

Для роботи зі стеком імен використовують кілька команд. Очищення стека імен виконується за допомогою команди InitNames:

C#: void InitNames(); Object Pascal: procedure glInitNames;

Поміщення імені у стек виконується за допомогою команди PushName:

C#: void PushName(uint name); Object Pascal: procedure glPushName(name: GLuint);

Ім'я передається як параметр команди.

Перед використанням стека імен він повинен бути ініціалізований за допомогою команди InitNames. Потім у стек необхідно помістити один елемент за допомогою команди PushName. Перед формуванням кожного з об'єктів єдиний елемент стека імен буде замінюватися на ім'я об'єкта, що формується за допомогою команди LoadName . Процедура замінює останній елемент у стеку імен на заданий як параметр. Таким чином, ініціалізація та використання стека імен схематично можна представити наступним чином:

InitNames; PushName(0); … LoadName(1); / / Формування об'єкта № 1 LoadName (2); / / Формування об'єкта № 2 LoadName (3); / / Формування об'єкта № 3 / / І т.д. Лістинг 10.7. Схема використання стек імен для вибору об'єктів

У цьому розділі ми навчимося створювати тривимірні зображення за допомогою функцій бібліотеки OpenGL для того, щоб у наступному розділі розробити Windows-додаток, який можна розглядати як інструмент перегляду результатів наукових розрахунків. Матеріал цього розділу дозволить вам поступово увійти в курс справи та опанувати дуже привабливу технологію створення та управління тривимірними зображеннями. Спочатку ми розглянемо основні можливості бібліотеки OpenGL, потім навчимося керувати функціями OpenGLна прикладі простих додатківконсольного типу і лише після цього приступимо до розробки Windows-програми.

Читач, напевно, знає, що OpenGL це оптимізована, високопродуктивна графічна бібліотекафункцій та типів даних для відображення дво- та тривимірної графіки. Стандарт OpenGL було затверджено у 1992 р. Він заснований на бібліотеці IRIS GL, розробленій компанією Silicon Graphics (www.sgi.com). OpenGL підтримують усі платформи. Крім того, OpenGL підтримано апаратно. Існують відеокарти з акселераторами та спеціалізовані SD-картки, які виконують примітиви OpenGL на апаратному рівні.

Матеріал першої частини цього уроку навіяний дуже гарною книгою (доступною в online-варіанті) видавництва Addison-Wesley "OpenGL Programming Guide, The Official Guide to Learning OpenGL". Якщо читач володіє англійською мовою, то ми рекомендуємо її прочитати.

бібліотеки, що підключаються

Microsoft-реалізація OpenGL включає повний набіркоманд OpenGL, тобто глобальних функцій, що входять до ядра бібліотеки OPENGL32.LIB та мають префікс gl(наприклад, glLineWidth). Зауважте, що функції з ядра бібліотеки мають безліч версій, що дозволяє задати бажаний параметр або налаштування будь-яким зручним для вас способом. Перегляньте довідку з сімейства glColor*. Виявляється, що встановити поточний колір можна 32 способами. Наприклад, функція:

Void glColorSb(GLbyte red, GLbyte green, GLbyte blue);

Визначає колір трьома компонентами типу GLbyte, а функція:

Void glColor4dv (const GLdouble *v);

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

З урахуванням цих варіантів ядро ​​бібліотеки містить понад 300 команд. Крім того, ви можете підключити бібліотеку утиліт GLU32.LIB, які доповнюють головне ядро. Тут є функції управління текстурами, перетворенням координат, генерацією сфер, циліндрів та дисків, сплайнових апроксимацій кривих та поверхонь ( NURBS - Non-Uniform Rational B-Spline), і навіть обробки помилок. Ще одна, додаткова ( auxiliary) бібліотека GLAUX.LIB дозволяє простим способомстворювати Windows-вікна, зображати деякі SD-об'єкти, обробляти події введення та керувати фоновим процесом. На жаль, цю бібліотеку не документовано. Компанія Microsoftне рекомендує користуватися нею для розробки комерційних проектів, оскільки вона містить код циклу обробки повідомлень, який неможливо вставити обробку інших довільних повідомлень.

Примітка
Тип GLbyte еквівалентний типу signed char, a GLdouble - типу double. Свої власні типи використовують із метою спрощення переносимості інші платформи. Список типів OpenGL ми наведемо нижче. Четвертий компонент кольору визначає прозорість кольору, тобто спосіб змішування кольору тла із кольором зображення. Деякі команди OpenGL мають наприкінці символ v, який вказує, що її аргументом має бути адреса масиву (вектора). Вектор у математиці - це послідовність чисел (координат), що єдиним чином задають елемент векторного простору. Багато команд мають кілька версій, дозволяючи зрештою задати вектор різними способами
.

Близько двадцяти Windows GDI-функцій створено спеціально для роботи з OpenGL. Більшість із них має префікс wgl(Абревіатура від Windows GL). Ці функції є аналогами з префіксом glx, які підключають OpenGL до платформи X window System. Нарешті, існує кілька Win32-функцій для керування форматом пікселів та подвійний буферизацією. Вони застосовні лише для спеціалізованих вікон OpenGL.