Создаём компьютерную игру
eng   рус

Инициализация OpenGL в Windows

Следующий урок: Основы OpenGL и рендеринг треугольника. Графический конвейер, вершинный и фрагментный шейдеры

Сегодня мы узнаем всё (реально всё), что нужно, чтобы запустить программу на C/C++, использующую OpenGL на Windows. Прикреплённые проекты сделаны в Visual Studio 2019. В уроке мы рассмотрим полную инициализацию OpenGL.

Список библиотек я брал из вики для OpenGL. Для урока я выбрал наиболее простые варианты в настройке.

Первая программа на OpenGL 4.6

Версия 4.6, которую мы будем рассматривать вышла довольно давно (июль 2017). Поэтому, у вас не должно возникнуть проблем, но, на всякий случай, установите последнюю версию драйверов. Драйвера, поддерживающие OpenGL 4.6, для видеокарт AMD и NVidia вышли в 2018. Аппаратная поддержка доступна начиная c AMD Radeon HD 5000 (2009г.) и NVidia GeForce 400 (2010г.). Драйвера для встроенных адаптеров Intel вышли в первой половине 2019г. В случае, если ваша видеокарта не поддерживает четвёртую версию OpenGL, рекомендую обратить внимание на Mesa3D - это программная реализация OpenGL.

Так как OpenGL является кроссплатформенным API, то не существует стандартного способа инициализации. Для использования OpenGL в программе необходимо сделать две вещи: создать OpenGL контекст и загрузить функции OpenGL API. Для каждой из этих задач существуют разные библиотеки.

Начнём мы с загрузки OpenGL функций.

Загрузка функций OpenGL API

В спецификации OpenGL описываются множество разных функций. Например, самая первая OpenGL функция, которую мы будем использовать: glGenVertexArrays. Необходимо чтобы наша программа узнала, что такая функция существует. Для этого мы будем использовать одну из библиотек: GLEW или glatter.

В спецификации имена OpenGL функций выглядят так: GenVertexArrays, BindVertexArray, BeginQuery. В реальном коде к этим именам нужно добавлять префикс gl (зависит от библиотеки, в некоторых это не так): glGenVertexArrays, glBindVertexArray, glBeginQuery, glUseProgram.

GLEW (OpenGL Extension Wrangler)

Скачиваем GLEW (первый файл для Windows, на данный момент это glew-2.1.0-win32.zip). Распаковываем в любую папку. В настройках проекта добавляем папку include и lib (lib\Release\x64). Из папки bin\Release\x64 копируем файл glew32.dll в папку с нашим проектом.

У меня все библиотеки лежат в папке: C:\prog\libs, соотвественно, путь к glew: C:\prog\libs\glew-2.1.0. Свойства проекта в Visual Studio открываются через пункт меню Проект → Свойства (Project → Properties) или через контекстное меню проекта в обозревателе решений.

В коде после создание контекста (об этом ниже) нужно вызвать функцию glewInit. Вот весь код, касающийся GLEW:

#include <GL/glew.h> // включаем заголовочный файл #pragma comment( lib, "glew32.lib" ) // добавляем статичную библиотеку // Не забудьте ещё скопировать dll в папку с проектом int main(int argc, char* argv[]) { // создание контекста OpenGL glewInit(); }

После вызова glewInit мы можем пользоваться функциями OpenGL.

По поводу имени библиотеки GLEW. GLEW расшифровывается как OpenGL Extension Wrangler. Wrangler - пастух. Соотвественно, название библиотеки можно понимать как: тот, кто управляет расширенями OpenGL. Про расширения мы будем говрить позже.

glatter

Второй вариант - glatter. Скачиваем и распаковываем. Если вы не пользовались github, то проходите по ссылке, нажимайте зелёную кнопку Clone or download (справа) → Download Zip. После разархивирования, добавляем папку include к проекту:

Теперь в коде осталось только включить заголовочный файл и можно вызывать OpenGL функции. Инициализировать ничего не надо (вызов функций можно делать только после создания OpenGL контекста):

#include <glatter/glatter.h>

Я не смог найти значение названия библиотеки glatter. Автор из Германии и там это слово есть - одна из форм слова "блестящий".

