1. Настройка окружения и основы современного C++ для игр
Настройка окружения и основы современного C++ для игр
Зачем эта статья и что будет дальше
В этом курсе мы будем учиться делать игровой рендеринг и базовую архитектуру приложения на чистом Vulkan API, параллельно укрепляя навыки современного C++.
Эта первая статья решает две задачи:
Далее в курсе мы постепенно перейдём к созданию окна, инициализации Vulkan (instance, device, swapchain), загрузке шейдеров, рендер-проходам, синхронизации и структуре мини-движка.
Что именно мы собираем
Минимальная цель после этой статьи: проект, который
VkResult.> Vulkan — низкоуровневый графический API. Он даёт контроль и производительность, но требует явного управления ресурсами и синхронизацией. Поэтому в этом курсе мы с самого начала будем опираться на практики современного C++.
Выбор платформы и компилятора
Vulkan доступен на Windows и Linux. В курсе примеры будут кроссплатформенными на уровне CMake.
Рекомендуемые варианты
Полезные ссылки:
Стандарт C++
Рекомендуемый минимум: C++20. Если у вас ограничения, допустим C++17, но часть удобных типов (например, std::span) придётся заменять.
Инструменты, которые нужны почти всегда
Git
Git нужен, чтобы
Ссылка:
CMake
CMake — генератор сборочных файлов. Он позволит собирать один и тот же проект в Visual Studio, Ninja, Make и так далее.
Ссылка:
Менеджер зависимостей (опционально, но полезно)
Для библиотек вроде GLFW и math-библиотек удобно использовать менеджер зависимостей.
Самый простой старт на Windows и Linux:
Если вы пока не хотите менеджер зависимостей, можно подключить GLFW через CMake FetchContent (покажу ниже).
Установка Vulkan SDK
Вам нужен Vulkan SDK от LunarG. Он обычно включает:
vulkan.h),glslangValidator).Установка:
VULKAN_SDK выставлена (обычно ставится установщиком)Ссылка:
Справочные материалы Vulkan:
Окно и ввод: GLFW
Vulkan не создаёт окно сам. Для кроссплатформенного окна и ввода мы используем GLFW.
Ссылка:
Важно: мы будем использовать GLFW только для окна и поверхностей (surface). Весь рендер — на Vulkan.
Отладка графики: RenderDoc
RenderDoc позволяет захватывать кадр и смотреть:
Ссылка:
Как выглядит рабочий цикл разработки
!Схема того, как исходники превращаются в приложение и где подключаются инструменты отладки
Структура проекта
Рекомендуемая минимальная структура:
CMakeLists.txtsrc/main.cpp
- vk_check.hpp
assets/shaders/
external/ (если не используете менеджер зависимостей)Почему так удобно:
Минимальный CMake-проект с Vulkan и GLFW
Ниже пример CMake, который:
find_packageFetchContentCMakeLists.txt:
Пояснения:
find_package(Vulkan REQUIRED) просит CMake найти Vulkan, установленный через SDK/систему.FetchContent скачает GLFW при конфигурации проекта.APP_ENABLE_VALIDATION — наш флаг, чтобы включать слои валидации только в debug.Минимальный стартовый код
Проверка VkResult
Vulkan-функции часто возвращают VkResult. Это код результата: успех или конкретная ошибка.
Сделаем маленький помощник:
src/vk_check.hpp:
Почему это полезно:
Создание окна и Vulkan instance
src/main.cpp:
Что здесь важно понимать:
GLFW_INCLUDE_VULKAN заставляет GLFW подключить Vulkan-заголовки корректно.glfwGetRequiredInstanceExtensions возвращает список расширений Vulkan, необходимых для работы с окнами на вашей платформе.VkInstance — самый первый объект Vulkan: контекст API.Слои валидации: зачем они нужны
Слои валидации (validation layers) — это прослойка, которая проверяет правильность вызовов Vulkan и сообщает о проблемах:
Базовый слой, который обычно используют:
VK_LAYER_KHRONOS_validationИсходники и документация проекта:
Важно: включить слой — это только половина дела. Позже мы добавим debug messenger, чтобы сообщения приходили в консоль в удобном виде.
Основы современного C++ для Vulkan и игр
Ниже — только те основы, которые сразу помогают писать надёжный код вокруг Vulkan.
Время жизни объектов и RAII
В Vulkan вы постоянно создаёте и уничтожаете объекты: instance, device, image, buffer, semaphore и так далее.
RAII — подход, где ресурс захватывается в конструкторе объекта C++, а освобождается в деструкторе. Тогда даже при раннем выходе из функции или исключении ресурсы корректно освободятся.
Мини-идея:
Пока мы вручную вызвали vkDestroyInstance. В следующих статьях начнём оборачивать Vulkan-объекты в маленькие RAII-обёртки.
Владение памятью: std::unique_ptr и std::shared_ptr
std::unique_ptr<T> — единоличное владение. Самый частый выбор по умолчанию.std::shared_ptr<T> — разделяемое владение с подсчётом ссылок. Полезно реже, потому что дороже и может скрывать жизненный цикл.Для игр и Vulkan-кода обычно выгодно:
shared_ptr в горячих местахПеремещение вместо копирования (move semantics)
Большие контейнеры (std::vector, std::string) копировать дорого. C++ умеет перемещать — передавать владение внутренним буфером без копирования.
Это критично для:
Практическое правило:
Контейнеры и представления данных
std::vector<T> — основной динамический массив.std::span<T> — не владеющее представление массива: указывает на память, но не управляет ей.std::string_view — не владеющее представление строки.Почему это важно для игр:
span и string_view помогают делать API удобным и быстрымenum class вместо обычных enum
enum class даёт более строгую типизацию. Это уменьшает количество ошибок, когда разные перечисления случайно смешиваются.
Для движка это полезно, например, для:
constexpr для констант и таблиц
constexpr позволяет вычислять значения на этапе компиляции, где это возможно. В играх это удобно для:
Обработка ошибок в Vulkan-стиле
Vulkan редко использует исключения: большинство функций возвращает VkResult.
В C++-коде проекта возможны два подхода:
Мы в начале курса используем vkCheck(..., "...") с исключениями для простоты. Когда архитектура станет серьёзнее, обсудим, где исключения уместны, а где лучше явные коды ошибок.
Проверка окружения: как понять, что всё установлено
Признаки, что вы готовы к следующим статьям:
vkCreateInstanceVK_LAYER_KHRONOS_validation находится (если нет — переустановите SDK или проверьте переменные окружения)Если vkCreateInstance возвращает ошибку:
Итоги
Теперь у вас есть:
VkInstanceВ следующей статье мы расширим каркас: добавим debug messenger, аккуратную инициализацию, выбор физического устройства (GPU) и подготовимся к созданию swapchain.