λλ¬λ³΄κΈ°
μ΄λ² μ±ν°μμλ μ΄λ―Έ μμ±λ μ€μΌλ ν€ μ½λλ₯Ό μ΄ν΄λ³΄λ©° ν΄λΉ μ½λκ° μ€μ λ‘ μ΄λ€ μν μ νλ μ§ νμΈν΄λ³΄κ² μ΅λλ€.
νμΌμ project/src/ ν΄λμ μμ΅λλ€.
- vk_engine.h/cpp : μ΄λ μμ§μ ν΅μ¬ ν΄λμ€μ λλ€. νν 리μΌμμ λ€λ£° λλΆλΆμ μ½λκ° μλ κ³³μ λλ€.
- main.cpp : μ½λμ μ§μ μ μ λλ€. vk_engine νΈμΆ μΈμλ μ무 μ½λλ μμ΅λλ€.
- vk_initializers.h/cpp : Vulkan ꡬ쑰체λ₯Ό μμ±νλ κ²μ λλ ν¨μκ° ν¬ν¨λμ΄ μμ΅λλ€.
- vk_images.h/cpp : μ΄λ―Έμ§μ κ΄λ ¨λ ν¨μλ€μ ν¬ν¨λμ΄ μμ΅λλ€.
- vk_pipelines.h/cpp : νμ΄νλΌμΈμ μν μΆμνκ° ν¬ν¨λμ΄ μμ΅λλ€.
- vk_descriptors.h/cpp : λμ€ν¬λ¦½ν° μ (descriptor set) μΆμνκ° ν¬ν¨λμ΄ μμ΅λλ€.
- vk_loader.h/cpp : GLTF νμΌμ λΆλ¬μ€κΈ° μν ν¨μκ° ν¬ν¨λμ΄ μμ΅λλ€.
- vk_types.h : μ 체 μ½λ λ² μ΄μ€λ μ΄ ν€λλ₯Ό ν¬ν¨ν©λλ€. μ΄λ λ리 μ¬μ©λλ κΈ°λ³Έ ꡬ쑰체μ ν¬ν¨ νμΌμ μ 곡ν©λλ€.
vk_engine
μ νλ‘μ νΈμ μ€μ¬μ΄μ μ£Όμ μμ§ ν΄λμ€κ° λ κ²μ
λλ€. vk_loader
λ GLTF νμΌμ λΆλ¬μ¬ λ vk_engine
κ³Ό μνΈμμ©ν΄μΌ νλ―λ‘, μ΄μ ν΅ν©λ μμ μ
λλ€. κ·Έ μΈμ λ€λ₯Έ νμΌλ€μ νν λ¦¬μΌ μ§νμ λ°λΌ λ§λ€μ΄μ§λ μΌλ°μ μΈ Vulkan μΆμν κ³μΈ΅μΌλ‘, Vulkan μΈμλ λ³λ€λ₯Έ μμ‘΄μ±μ΄ μμ΅λλ€. λ°λΌμ μ΄λ¬ν μΆμν νμΌλ€μ μ¬λ¬λΆμ λ€λ₯Έ νλ‘μ νΈμμλ μμ λ‘κ² νμ©ν μ μμ΅λλ€.
μ½λ
#include <vk_engine.h>
int main(int argc, char* argv[])
{
VulkanEngine engine;
engine.init();
engine.run();
engine.cleanup();
return 0;
}
λ¨μν main.cpp
λ‘ μμν©λλ€. VulkanEngine
ν¨μλ₯Ό νΈμΆνλ κ²μΈμλ μ무κ²λ νμ§ μμ΅λλ€.
ν₯νμλ argc/argv
μμ μ λ¬λ λͺ
λ Ήμ€ μΈμλ μ€μ νμΌμ μ΄μ©ν΄ νλΌλ―Έν°λ₯Ό ꡬμ±νλ μ©λλ‘ μ¬μ©ν μλ μμ΅λλ€.
vk_types.h
μ λ€μμ ν¬ν¨ν©λλ€.
#pragma once
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include <span>
#include <array>
#include <functional>
#include <deque>
#include <vulkan/vulkan.h>
#include <vulkan/vk_enum_string_helper.h>
#include <vk_mem_alloc.h>
#include <fmt/core.h>
#include <glm/mat4x4.hpp>
#include <glm/vec4.hpp>
#define VK_CHECK(x) \
do { \
VkResult err = x; \
if (err) { \
fmt::print("Detected Vulkan error: {}", string_VkResult(err)); \
abort(); \
} \
} while (0)
#pragrma once
λ μ»΄νμΌλ¬μκ² κ°μ νμΌμ λ λ² ν¬ν¨νμ§ λ§λΌκ³ μλ €μ£Όλ μ μ²λ¦¬κΈ° μ§μλ¬Έμ
λλ€. μ΄λ ν€λκ°λμ λμΌν μν μ νμ§λ§ λ κ°κ²°ν©λλ€.
<vulkan/vulkan.h>
λΌλ Vulkan ν΅μ¬ ν€λλ₯Ό ν¬ν¨ν©λλ€. μ΄λ μ°λ¦¬κ° νμλ‘ νλ λͺ¨λ ꡬ쑰체μ Vulkan ν¨μ μ μλ₯Ό λ΄κ³ μμ΅λλ€. λν μ½λ μ λ°μ μ¬μ©ν fmt λΌμ΄λΈλ¬λ¦¬μ ν΅μ¬ ν€λλ₯Ό ν¬ν¨νκ³ VK_CHECK
λ§€ν¬λ‘λ₯Ό λ§λ€μ΄ Vulkan νΈμΆ μ μλ¬λ₯Ό κ΄λ¦¬ν κ²μ
λλ€. νν 리μΌμμλ vk_enum_string_helper.h
λ₯Ό μ¬μ©ν κ²μ
λλ€. μ΄λ Vulkan SDKκ° μ 곡νλ ν€λλ‘, μ£Όμ΄μ§ Vulkan μ΄κ±°νμ λν λ¬Έμμ΄μ κ°μ Έμ¬ μ μκ² ν΄μ€λλ€. μ΄λ¬ν λ°©μμΌλ‘ λ‘κ·Έλ₯Ό μμ±ν λ λ§€μ° μ μ©ν©λλ€.
μ΄ νν 리μΌμ μΆλ ₯μ μν΄ νμ€ std::cout
μ μ¬μ©νμ§ μμ κ²μ
λλ€. λμ {fmt}
λΌμ΄λΈλ¬λ¦¬λ₯Ό λμ μ¬μ©ν κ²μ
λλ€. μ΄λ λ¬Έμμ΄ ν¬λ§·ν
κ³Ό μΆλ ₯μ μν κ³ νμ§ λΌμ΄λΈλ¬λ¦¬μ
λλ€. C++20μ std::format
μ μ΄ λΌμ΄λΈλ¬λ¦¬λ₯Ό κΈ°λ°μΌλ‘ μμ±λμμ§λ§, λ λ§μ κΈ°λ₯κ³Ό μ§μμ μν΄ ν΄λΉ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νκ² μ΅λλ€. μ¬κΈ°μλ Vulkan μλ¬κ° λ°μν κ²½μ° fmt::println
μ μ¬μ©ν΄ μ½μμ°½μ μλ¬λ₯Ό μΆλ ₯νκ² μ΅λλ€.
vk_initializers.h
λ μ¬μ μμ±λ νμΌμ
λλ€. μ΄λ λλΆλΆμ Vulkan info ꡬ쑰체μ λ€λ₯Έ μ μ¬ν κ²λ€μ μ΄λμ
λΌμ΄μ λ₯Ό λ΄μ΅λλ€. μ΄λ μ΄λ¬ν ꡬ쑰체λ€μ μ½κ° μΆμννμ¬ μ΄λ₯Ό μ¬μ©ν λ λ§λ€ μ½λμ μΆμνμ λν΄ μ€λͺ
ν κ²μ
λλ€.
Vulkan κ·Έ μ체λ₯Ό λ΄λ vk_types
ν€λλ₯Ό ν¬ν¨νκ³ , μ΄ν μ΄κ³³μ μΆκ°ν ν¨μλ₯Ό λ΄μ λ€μμ€νμ΄μ€λ₯Ό μ μΈν©λλ€.
λ§μ§λ§μΌλ‘ ν΅μ¬ ν΄λμ€μΈ vk_engine.h
λ₯Ό μ΄ν΄λ΄
μλ€.
#pragma once
#include <vk_types.h>
class VulkanEngine {
public:
bool _isInitialized{ false };
int _frameNumber {0};
bool stop_rendering{ false };
VkExtent2D _windowExtent{ 1700 , 900 };
struct SDL_Window* _window{ nullptr };
static VulkanEngine& Get();
//initializes everything in the engine
void init();
//shuts down the engine
void cleanup();
//draw loop
void draw();
//run main loop
void run();
};
vk_initializers
κ³Ό λ§μ°¬κ°μ§λ‘ vk_types
λ₯Ό ν¬ν¨ν©λλ€. Vulkan νμ
μΈ VkExtent2D
κ° νμνκΈ° λλ¬Έμ
λλ€. VulkanEngineμ μ°λ¦¬κ° μμ
ν ν΅μ¬μ
λλ€. μμ§μ΄ μννλ λλΆλΆμ μμ
μ μ΄ ν΄λμ€λ₯Ό μ€μ¬μΌλ‘ μμ
ν κ²μ
λλ€. μ΄λ κ² νλ©΄ νλ‘μ νΈμ μν€ν
μ²λ₯Ό λ¨μνκ² λ§λ€ μ μμ΅λλ€.
μμ§μ΄ μ΄κΈ°ν λμλμ§λ₯Ό νμΈνλ νλκ·Έ, νλ μμ λνλ΄λ μ μ, κ·Έλ¦¬κ³ μ°½μ ν¬κΈ°λ₯Ό ν½μ λ¨μλ‘ μ μ₯νλ λ³μλ₯Ό κ°μ΅λλ€.
μ μΈ struct SDL_Window* _window;
λ νΉν μ€μν©λλ€. struct
κ° λ§¨ μμ μ¨ μ μ μ μν©μλ€. μ΄λ μ λ°© μ μΈμ΄λΌ λΆλ¦¬λ κ²μΌλ‘, VulkanEngine ν€λμ SDLμ ν¬ν¨μν€μ§ μκ³ λ ν΄λμ€ λ΄λΆμμ SDL_Window
ν¬μΈν°λ₯Ό μ¬μ© κ°λ₯νκ² ν΄μ€λλ€. μ΄ λ³μλ μ ν리μΌμ΄μ
μμ λ§λ€ μ°½μ λ΄κ³ μμ΅λλ€.
λν Get()
ν¨μλ₯Ό μ μ μ±ν΄ν€ ν¨ν΄μΌλ‘ μΆκ°νμ΅λλ€.
ν€λμ λν΄ λ€λ€λ³΄μμΌλ―λ‘, cpp νμΌμ μ΄ν΄ λ΄ μλ€.
vk_engine.cpp line 1
#include "vk_engine.h"
#include <SDL.h>
#include <SDL_vulkan.h>
#include <vk_initializers.h>
#include <vk_types.h>
#include <chrono>
#include <thread>
λ€λ₯Έ νμΌλ€κ³Όλ λ¬λ¦¬, μ¬κΈ°μλ λ λ§μ κ²λ€μ ν¬ν¨νκ³ μμ΅λλ€. <SDL.h>
μ <SDL_vulkan.h>
λͺ¨λλ₯Ό ν¬ν¨νκ³ μμ΅λλ€. SDL.h
λ SDL λΌμ΄λΈλ¬λ¦¬μ μ°½μ μ΄κ³ μ
λ ₯μ λ°λ ν΅μ¬ λ°μ΄ν°λ₯Ό λ΄κ³ μμ΅λλ€. λ°λ©΄ SDL_vulkan.h
λ Vulkan νΉμ νλκ·Έμ Vulkanκ³Ό νΈνλλ μ°½μ μ΄κΈ° μν κΈ°λ₯, κ·Έ μΈμλ λ€μν Vulkan νΉμ κΈ°λ₯μ λ΄κ³ μμ΅λλ€. λν μ¬μ©ν λͺλͺ STL 컨ν
μ΄λλ μΆκ°ν©λλ€.
vk_engine.cpp, line 10
constexpr bool bUseValidationLayers = false;
VulkanEngine* loadedEngine = nullptr;
VulkanEngine& VulkanEngine::Get() { return *loadedEngine; }
void VulkanEngine::init()
{
// only one engine initialization is allowed with the application.
assert(loadedEngine == nullptr);
loadedEngine = this;
// We initialize SDL and create a window with it.
SDL_Init(SDL_INIT_VIDEO);
SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_VULKAN);
_window = SDL_CreateWindow(
"Vulkan Engine",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
_windowExtent.width,
_windowExtent.height,
window_flags);
// everything went fine
_isInitialized = true;
}
SDL μ°½μ μμ±νλ 첫 λ²μ¬ μ½λλ₯Ό μ΄ν΄λ΄
μλ€. 첫 λ²μ§Έλ‘ νλ κ²μ SDL λΌμ΄λΈλ¬λ¦¬ μ΄κΈ°νμ
λλ€. SDL λΌμ΄λΈλ¬λ¦¬λ λ€μν κΈ°λ₯μ ν¬ν¨νκ³ μκΈ° λλ¬Έμ μ°λ¦¬κ° μ΄λ€ κΈ°λ₯μ μ¬μ©ν κ²μΈμ§μ λν νλκ·Έλ₯Ό μ λ¬ν΄μΌ ν©λλ€. SDL_INIT_VIDEO
λ SDLμκ² κΈ°λ³Έ μ°½ κΈ°λ₯μ μ¬μ©νκ³ μΆλ€λ κ²μ μλ €μ€λλ€. μ΄λ λν ν€λ³΄λμ λ§μ°μ€ μ
λ ₯μ λ°λ κΈ°λ³Έ μ
λ ₯ μ΄λ²€νΈλ ν¬ν¨ν©λλ€.
λν Vulkan μμ§μ μ±κΈν€μΌλ‘ μ°Έμ‘°νκΈ° μν μ μ ν¬μΈν°λ₯Ό μ€μ ν©λλ€. μ νμ μΈ μ±κΈν€ λμ μ΄μ²λΌ μμ νλ μ΄μ λ ν΄λμ€κ° μ΄κΈ°νλκ³ νκ΄΄λλ μμ μ λͺ μμ μΌλ‘ μ μ΄νκΈ° μν΄μμ λλ€. μΌλ°μ μΈ C++ μ±κΈν€ ν¨ν΄μ μ΄λ¬ν μ μ΄λ₯Ό ν μ μμ΅λλ€.
SDLμ΄ μ΄κΈ°νλλ©΄, μ΄λ₯Ό μ¬μ©ν΄ μ°½μ μμ±ν κ²μ
λλ€. μ°½μ μ΄νμ μ¬μ©ν μ μλλ‘ _window
λ©€λ²μ λ΄κΉλλ€.
SDLμ΄ C λΌμ΄λΈλ¬λ¦¬μ΄κΈ° λλ¬Έμ, μμ±μμ νκ΄΄μλ₯Ό μ§μνμ§ μμ΅λλ€. λ°λΌμ μλμ μΌλ‘ νκ΄΄ν΄μ£Όμ΄μΌ ν©λλ€.
μ°½μ΄ λ§λ€μ΄μ§λ©΄ νκ΄΄λ μνν΄μΌ ν©λλ€.
void VulkanEngine::cleanup()
{
if (_isInitialized) {
SDL_DestroyWindow(_window);
}
// clear engine pointer
loadedEngine = nullptr;
}
void VulkanEngine::draw()
{
// nothing yet
}
SDL_CreateWindow
μμ νλ κ²κ³Ό μ μ¬νκ², SDL_DestroyWindow
λ μνν νμκ° μμ΅λλ€. μ΄λ νλ‘κ·Έλ¨μ μ°½μ μ κ±°ν©λλ€. μ΄μ μμ§μ΄ μμ ν μ 리λμμΌλ―λ‘, μ΄ μ§μ μμ μμ§μ κ°λ¦¬ν€λ μ±κΈν€ ν¬μΈν°λ μ΄κΈ°νν©λλ€.
μ΄νμ λ λ§μ ν¨μλ₯Ό cleanup
ν¨μμ μΆκ°ν κ²μ
λλ€.
draw
ν¨μκ° μ§κΈμ λΉμ΄μμ§λ§, μ΄νμ λ λλ§ μ½λλ₯Ό μΆκ°ν κ²μ
λλ€.
void VulkanEngine::run()
{
SDL_Event e;
bool bQuit = false;
// main loop
while (!bQuit) {
// Handle events on queue
while (SDL_PollEvent(&e) != 0) {
// close the window when user alt-f4s or clicks the X button
if (e.type == SDL_QUIT)
bQuit = true;
if (e.type == SDL_WINDOWEVENT) {
if (e.window.event == SDL_WINDOWEVENT_MINIMIZED) {
stop_rendering = true;
}
if (e.window.event == SDL_WINDOWEVENT_RESTORED) {
stop_rendering = false;
}
}
}
// do not draw if we are minimized
if (stop_rendering) {
// throttle the speed to avoid the endless spinning
std::this_thread::sleep_for(std::chrono::milliseconds(100));
continue;
}
draw();
}
}
μ ν리μΌμ΄μ
μ λ©μΈ 루νμ
λλ€. while()
μ 무ν λ°λ³΅λ¬Έμ΄ μμ΅λλ€. μ΄λ SDLμ΄ SDL_QUIT
λ₯Ό λ°μμ λμλ§ λ©μΆ₯λλ€.
λ§€ λ°λ³΅λ§λ€ SDL_PollEvent
λ₯Ό μνν©λλ€. μ΄λ SDLμκ² μ§λ νλ μλμ OSκ° μ ν리μΌμ΄μ
μΌλ‘ λ³΄λΈ λͺ¨λ μ΄λ²€νΈλ₯Ό μμ²ν©λλ€. μ¬κΈ°μ ν€λ³΄λ μ
λ ₯, λ§μ°μ€ μ΄λ, μ°½ μμ§μ΄κΈ°, μ΅μν λ±μ νμΈν μ μμ΅λλ€. μ§κΈμ SDL_QUIT
κ³Ό μ°½ μ΅μν/볡ꡬμλ§ μ κ²½μ°λ©΄ λ©λλ€. μ°½μ μ΅μννλ μ΄λ²€νΈλ₯Ό λ°μΌλ©΄, stop_rendering
λΆ κ°μ true
λ‘ μ€μ ν΄ μ΅μν λμμ λ 그리λ κ²μ λ°©μ§ν©λλ€. μ°½μ 볡ꡬνλ©΄ μ΄λ₯Ό λ€μ false
λ‘ μ€μ ν΄ κ·Έλ¦¬κΈ°λ₯Ό κ³μνλλ‘ ν©λλ€.
λ§μ§λ§μΌλ‘, λ©μΈ 루νμ κ° λ°λ³΅λ§λ€ draw()
λ₯Ό νΈμΆνκ±°λ κ·Έλ¦¬κΈ°κ° λΉνμ±νλ κ²½μ°μλ std::this_thread::sleep_for
λ₯Ό νΈμΆν©λλ€. μ΄λ κ² νλ©΄ μ°½μ΄ μ΅μν λμμ λ μ€νλλ κ²μ λ°©μ§ν¨μΌλ‘μ μ±λ₯μ μ μ½ν μ μμ΅λλ€.
μ΄μ SDLμ΄ μ΄λ»κ² μ°½μ λ§λλμ§λ₯Ό μ΄ν΄λ΄€μ΅λλ€. μ¬μ€ κ·Έ μΈμλ ν° λ³νκ° μμ΅λλ€.
μ΄μ SDL μ΄λ²€νΈλ₯Ό μ€νν΄λ³΄λ κ²λ§μ΄ λ¨μμ΅λλ€.
μ°μ΅μΌμ SDL2μ λ¬Έμλ₯Ό μ½μ΄ fmt::print
λ₯Ό μ¬μ©ν΄ ν€λ³΄λ μ΄λ²€νΈλ₯Ό λ‘κ·Έλ‘ μΆλ ₯ν΄λ³΄λ κ²λ μ’μ΅λλ€.
μ΄μ 첫 μ±ν°λ₯Ό μ§νν μ μμ΅λλ€. λ λλ§ λ£¨νλ₯Ό ꡬνν΄λ³΄κ² μ΅λλ€.
Next: Initializing Vulkan