Другие библиотеки для загрузки OpenGL API

Существуют и другие библиотеки для загрузки OpenGL функций, но они требуют больше действий чем GLEW или glatter. Некоторые из этих вариантов: GL3W (использует скрипт на Python для генерациий заголовочных файлов OpenGL), glLoadGen (использует Lua скрипт), Galogen (командная утилита), Glad (приложение на Python или веб страница). В этих библиотеках используются дополнительные зависимости.

Кроме того, вы можете самостоятельно загрузить OpenGL функции, не используя вышеперечисленные библиотеки. В Windows для этого используется функция wglGetProcAddress. В качестве аргумента мы передаём имя функции (в виде строки char*), которую мы хотим получить, а возвращает она, соответственно, адрес этой функции. При таком способе вам нужно будет самостоятельно загружать каждую OpenGL функцию. wglGetProcAddress объявлена в wingdi.h, а для её использования необходимо подключить библиотеки Opengl32.lib, Opengl32.dll. Это информация для общего развития, в дальнейших уроках мы будем пользоваться только GLEW или glatter.

Теперь мы переходим к созданию контекста OpenGL.

Создание OpenGL контекста

Что такое OpenGL контекст мы поговорим в следующем уроке. Сейчас нам важно, что OpenGL контекст привязывается к окну. Так как OpenGL - кросплатформенная API, а в разных операционных системах окна создаются совершенно по-разному, это означает, что и создание контекста происходит по-разному. В спецификации OpenGL ничего не сказано, как создавать контекст. Существуют разные библиотеки для решения этой задачи. Мы рассмотрим freeglut, SDL2 и GLFW. Эти библиотеки отвечают за создание окна, OpenGL контекста, смену кадров, очередь сообщений.

Важно: При создании проекта для любой библиотеки выбирайте консольное приложение. Все библиотеки используют консольное приложение и самостоятельно создают окна. При этом, мы будем использовать следующую форму main:

int main(int argc, char* argv[]) { }

freeglut требует аргументы arc и argv, а SDL2 требует именно этот вариант main. Для GLFW аргументы main не имеют значения.

Также, обратите внимание, в какой момент вызывается glewInit (после создания контекста).

Ещё одна ремарка: во всех случаях необходимо подключить библиотеку OpenGL32.lib. В ней определены самые старые функции OpenGL (ещё с первой версии), такие как, glClear, glClearColor. Архиктура не имеет значения, x86 и x64 должны использовать один и тот же файл.

Приложения на всех библиотеках имеют одинаковую структуру:

  • Инициализация OpenGL
  • Инициализация GLEW
  • Главный цикл:
    • Проверка событий (нажатие клавиш клавиатуры/мышки...) в очереди
    • Очистка буфера кадра (glClear, glClearColor)
    • Рендеринг кадра (именно здесь будут использоваться функции OpenGL, загруженные с помощью GLEW). В этом уроке этого не будет
    • Смена кадров (вывод буфера на экран). У нас есть две 2д картинки - фоновый буфер и основной. Основной буфер - это то, что пользователь видит на экране. Пока пользователь смотрит на основной буфер, мы рисуем в фоновом следующий кадр. Кода мы отрисовали кадр, мы меняем указатели буферов местами: фоновый становится основным и наоборот. Теперь пользователь видит новый кадр, а мы можем рисовать новый в фоновом буфере
  • Освобождение ресурсов

GLFW

Скачиваем GLFW (Graphics Library Framework). Под заголовком Windows pre-compiled binaries выбираем 64-bit Windows binaries. Распаковываем. У меня это папка C:\prog\libs\glfw-3.3.2.bin.WIN64. Заголовочные файлы, как обычно в папке include, а библиотеки в lib-vc2019. Нужно скопировать glfw3.dll в папку с вашим проектом.

Теперь полный код:

