Перейти к основному содержимому

OpenGL — 3D-графика на C++

Разработчику Архитектору

Что такое OpenGL

OpenGL — кроссплатформенный графический API: набор функций для описания геометрии, текстур, шейдеров и состояния GPU. Драйвер видеокарты переводит вызовы OpenGL в команды железа.

Важно разделять роли:

  • OpenGL — только рендер (что рисовать на GPU);
  • GLFW / SDL / SFML — окно, контекст, swap buffers, ввод;
  • GLAD / GLEW — загрузка указателей на функции OpenGL 3.3+ (на Windows OpenGL32.dll знает лишь устаревшие версии).

OpenGL не создаёт игру и не загружает PNG — это ваш C++ код и stb_image.

Теория конвейера и GLSL — OpenGL и шейдеры. Здесь — практический C++-стек и место OpenGL среди SFML, SDL, Raylib, DirectX и Vulkan.


Ключевые понятия

ТерминОпределение
Core profileРежим OpenGL 3.3+ без устаревшего fixed-function
VBOVertex Buffer Object — массив вершин в памяти GPU
VAOVertex Array Object — привязка атрибутов вершин к шейдеру
EBO / IBOИндексный буфер — переиспользование вершин в mesh
Shader programСкомпилированная пара vertex + fragment shader
UniformГлобальная переменная шейдера (MVP, цвет, текстура)
MVPModel × View × Projection — цепочка 3D-трансформаций
FramebufferЦелевой буфер кадра (цвет + depth)

Математика 3D — компьютерная графика.


Стек для учёбы на C++

КомпонентРоль
GLFWОкно, контекст OpenGL, glfwSwapBuffers, ввод
GLAD или GLEWЗагрузка glGen*, glDraw* и т.д.
GLMmat4, vec3, lookAt, perspective
stb_imagePNG/JPG → пиксели для glTexImage2D
CMakeСборка (1006)

Окно через SDL: SDL_GL_CreateContext. Через SFML: window.setActive(true) + GLAD.


OpenGL, Vulkan и DirectX

КритерийOpenGL 3.3+VulkanDirectX 12
ПлатформыWin, Linux (macOS — deprecated)Win, Linux, Android; macOS via MoltenVKWindows, Xbox
УправлениеСреднееПолноеПолное
Первый треугольникБыстрееДольшеСредне (D3D11 проще)
CPU overheadВышеНижеНизкий
ШейдерыGLSLSPIR-VHLSL → DXIL

Правило выбора: OpenGL — учёба 3D на Windows/Linux. Vulkan — свой движок (29). DirectX — Windows/Xbox (2746). 2D без шейдеров — Raylib или SFML.


Core profile и конвейер

С OpenGL 3.3 fixed-function (glBegin/glEnd) убран. Минимальная цепочка:

CPU: данные в VBO → привязка VAO → glDrawElements
GPU: Vertex Shader → Rasterization → Fragment Shader → Framebuffer

Этапы GPU (подробнее — 18):

  • Vertex shader — позиция каждой вершины (gl_Position), передача UV и нормалей;
  • Rasterization — треугольник → фрагменты (будущие пиксели);
  • Fragment shader — цвет пикселя, текстуры, освещение;
  • Depth test — Z-buffer отсекает скрытые поверхности.

Минимальный каркас на C++ с GLFW и GLAD

#include <glad/glad.h>
#include <GLFW/glfw3.h>

static void framebuffer_size_callback(GLFWwindow*, int w, int h) {
glViewport(0, 0, w, h);
}

int main() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", nullptr, nullptr);
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);

glEnable(GL_DEPTH_TEST);

while (!glfwWindowShouldClose(window)) {
glClearColor(0.12f, 0.12f, 0.16f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// drawScene(mvp);
glfwSwapBuffers(window);
glfwPollEvents();
}

glfwTerminate();
return 0;
}

Разбор построчно

  • glfwWindowHint(..., CORE_PROFILE) — запрос modern OpenGL; без hints macOS может дать 2.1.
  • glfwMakeContextCurrent — OpenGL привязан к потоку; вызывать GL из другого потока нельзя без sharing.
  • gladLoadGLLoader(glfwGetProcAddress) — загрузка функций; до этого glClear может упасть.
  • glEnable(GL_DEPTH_TEST) — без depth 3D-объекты "просвечивают" друг через друга.
  • glClear — очистка color + depth буферов каждый кадр.
  • glfwSwapBuffers — double buffering; показ готового кадра.
  • glfwPollEvents — обработка закрытия окна и ввода.

Шейдеры подключают отдельно: читают .vert/.frag, glCompileShader, glLinkProgram, лог через glGetProgramInfoLog.


MVP и камера через GLM

glm::mat4 model = glm::mat4(1.f);
glm::mat4 view = glm::lookAt(
glm::vec3(0.f, 0.f, 3.f), glm::vec3(0.f), glm::vec3(0.f, 1.f, 0.f));
glm::mat4 proj = glm::perspective(
glm::radians(45.f), aspect, 0.1f, 100.f);
glm::mat4 mvp = proj * view * model;
glUniformMatrix4fv(locMvp, 1, GL_FALSE, &mvp[0][0]);
  • Model — положение объекта в мире.
  • View — положение камеры (обратная трансформация мира).
  • Projection — перспектива или ортография.
  • В vertex shader: gl_Position = uMVP * vec4(aPos, 1.0).

Текстуры

Типичный порядок:

  1. stbi_load → пиксели на CPU;
  2. glGenTextures, glTexImage2D, glGenerateMipmap;
  3. Fragment shader: uniform sampler2D uTex; + texture(uTex, vUV).

OpenGL считает начало текстуры снизу; для stb часто нужен stbi_set_flip_vertically_on_load(true).


CMake-фрагмент

find_package(glfw3 REQUIRED)
find_package(glad REQUIRED)
find_package(glm CONFIG REQUIRED)

add_executable(gl_app main.cpp)
target_link_libraries(gl_app PRIVATE glfw glad glm::glm)

Шейдеры копируют в build dir: file(COPY shaders DESTINATION ${CMAKE_BINARY_DIR}).


OpenGL внутри других фреймворков

ФреймворкКак получить OpenGL
SFMLwindow.setActive(true) + GLAD
SDLSDL_GL_CreateContext
QtQOpenGLWidget, Qt Quick Scene Graph
RaylibGL скрыт; raw GL — отдельное окно GLFW/SDL

Desktop UI на GL — Qt. Только Windows — DirectX.


Когда OpenGL уместен

СценарийOpenGL
Учебный курс 3D, Linux/WindowsДа
Новый macOS-only продуктMetal / MoltenVK
Максимум CPU→GPU throughputVulkan / D3D12
2D без шейдеровRaylib, SFML

Частые ошибки

СимптомПричинаРешение
Segfault на glDraw*GLAD не загруженloader после context
Пустой экранviewport 0×0callback resize
Розовые текстурыformat / mipmapinternalFormat, mipmap
Z-fightingnear plane слишком близкоподнять near, log depth

Что читать дальше