OpenGL/C++. Первое окно
Время чтения: 6 минут
В этой статье я расскажу как происходит инициализация OpenGL и создаётся окно в котором мы будем всё отрисовывать.
В прошлой статье я рассказал как настроить окружение и запустить самый простой проект – продолжу с того, на чём остановился.
В левой части экрана ты можешь увидеть список всех проектов – найди там проект “tutorial01_first_window” и открой файл “tutorial01.cpp”.
Там ты увидишь код, который инициализирует все библиотеки и создаёт окно – давай разберём по порядку.
Подключаем стандартные заголовки
// Include standard headers
#include <stdio.h>
#include <stdlib.h>
Тут никаких откровений – стандартные библиотеки C++ для вывода логов через всякие printf.
Подключаем заголовочный файл GLEW
// Include GLEW
#include <GL/glew.h>
GLEW это обёртка над OpenGL, которая подключает самые свежие функции OpenGL, поддерживаемые твоей системой.
У них на сайте написано: “OpenGL Extension Wrangler Library (GLEW) это кросс-платформенная C++ библиотека с открытым исходным кодом для загрузки расширений. GLEW предоставляет эффективный механизм, который в реальном времени определяет какие расширения OpenGL поддержаны на целевой платформе. Вся базовая функциональность OpenGL и его расширений предоставляется в едином заголовочном файле.
Почему в OpenGL сразу не включены все функции, зачем какие-то расширения?
OpenGL сообщает, что базовая функциональность OpenGL работает везде, а вот работоспособность расширений уже зависит от конкретного железа и операционной системы. Поэтому и приходится сначала смотреть что у тебя за система, а потом подключать функции.
Подключаем заголовочный файл GLFW и создаём указатель на окно
// Include GLFW
#include <GLFW/glfw3.h>
GLFWwindow* window;
GLFW это библиотека, в которой спрятана вся платформенно-зависимая логика создания окон и управления вводом. Без неё пришлось бы для разработки под Windows разбираться с Win API, под Linux – с Linux API, а под MacOS – Cocoa API.
У них на сайте написано: “GLFW это кросс-платформенная библиотека с открытым исходным кодом для разработки с применением OpenGL, OpenGL ES и Vulkan. GLFW предоставляет простой API для создания окон, контекстов и поверхностей, а также получения ввода и системных событий.”
Кроме подключения заголовочника, мы ещё создаём указатель на объект окна, который в дальнейшем создадим.
Подключаем заголовочный файл GLM
// Include GLM
#include <glm/glm.hpp>
using namespace glm;
GLM это библиотека, которая реализует множество математических конструкций и операций над ними – они нам пригодятся в дальнейшем.
У них в гитхабе написано: OpenGL Mathematics (GLM) это математическая библиотека из заготовочных файлов, основанная на спецификации к OpenGL Shading Language (GLSL).
Ну вроде всё, с библиотеками закончили, теперь к самому коду!
Инициализация GLFW
// Initialise GLFW
if( !glfwInit() )
{
fprintf( stderr, "Failed to initialize GLFW\n" );
getchar();
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
Первыми делом в main() мы инициализируем библиотеку GLFW, чтобы приступить к созданию окна.
После этого мы выставляем ряд параметров для окна GLFW:
- GLFW_SAMPLES – выбираем 4-х кратный экранный буфер для сглаживания MSAA. Если эту опцию не ставить, то без сглаживания все линии будут рисоваться лесенкой.
- GLFW_CONTEXT_VERSION_MAJOR и GLFW_CONTEXT_VERSION_MINOR – задают версию OpenGL, которую будет использовать приложение
- GLFW_OPENGL_FORWARD_COMPAT – опция для выставления совместимости в экзотических случаях: “можно использовать более новую версию OpenGL, если необходимо”
- GLFW_OPENGL_PROFILE – выбор подмножества функций OpenGL
Подробное описание этих и кучи других параметров можно найти здесь.
Создаём окно
// Open a window and create its OpenGL context
window = glfwCreateWindow( 1024, 768, "Tutorial 01", NULL, NULL);
if( window == NULL ){
fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n" );
getchar();
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
Вызываем функцию библиотеки GLFW для создания окна, и указываем там его ширину, высоту и заголовок. После этого делаем контекст окна активным.
Контекст – это объект из OpenGL, который в себе хранит всё-всё-всё относящееся к OpenGL (текстуры, полигоны и т.д.). GLFW заботливо заворачивает внутрь окна контекст OpenGL – мы можем создать несколько окон с разными контекстами (несколько окон с разными играми), а можем создать несколько окон с одним и тем же контекстом (одна игра на несколько окон).
Инициализация GLEW
// Initialize GLEW
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
getchar();
glfwTerminate();
return -1;
}
Инициализируем GLEW, а вместе с ней и сам OpenGL.
Включаем отслеживание клавиш для текущего окна
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
Выставляем цвет очистки окна
// Dark blue background
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
Выставляем цвет очистки окна в формате RGB (последний аргумент это альфа-канал, про него потом).
В OpenGL каждый кадр открисовывается заново. Представь как художники рисуют анимации – они рисуют сразу все кадры на отдельных холстах, а потом их меняют. OpenGL – это художник, у которого есть только два “холста”:
- OpenGL показывает пользователю первый “холст”
- В это время весь второй “холст” заливается сплошным цветом (в нашем случае синим)
- Поверх этого цвета рисуются наши 3D-модели
- OpenGL меняет местами первый и второй “холст” – теперь второй показывается пользователю, а первый перерисовывается
“Холст” называется кадром, и этот процесс происходит очень быстро. Например 60 FPS, это 60 кадров в секунду – каждые 16 миллисекунд OpenGL заканчивает рисовать кадр и меняет его с предыдущим.
Такой механизм, в котором есть два кадра – “в перерисовке” и “готовый” – называется двойной буфферизацией.
Зачищаем окно и слушаем ввод с клавиатуры
do{
// Clear the screen. It's not mentioned before Tutorial 02, but it can cause flickering, so it's there nonetheless.
glClear( GL_COLOR_BUFFER_BIT );
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
} // Check if the ESC key was pressed or the window was closed
while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0 );
Вызываем функцию OpenGL glClear(), которая очищает экран указанным в glClearColor() цветом. GL_COLOR_BUFFER_BIT говорит о том, что нужно почистить только цвет (да, в OpenGL на экране хранится не только цвет, но об этом тоже потом).
Функция glfwSwapBuffers() делает то, о чём я говорил – меняет кадры “в перерисовке” и “готовый” местами.
Фунцкия glfwPollEvents() запрашивает у системы новые события – это нужно чтобы отслеживать нажатие клавиш и прочее.
В условии цикла while:
- Через функцию glfwGetKey() мы забираем текущее состояние кнопки Escape и сравниваем с состоянием GLFW_PRESS. Без этой проверки окно не закроется при нажатии Escape.
- Вызыввем функцию чтобы получить текущее состояние окна – если пользователь нажал крестик на окне или Alt+F4, то вернётся 1. Без этой проверки окно не закроется при нажатии на крестик.
Высвобождаем ресурсы
// Close OpenGL window and terminate GLFW
glfwTerminate();
Говорим GLFW сворачиваться, а он за нас зачистит и объект окна window, и сам OpenGL – просто сказка, а не библиотека!
Задание на закрепление
Задания на закрепления всегда очень простые и преследуют цель вовлечь тебя в процесс экспериментирования (ведь это интересно).
- Замени цвет очистки окна на свой любимый цвет. Вот мой любимый цвет:
glClearColor(0.f, 227.f/255.f, 253.f/255.f, 0.0f);
- Плавная смена цвета:
- Перенеси функцию glClearColor() внутрь цикла while()
- создай вне цикла float переменную i
- Добавь внутрь цикла изменение i на 0.0001
- Подставь i вместо одной из компонент цвета в функцию glClearColor()
Заключение
Итого, мы изучили:
- Что такое библиотеки:
- GLEW (управляет расширениями OpenGL)
- OpenGL (базовая функциональность + расширения)
- GLFW (кросс-платформенная библиотека для создания и управления окнами)
- GLM (библиотека для математики)
- Двойная буфферизация (два холста)
В следующей статье ты нарисуешь самый настоящий треугольник! Это будет поворотным моментом в твоём обучениии, ведь даже самые крутые и сложные 3D-модели будут состоять из тех же самых треугольников.