#include <GL/glew.h> #include <GLFW/glfw3.h> #pragma comment( lib, "glew32.lib" ) #pragma comment( lib, "glfw3.lib" ) #pragma comment (lib, "OpenGL32.lib") int width = 800; int height = 600; int main(int argc, char* argv[]) { glfwInit(); GLFWwindow* window = glfwCreateWindow(width, height, "OpenGL first program", nullptr, nullptr); glfwMakeContextCurrent(window); glewInit(); while (!glfwWindowShouldClose(window)) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, GL_TRUE); glClearColor(0.5f, 0.5f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glfwSwapBuffers(window); glfwPollEvents(); } glfwTerminate(); return 0; }

В программе с GLFW мы используем следующие функции: glfwInit, glfwCreateWindow, glfwMakeContextCurrent, glfwWindowShouldClose, glfwGetKey, glfwSetWindowShouldClose, glfwSwapBuffers, glfwPollEvents, glfwTerminate.

Сначала инициализируем GLFW, создаём окно и присваиваем ему контекст. При создании окна с помощью glfwCreateWindow мы указываем ширину/высоту окна и заголовок, остальные аргументы не важны. Затем инициализируем GLEW.

В основном цикле мы проверяем, была ли нажата клавиша Escape, и если да, то устанавливливаем закрывающий флаг (его мы проверяем в условии цикла с помощью glfwWindowShouldClose). Обратите внимание, что для управления вводом GLFW определяет свои константы (GLFW_KEY_ESCAPE, GLFW_PRESS), их имена говорят сами за себя.

Затем, в основном цикле мы очищаем буфер кадра, выводим содержимое на экран и проверяем события в очереди событий.

После окончания основного цикла мы вызываем glfwTerminate.

glClearColor задаёт цвет, которым будет заполняться фоновый буфер (это 2д картинка, в которой происходит рисование кадра) при очистке. glClear очищает фоновый буфер. Здесь мы очищаем только цвет - GL_COLOR_BUFFER_BIT. Ещё мы можем очищать буфер глубины, но об этом позже.

glfwSwapBuffers выводит содержимое на экран. Имя функции - swap buffers - поменять буферы местами. В других библиотеках тоже есть подобная функция.

SDL2

Библиотека SDL (Simple DirectMedia Layer), помимо OpenGL, имеет возможности для работы с 2д графикой и звуком.

Переходим. В разделе Development Libraries выбираем файл SDL2-devel-2.0.10-VC.zip. Распаковываем архив и настраиваем папки проекта.

#include <GL/glew.h> #include <SDL.h> #pragma comment( lib, "glew32.lib") #pragma comment( lib, "SDL2.lib") #pragma comment( lib, "SDL2main.lib") #pragma comment( lib, "OpenGL32.lib") int width = 800; int height = 600; int main(int argc, char* argv[]) { SDL_Init(SDL_INIT_EVERYTHING); SDL_Window* window = SDL_CreateWindow("OpenGL first program", 100, 100, width, height, SDL_WINDOW_OPENGL); SDL_GLContext context = SDL_GL_CreateContext(window); glewInit(); bool quit = false; SDL_Event e; while (!quit) { while (SDL_PollEvent(&e) != 0) { if (e.type == SDL_QUIT) { quit = true; } } glClearColor(0.5f, 0.5f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); SDL_GL_SwapWindow(window); } SDL_GL_DeleteContext(context); SDL_DestroyWindow(window); SDL_Quit(); return 0; }

В SDL2 мы используем следующие функции: SDL_Init, SDL_CreateWindow, SDL_GL_CreateContext, SDL_PollEvent, SDL_GL_SwapWindow, SDL_GL_DeleteContext, SDL_DestroyWindow, SDL_Quit. Сначала мы инициализируем SDL, используя флаг SDL_INIT_EVERYTHING (everything - всё), который говорит, что мы хотим инициализировать все системы SDL: графику, звук, таймеры, устройства ввода. В нашем случае можно обойтись только SDL_INIT_VIDEO. После этого мы создаём окно и OpenGL контекст.

В основном цикле мы проверяем очередь событий (SDL_PollEvent), очищаем буфер и выводим содержимое на экран с помощью смены кадров (SDL_GL_SwapWindow).

Если произошло событие SDL_QUIT, мы заканчиваем цикл, изменяя переменную quit, затем удаляем контекст, окно, и освобождаем все ресурсы.

freeglut

Я упоминаю здесь freeglut (The Open-Source OpenGL Utility Toolkit) только для соотстветсвия с английской версией урока, который я писал несколько лет назад. На данный момент рекомендую использовать GLFW или SDL. freeglut больше подходит для Linux.

FreeGLUT основывается на библиотеке GLUT, которая была создана в 1994г. (да и устарела GLUT уже как двадцать лет).

Проходим по Ссылке и ищем там "Download freeglut 3.0.0 for MSVC" в разделе freeglut 3.0.0 MSVC Package. После распаковки архива указываем в своём проекте пути к заголовчным файлам и библиотеке. Также, необходимо скопировать freeglut.dll в папку с проектом.

#include <GL/glew.h> #include <GL/freeglut.h> #pragma comment( lib, "glew32.lib" ) #pragma comment( lib, "freeglut.lib" ) #pragma comment (lib, "OpenGL32.lib") int width = 640; int height = 480; void displayFunc(void); int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitWindowSize(width, height); int id = glutCreateWindow("OpenGL first program"); glewInit(); glutDisplayFunc(displayFunc); glutMainLoop(); exit(0); } void displayFunc(void) { glClearColor(0.5f, 0.5f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glutSwapBuffers(); }

Здесь мы используем функции из freeglut: glutInit, glutInitWindowSize, glutCreateWindow, glutDisplayFunc, glutMainLoop, glutSwapBuffers. Собственно, инициализируем саму библиотеку, задаём размер окна и затем создаём его, указываем функцию, которая будет вызываться каждый кадр (displayFunc), запускаем основной цикл. В каждом кадре мы очищаем буфер и выводим содержимое буфера на экран с помощью glutSwapBuffers.

Заключение

В прикреплённом решении для Visual Studio 2019 есть три проекта для GLFW, SDL, freeglut. Везде используется GLEW. В данных проектах есть все нужные файлы: включаемые файлы и библиотеки, и они находятся в папках проектов. В следующих уроках вам нужно будет самостоятельно добавлять библиотеки. Я постраюсь поддерживать код для GLFW/SDL2 в связке с GLEW.

Я бы, конечно, хотел добавить проекты для VSCode и Linux, но не уверен, что это кому-нибудь нужно, а на проверку и написание уходит много времени.

Теперь, когда есть основа программы, версию OpenGL можно проверить с помощью функции glGetString:

const GLubyte* version = glGetString(GL_VERSION);

Значение можно посмотреть в отладчике или привести тип и вывести в консоль (все приложения GLFW, SDl2 и freeglut - консольные).

За рамками урока, как обычно, осталась проверка возвращаемых значений разных функций. Если возникнут проблемы, пишите в комментарии (это позволит дополнить урок), отвечу, по возможности, быстро.

Комментарии:

30 июля 2020 г. 7:04
1 Guest
Друзья, щедро делюсь с вами своим наблюдением. Нашла тут сайт, при добавлении на который, мой баннер размещается на всех сайтах сделанных одной web-студией, их не много, но они достойные! Есть посещаемые социальные сети и видно, что функционирующие Интернет магазины... Как по мне получить такую рекламу сразу всего за 5 рублей в сутки вариант не требующий больших затрат. Да это ротатор, но метрика стала показывать заходы с этого сервиса и некоторые длятся почти два часа с четырьмя зелеными кружками, раньше такого не было. Если что не так, не судите строго, посоветуйте, может я не права? <a href=https://karalinka.ru>Добавь свой баннер сразу на несколько сайтов</a>
5 августа 2020 г. 11:18
3 Guest
Using Propecia Results Enhagnax https://ascialis.com/ - Cialis unimmeri Priligy Comprimidos bofsSoup <a href=https://ascialis.com/#>Cialis</a> crebmaccum how long does cialis work for
2 августа 2020 г. 16:03
2 Guest
Друзья, здравствуйте! Монтаж, установка и обслуживание климатической техники. Интернет магазин кондиционеров, заказать установку кондиционера на выгодных условиях можно у нас. Поможем выбрать кондиционер <a href=https://climat-spb.ru>каталог кондиционеров</a>