9 minutes
๐ง SDL๊ณผ OpenGL
1. SDL3
SDL์ Simple Direct Media Layer์ ์ฝ์๋ก, ๊ฒ์์ด๋ ๋ฉํฐ๋ฏธ๋์ด ํ๋ก๊ทธ๋จ์ ๋ง๋ค ๋ ํ์ํ ์ด์์ฒด์ ์์กด ๊ธฐ๋ฅ์ ์ถ์ํํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค. SDL์ด ๋์์ฃผ๋ ๋ํ์ ์ธ ์ผ์ ๋ค์๊ณผ ๊ฐ๋ค.
์ฐฝ ์์ฑ
์ด๋ฒคํธ ์ฒ๋ฆฌ
ํค๋ณด๋ / ๋ง์ฐ์ค / ๊ฒ์ํจ๋ ์ ๋ ฅ
์ค๋์ค
ํ์ด๋จธ
OpenGL, Vulkan, Metal ๊ฐ์ ๊ทธ๋ํฝ์ค API์ ์ฐ๊ฒฐํ ์ ์๋ window ์ค๋น
SDL ์์ฒด์๋ ๊ฐ๋จํ ๋ ๋๋ง ๊ธฐ๋ฅ์ด ํฌํจ๋์ด ์๊ธฐ๋ ํ์ง๋ง, SDL์ ์ฃผ๋ ์ญํ ์ ๋ค์๊ณผ ๊ฐ๋ค.
OpenGL์ ์ฌ์ฉํ ์ ์๋ ์ฐฝ ์์ฑ
OpenGL Context ์์ฑ
์ด๋ฒคํธ ๋ฃจํ ์ ๊ณต
๋งค ํ๋ ์ back buffer๋ฅผ front buffer๋ก swap
1.1. SDL3์ ์ฃผ์ ํจ์
SDL_InitSDL์ ํน์ subsystem์ ์ด๊ธฐํํ๋ค. ์ฐฝ๊ณผ OpenGL Context๋ฅผ ๋ง๋ค๋ ค๋ฉด video subsystem์ด ํ์ํ๋ค.
if (!SDL_Init(SDL_INIT_VIDEO)) { SDL_Log("SDL_Init failed: %s", SDL_GetError()); return -1; }SDL3์ ๋ง์ ํจ์๋ค์ ์คํจ ์
false๋nullptr์ ๋ฐํํ๊ณ , ์์ธํ ์๋ฌ ๋ฉ์์ง๋SDL_GetError()๋ก ํ์ธํ๋ค.SDL_GL_SetAttributeOpenGL Context๋ฅผ ๋ง๋ค๊ธฐ ์ ์ ์ํ๋ ์์ฑ์ ์์ฒญํ๋ ํจ์. OpenGL 4.6 Core Profile์ ์์ฒญํ๋ ค๋ฉด ์ด๋ฐ ์์ ์ค์ ์ด ํ์ํ๋ค.
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);OpenGL Context๋ ์์ฑ ์์ ์ ์์ฑ์ด ๊ฒฐ์ ๋๊ธฐ ๋๋ฌธ์ ์ด ํจ์๋ ๋ฐ๋์ ์ฐฝ๊ณผ context๋ฅผ ๋ง๋ค๊ธฐ ์ ์ ํธ์ถํด์ผ ํ๋ค. ํ๋ ์ฃผ์ํ ์ ์ ์ด ํจ์๋ ๊ทธ์ ์์ฒญ์ด๋ผ๋ ์ ์ผ๋ก, ๋๋ผ์ด๋ฒ๋ ํ๋ซํผ์ด ์ ํํ ๊ฐ์ ์์ฑ์ ๋ณด์ฅํ์ง ์์ ์ ์๋ค.
context ์์ฑ ํ
SDL_GL_GetAttribute๋ก ์ค์ ์์ฑ๋ ๊ฐ์ ํ์ธํ ์ ์๋ค.SDL_CreateWindow์ด์์ฒด์ ์ฐฝ์ ๋ง๋๋ ํจ์. OpenGL์ ์ฌ์ฉํ ์ฐฝ์ด๋ผ๋ฉด ๋ฐ๋์
SDL_WINDOW_OPENGLflag๊ฐ ํ์ํ๋ค.SDL_WINDOW_OPENGL์ด ๋น ์ง๋ฉดSDL_GL_CreateContext๊ฐ ์คํจํ ์ ์๋ค.SDL_Window* window = SDL_CreateWindow( "Cookie Engine", 1280, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE ); if (!window) { SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError()); return -1; }SDL_WINDOW_RESIZABLE์ ์ฐฝ ํฌ๊ธฐ ๋ณ๊ฒฝ์ ํ์ฉํ๋ค. ๊ฒ์ ์์ง ์๋ํฐ์์๋ ์ฐฝ ํฌ๊ธฐ ๋ณ๊ฒฝ์ ๋์ํด์ผ ํ๋ฏ๋ก ์ด๋ฐ๋ถํฐ ์ผ๋๋ ํธ์ด ์ข๋ค.SDL_GL_CreateContextSDL window์ ์ฐ๊ฒฐ๋ OpenGL Context๋ฅผ ๋ง๋ ๋ค. OpenGL Context๋ ํ์ฌ OpenGL ํธ์ถ๋ค์ด ์ด๋ค GPU ์ํ์ ๋ฆฌ์์ค ์งํฉ์ ๋ํด ์คํ๋๋๊ฐ๋ฅผ ๋ํ๋ด๋ ์คํ ๋ฌธ๋งฅ์ด๋ค.
SDL_GLContext context = SDL_GL_CreateContext(window); if (!context) { SDL_Log("SDL_GL_CreateContext failed: %s", SDL_GetError()); return -1; }OpenGL ํจ์๋ context ์์ด ์ ๋๋ก ์ฌ์ฉํ ์ ์๋ค. GLAD๋ฅผ ๋ก๋ฉํ๋ ๊ฒ๋ context ์์ฑ ์ดํ์ ํด์ผ ํ๋ค.
SDL_GL_MakeCurrentOpenGL Context๋ ์์ฑ๋ง ํ๋ค๊ณ ๋์ด ์๋๊ณ , ํ์ฌ ์ค๋ ๋์์ ์ด๋ค context๋ฅผ ์ฌ์ฉํ ์ง ์ง์ ํด์ผ ํ๋ค. main ์ค๋ ๋ ํ๋๋ง ์ฌ์ฉํ ๋๋ ๋ด์ฉ์ด ํฌ๊ฒ ๋ณต์กํ์ง ์๋ค. ํ์ง๋ง ๋์ค์ ๋ ๋ ์ค๋ ๋, ๋ฆฌ์์ค ๋ก๋ฉ ์ค๋ ๋, shared context ๊ฐ์ ๊ฐ๋ ์ผ๋ก ๋๋์ด์ง๋ฉด ์ด ํจ์์ ์๋ฏธ๊ฐ ์ค์ํด์ง๋ค.
if (!SDL_GL_MakeCurrent(window, context)) { SDL_Log("SDL_GL_MakeCurrent failed: %s", SDL_GetError()); return -1; }SDL_GL_SetSwapIntervalVSync ์ค์ ์ ์ฌ์ฉํ๋ค. ๋งค๊ฐ ๋ณ์๋ก 1์ ๋๊ฒจ์ฃผ๋ฉด ๋ชจ๋ํฐ์ refresh์ ๋ง์ถ์ด swapํ๋ค๋ ๋ป์ด๋ค.
SDL_GL_SetSwapInterval(1);๋๋ต์ ์ผ๋ก ํ๋ฉด ์ฐข์ด์ง์ ์ค์ด๋ ๋์ FPS๊ฐ ๋ชจ๋ํฐ ์ฃผ์ฌ์จ์ ๋ฌถ์ผ ์ ์๋ค.
SDL_PollEvent์ด๋ฒคํธ ํ์์ ์ด๋ฒคํธ๋ฅผ ํ๋์ฉ ๊บผ๋ธ๋ค. ์ด๋ฒคํธ๋ ์ด์์ฒด์ ๋ SDL์ด ํ๋ก๊ทธ๋จ์ ์ ๋ฌํ๋ ์ ๋ ฅ / ์ํ ๋ณํ ๋ฉ์์ง๋ฅผ ์๋ฏธํ๋ค.
SDL_Event event; while (SDL_PollEvent(&event)) { if (event.type == SDL_EVENT_QUIT) { running = false; } }๊ฒ์ ์์ง์์๋ ์ด ์ด๋ฒคํธ๋ค์ Input System์ผ๋ก ๋ณํํ๊ฑฐ๋, Editor UI๋ก ์ ๋ฌํ๊ฑฐ๋, Viewport Client์ dispatchํ๋ ๊ตฌ์กฐ๋ก ๋ฐ์ ์ํจ๋ค.
SDL_GL_SwapWindowOpenGL์ ๋ณดํต double buffering์ ์ฌ์ฉํ๋ค. ํ๋ฉด์ ๋ณด์ด๋ front buffer์, ๋ค์ ํ๋ ์์ ๊ทธ๋ฆฌ๋ back buffer๊ฐ ๋ฐ๋ก ์๋๋ฐ, ์ฐ๋ฆฌ๋ back buffer์ ๋ ๋๋งํ๊ณ , ํ๋ ์ ๋ง์ง๋ง์ swapํ๋ค.
SDL_GL_SwapWindow(window);์ด ํจ์๋ฅผ ํธ์ถํด์ผ ๋ฐฉ๊ธ OpenGL๋ก ๊ทธ๋ฆฐ ๊ฒฐ๊ณผ๊ฐ ์ค์ ์ฐฝ์ ํ์๋๋ค.
SDL_DestroyWindow,SDL_GL_DestroyContext,SDL_Quitํ๋ก๊ทธ๋จ ์ข ๋ฃ ์์๋ ์์ฑํ ๋ฆฌ์์ค๋ฅผ ์ ๋ฆฌํด์ผ ํ๋ค.
SDL_GL_DestroyContext(context); SDL_DestroyWindow(window); SDL_Quit();์ด ๋ถ๋ถ์ C++ RAII ๊ตฌ์กฐ๋ก ๊ฐ์ธ๋ฉด ๋์ค์ ์๋ํํ ์ ์๋ค.
2. OpenGL
OpenGL์ GPU์๊ฒ ๋ ๋๋ง ์์ ์ ์ง์ํ๋ ๊ทธ๋ํฝ์ค API๋ค. OpenGL ์์ฒด๋ ์์ง๋ ์๋๊ณ , ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์๋๋ค.
OpenGL์ด ํด์ฃผ๋ ์ผ์ ๋ ๋ฎ์ ์์ค์ด๋ค.
GPU buffer ์์ฑ
GPU texture ์์ฑ
shader program ์์ฑ
vertex ๋ฐ์ดํฐ๋ฅผ GPU pipeline์ ์ ๋ ฅ
draw call ์คํ
framebuffer์ ํฝ์ ๊ฒฐ๊ณผ ๊ธฐ๋ก
์ฆ, OpenGL์ ์์ง์ Renderer Backend์ ํด๋นํ๋ค.
2.1. ๊ธฐ๋ณธ ํ๋ฆ
OpenGL์ด ํ ํ๋ ์์ ๊ทธ๋ฆฌ๋ ๊ธฐ๋ณธ ํ๋ฆ์ ๋ค์๊ณผ ๊ฐ๋ค.
1. viewport ์ค์
2. color/depth buffer clear
3. shader program ์ฌ์ฉ
4. VAO bind
5. draw call ํธ์ถ
6. SDL_GL_SwapWindow๋ก ํ๋ฉด ํ์
์ฝ๋๋ก ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ ํํ๊ฐ ๋๋ค
glViewport(0, 0, width, height);
glClearColor(0.1f, 0.15f, 0.25f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(sphereVao);
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, nullptr);
SDL_GL_SwapWindow(window);
2.2. OpenGL ๋ ๋๋ง ํ์ดํ๋ผ์ธ
OpenGL์์ sphere ํ๋๊ฐ ๊ทธ๋ ค์ง๋ ๊ณผ์ ์ ์์ฃผ ๋จ์ํํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
CPU ๋ฉ๋ชจ๋ฆฌ์ ์ ์ ๋ฐฐ์ด
-> VBO๋ก GPU์ ์
๋ก๋
-> EBO๋ก ์ธ๋ฑ์ค ์
๋ก๋
-> VAO์ ์ ์ ํด์ ๋ฐฉ์ ์ ์ฅ
-> vertex shader ์คํ
-> clipping / NDC ๋ณํ
-> rasterization
-> fragment shader ์คํ
-> depth test
-> color buffer์ ํฝ์
๊ธฐ๋ก
CPU๋ sphere๋ฅผ ๊ตฌ์ฑํ๋ ์ ์ ๋ชฉ๋ก๊ณผ ์ผ๊ฐํ ๋ชฉ๋ก์ ๋ง๋ ๋ค
VBO๋ ์ ์ ๋ฐ์ดํฐ๋ฅผ GPU์ ์ ์ฅํ๋ค
EBO๋ ์ด๋ค ์ ์ ๋ค์ ๋ฌถ์ด ์ผ๊ฐํ์ ๋ง๋ค์ง ์ ์ฅํ๋ค
VAO๋ VBO ์์ ๋ฐ์ดํฐ๋ฅผ ์ด๋ป๊ฒ ์ฝ์์ง ์ ์ฅํ๋ค
vertex shader๋ ๊ฐ ์ ์ ์ ์ต์ข ์์น๋ฅผ ๊ณ์ฐํ๋ค
rasterizer๋ ์ผ๊ฐํ์ ํฝ์ ํ๋ณด๋ค๋ก ๋ฐ๊พผ๋ค
fragment shader๋ ๊ฐ ํฝ์ ์ ์์ ๊ณ์ฐํ๋ค
depth test๋ ๋ ๊ฐ๊น์ด ํฝ์ ๋ง ๋จ๊ธด๋ค
color buffer์ ์ต์ข ์์ด ๊ธฐ๋ก๋๋ค
2.3. OpenGL Context
OpenGL Context๋ OpenGL ์ํ์ ๋ฆฌ์์ค๋ฅผ ๋ด๋ ์คํ ๋ฌธ๋งฅ์ด๋ค. OpenGL ํจ์๋ค์ ๋๋ถ๋ถ ์ ์ญ ํจ์์ฒ๋ผ ๋ณด์ธ๋ค.
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ํ์ง๋ง ์ด ํจ์๋ค์ ์ค์ ๋ก๋ ํ์ฌ ์ค๋ ๋์ current๋ก ์ง์ ๋ OpenGL Context์ ๋ํด ๋์ํ๋ค. ๊ทธ๋์ context ์์ฑ๊ณผ current ์ง์ ์ด ์ค์ํ๋ค.
2.4. State Machine
OpenGL์ ์ฒ์ ๋ณผ ๋ ๊ฐ์ฅ ์์ฃผ ํท๊ฐ๋ฆฌ๋ ๋ถ๋ถ์ด bind ๊ธฐ๋ฐ ์ํ ๋ชจ๋ธ์ด๋ค. OpenGL์ state machine์ ์ธ ์ฑ๊ฒฉ์ด ๊ฐํ๋ค. ์ด๋ค ๊ฐ์ฒด๋ฅผ bindํ๋ฉด, ์ดํ ํจ์ ํธ์ถ์ด ๊ทธ bind๋ ๊ฐ์ฒด์ ๋ํด ๋์ํ๋ค.
GLuint vbo = 0;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
์ ์ฝ๋์์ glBufferData๋ ์ธ์๋ก vbo๋ฅผ ์ง์ ๋ฐ๋ ๋์ ํ์ฌ GL_ARRAY_BUFFER์ bind๋ buffer์ ๋ฐ์ดํฐ๋ฅผ ์
๋ก๋ํ๋ค.
OpenGL 4.5 ์ด์์ DSA(Direct State Access)๋ฅผ ์ฐ๋ฉด bind๋ฅผ ์ค์ผ ์ ์๋ค๋ ์ฅ์ ์ด ์๋ค.
2.5. OpenGL Loader and GLAD
C++์์ OpenGL ํจ์๋ฅผ ๋ฐ๋ก ํธ์ถํ ์ ์์ ๊ฒ ๊ฐ์ง๋ง, ์ค์ ๋ก๋ ๋ง์ OpenGL ํจ์๊ฐ ๋ฐํ์์ ๋๋ผ์ด๋ฒ์์ ๋ก๋ฉ๋์ด์ผ ํ๋ค. ํนํ Windows์์๋ OpenGL 1.1 ์ดํ์ ์ถ๊ฐ๋ ํจ์๋ค์ด ๊ธฐ๋ณธ์ ์ผ๋ก ๋ ธ์ถ๋์ง ์๋ ์ญ์ฌ์ ๋ฌธ์ ๊ฐ ์๊ณ , Linux์์๋ ํ์ฅ / ๋ฒ์ ๋ณ ํจ์ ํฌ์ธํฐ ๋ก๋ฉ ๋ฌธ์ ๊ฐ ์๋ค.
์ฌ๋ด์ผ๋ก, ์ด๋ฐ ๊ตฌ์กฐ๊ฐ ๋ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ๋ค. Windows๋ ์์ฃผ ์ค๋์ ์ OpenGL์ ์์คํ API๋ก ๋ฃ์๋ค. ๊ทธ๋ Windows์์ ๊ธฐ๋ณธ ์ ๊ณตํ OpenGL ๋ฒ์ ์ด OpenGL 1.1์ด์๋ค.
๋ฌธ์ ๋ ๊ทธ ์ดํ์ ๋ฐ์ํ๋๋ฐ, OpenGL์ ๊ณ์ ๋ฐ์ ํ์ง๋ง Windows์ ๊ธฐ๋ณธ opengl32.dll์ ํ๋ OpenGL ํจ์๋ค์ ๊ณ์ ์ง์ exportํ๋ ๋ฐฉ์์ผ๋ก ์
๋ฐ์ดํธ๋์ง ์์๋ค.
๋์ Windows์์๋ ํ๋ OpenGL ํจ์๋ค์ GPU vendor๋ค์ ICD(Installable Client Driver)๋ฅผ ์ด์ฉํ์ฌ ์ ๊ณตํ๋ค. ์ฆ ์ค์ ํ๋ OpenGL ํจ์๋ค์ ๊ตฌํ์ Microsoft์ opengl32.dll ์์ ์๋ ๊ฒ์ด ์๋๋ผ NVIDIA / AMD / Intel ๋๋ผ์ด๋ฒ๊ฐ ์ ๊ณตํ๋ค๋ ๊ฒ์ด๋ค.
๊ทธ๋์ ํ๋ OpenGL ํจ์๋ค์ ์ป๊ธฐ ์ํด์๋ ๋ฐํ์์ ํจ์ ์ฃผ์๋ฅผ ๊ฐ์ ธ์์ผ ํ๋ค. Windows์์๋ OpenGL context ์์คํ ์ธ WGL์์ ์ฌ์ฉํ๋ ํจ์๋ฅผ ์ด์ฉํด ๋ค์๊ณผ ๊ฐ์ด ํจ์๋ฅผ ๊ฐ์ ธ์จ๋ค.
wglGetProcAddress("glCreateShader")
GLAD๋ ์ด ์์ ์ ๋์ ํด์ฃผ๋ loader-generator๋ค. GLAD 2๋ฅผ ์ฌ์ฉํ๋ฉด ๋ณดํต ๋ค์ ํ๋ฆ์ด ๋๋ค.
#include <glad/gl.h>
int version = gladLoadGL((GLADloadfunc) SDL_GL_GetProcAddress);
if (version == 0)
{
SDL_Log("Failed to load OpenGL");
return -1;
}
SDL_Log("Loaded OpenGL %d.%d",
GLAD_VERSION_MAJOR(version),
GLAD_VERSION_MINOR(version));
SDL_GL_CreateContext์ SDL_GL_MakeCurrent ์ดํ์ GLAD๋ฅผ ๋ก๋ฉํด์ผ ํ๋ค๋ ์ ์ ์ ์ํ๋ค. ์ ์ฒด์ ์ธ ํธ์ถ ์์๋ ๋ค์๊ณผ ๊ฐ์์ผ ํ๋ค.
SDL_Init
-> SDL_GL_SetAttribute
-> SDL_CreateWindow
-> SDL_GL_CreateContext
-> SDL_GL_MakeCurrent
-> gladLoadGL
-> OpenGL ํจ์ ์ฌ์ฉ ๊ฐ๋ฅ
2.6. OpenGL Profile
OpenGL 4.6์ ์ฌ์ฉํ ๋ Core Profile๊ณผ Compatibility Profile์ ๊ตฌ๋ถํด์ผ ํ๋ค. Core Profile์ ํ๋ OpenGL ๊ธฐ๋ฅ๋ง ์ ๊ณตํ๊ณ , Compatibility Profile์ ์๋ OpenGL ๊ธฐ๋ฅ๊น์ง ํฌํจํ๋ค.
Core Profile์์๋ ๋ฐ๋์ ๋ค์๊ณผ ๊ฐ์ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ๋ค.
VAO
VBO
shader program
vertex attribute
draw call
2.7. ์ฃผ์ ํจ์
glGetStringOpenGL vendor, renderer, version์ ํ์ธํ๋ค.
SDL_Log("OpenGL Vendor: %s", glGetString(GL_VENDOR)); SDL_Log("OpenGL Renderer: %s", glGetString(GL_RENDERER)); SDL_Log("OpenGL Version: %s", glGetString(GL_VERSION));glViewportNDC๋ฅผ window pixel ์์ญ์ผ๋ก ๋ณํํ viewport๋ฅผ ์ค์ ํ๋ค.
glViewport(0, 0, width, height);glClearColor,glClearํ๋ฉด์ ์ง์ด๋ค.
glClearColor๋ฅผ ํตํด ์ด๋ค ์์ผ๋ก clearํ ์ง ์ค์ ํ ์ ์๋ค.glClearColor(0.1f, 0.15f, 0.25f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glEnableOpenGL ๊ธฐ๋ฅ์ ์ผ ๋ค.
glEnable(GL_DEPTH_TEST);glGenVertexArrays,glBindVertexArrayVAO๋ฅผ ๋ง๋ค๊ณ bindํ๋ค.
GLuint vao = 0; glGenVertexArrays(1, &vao); glBindVertexArray(vao);glGenBuffers,glBindBuffer,glBufferDataGPU buffer๋ฅผ ๋ง๋ค๊ณ ๋ฐ์ดํฐ๋ฅผ ์ ๋ก๋ํ๋ค.
GLuint vbo = 0; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);glVertexAttribPointer,glEnableVertexAttribArrayvertex ์์ฒด์ attribute ํด์ ๊ท์น์ ์ค์ ํ๋ค.
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); glEnableVertexAttribArray(0);glCreateShader,glShaderSource,glCompileShadershader object๋ฅผ ๋ง๋ค๊ณ ์ปดํ์ผํ๋ค.
GLuint vs = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vs, 1, &vertexSource, nullptr); glCompileShader(vs);glCreateProgram,glAttachShader,glLinkProgram,glUseProgramshader program์ ๋ง๋ ๋ค
GLuint program = glCreateProgram(); glAttachShader(program, vs); glAttachShader(program, fs); glLinkProgram(program); glUseProgram(program);glDrawElementsํ์ฌ VAO์ shader program์ ๊ธฐ์ค์ผ๋ก index buffer ๊ธฐ๋ฐ draw call์ ์คํํ๋ค. ์ฐธ๊ณ ๋ก index buffer ๋์ vertex buffer ๊ธฐ๋ฐ์ผ๋ก draw call์ ์คํํ ๋๋
glDraw๋ฅผ ์ฌ์ฉํ๋ค.glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, nullptr);glDelete*OpenGL object๋ฅผ ์ญ์ ํ๋ค.
glDeleteProgram(program); glDeleteShader(vs); glDeleteShader(fs); glDeleteBuffers(1, &vbo); glDeleteBuffers(1, &ebo); glDeleteVertexArrays(1, &vao);OpenGL object๋ ๋ฆฌ์์ค์ด๋ฏ๋ก ์๋ช ๊ด๋ฆฌ๊ฐ ํ์ํ๋ค. ๋์ค์๋ C++ RAII ํจํด์ ์ด์ฉํ๋ wrapper๋ฅผ ๋ง๋๋ ๊ฒ์ด ์ข๋ค.
2.8. VAO, VBO, EBO
VBO(Vertex Buffer Object)
์ ์ ๋ฐ์ดํฐ๋ฅผ GPU ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ๋ OpenGL object๋ค.
GLuint vbo = 0; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, vertexDataSize, vertices, GL_STATIC_DRAW);์ฌ๊ธฐ์
GL_STATIC_DRAW๋ ๋ฐ์ดํฐ ์ฌ์ฉ ํจํด์ ๋ํ ํํธ๋ค. static draw๋ ์์ฃผ ๋ฐ๋์ง ์๊ณ ๋ ๋๋ง์ ์ฃผ๋ก ์ฌ์ฉ๋๋ ๋ฐ์ดํฐ๋ผ๋ ๋ป์ด๋ค.EBO(Element Buffer Object)
Index Buffer๋ผ๊ณ ๋ ๋ถ๋ฅธ๋ค.
GL_ELEMENT_ARRAY_BUFFER์ bind๋ buffer๊ฐglDrawElements์์ ์ฌ์ฉ๋๋ค.GLuint ebo = 0; glGenBuffers(1, &ebo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexDataSize, indices, GL_STATIC_DRAW);VAO(Vertex Array Object)
์ ์ ๋ฐ์ดํฐ๋ฅผ ์ด๋ป๊ฒ ํด์ํ ์ง๋ฅผ ์ ์ฅํ๋ค.
glGenVertexArrays(1, &vao); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); glVertexAttribPointer( 0, // shader layout location 3, // vec3 GL_FLOAT, // float GL_FALSE, // normalized ์๋ sizeof(Vertex), // stride (void*) 0 // offset ); glEnableVertexAttribArray(0);์ด๋ค VBO๋ฅผ ์ฌ์ฉํ ์ง
position attribute๊ฐ ๋ช ๋ฒ์งธ location์ธ์ง
position์ด float ๋ช ๊ฐ๋ก ๊ตฌ์ฑ๋๋์ง
vertex ํ๋์ stride๊ฐ ๋ช byte์ธ์ง
position์ด vertex ๊ตฌ์กฐ์ฒด ์์์ ๋ช byte offset์ ์๋์ง
2.9. WSL Debian์์ OpenGL์ด ์คํ๋๋ ๊ตฌ์กฐ
WSL Debian์์ OpenGL์ ์ฌ์ฉํ๋ฉด, ์ผ๋ฐ์ ์ธ Linux-native ํ๊ฒฝ๊ณผ ์กฐ๊ธ ๋ค๋ฅด๊ฒ ๋์ํ๋ค. Windows 11 + WSLg ํ๊ฒฝ์์๋ ๋๋ต ๋ค์ ๊ตฌ์กฐ๋ก ์คํ๋๋ค.
SDL3 Window
-> OpenGL ํธ์ถ
-> Mesa libGL
-> Mesa Gallium d3d12 backend
-> Direct3D 12
-> Windows GPU Driver
-> GPU
์ฌ๊ธฐ์ Mesa๋ OpenGL์ ๋ํ์ ์ธ ์คํ์์ค ๊ตฌํ์ฒด๋ค.
OpenGL์ ํ์ค API์ด๊ณ , Mesa๋ ๊ทธ ํ์ค์ ์ค์ ๋ก ๊ตฌํํ ๋ฐํ์ / ๋๋ผ์ด๋ฒ ์คํ์ด๋ค. WSL์์๋ Mesa๊ฐ ์ง์ Linux GPU ๋๋ผ์ด๋ฒ๋ฅผ ํ๋ ๊ฒ์ด ์๋๋ผ, D3D12 backend๋ฅผ ํตํด Windows์ Direct3D 12 ๊ฒฝ๋ก๋ก GPU๋ฅผ ์ฌ์ฉํ๋ค. ๊ทธ๋์ glxinfo ๊ฒฐ๊ณผ๊ฐ ์ ์์ด๋ผ๋ฉด ๋ณดํต ๋ค์๊ณผ ๊ฐ์ด ๋์จ๋ค.
OpenGL vendor string: Microsoft Corporation
OpenGL renderer string: D3D12 (Intel(R) Arc(TM) Graphics)
OpenGL core profile version string: 4.6 (Core Profile) Mesa ...
๋ฐ๋๋ก ๊ฒฐ๊ณผ๊ฐ ๋ค์๊ณผ ๊ฐ์ด ๋์ค๋ฉด GPU ๋์ CPU๋ฅผ ์ฌ์ฉํ๋ software rendering ์ํ๋ค.
OpenGL renderer string: llvmpipe (...)
WSL์์ ์ฒ์ ๋ณ๋์ ์ค์ ์ ํด์ฃผ์ง ์์ผ๋ฉด ๊ธฐ๋ณธ ์ํ๊ฐ CPU software rendering์ธ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค. ๋ค์ ํ๊ฒฝ ๋ณ์๋ก D3D12 backend๋ฅผ ๊ฐ์ ํ ์ ์๋ค.
GALLIUM_DRIVER=d3d12
3. CMake ์ฐ๋
C++ ํ๋ก์ ํธ๋ ๋จ์ํ .cpp ํ์ผ๋ง ์ปดํ์ผํ๋ ๊ฒ์ผ๋ก ๋๋์ง ์๊ณ , ๋ค์๊ณผ ๊ฐ์ ๋ค์ํ ์์๋ค์ ํจ๊ป ๋น๋ํด์ผ ํ๋ค.
๋ด ์์ง ์ฝ๋
SDL3
GLAD์์ ์์ฑํ
gl.cImGui
์์คํ OpenGL ๋ผ์ด๋ธ๋ฌ๋ฆฌ
์ด๋ฐ ๊ฒ๋ค์ ๋งค๋ฒ ์ง์ clang++ ๋ช
๋ น์ผ๋ก ๋์ดํ๋ฉด ๊ธ๋ฐฉ ๋ณต์กํด์ง๊ธฐ ๋๋ฌธ์ CMake๋ฅผ ์ฌ์ฉํ๋ค. CMake๋ ์ฝ๊ฒ ๋งํด ์ด ํ๋ก์ ํธ๋ ์ด๋ค ์์ค ํ์ผ๋ก ๊ตฌ์ฑ๋์ด ์๊ณ , ์ด๋ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋งํฌํด์ผ ํ๋ฉฐ, ์ด๋ค include path๊ฐ ํ์ํ์ง๋ฅผ ์ ์ธํ๋ ๋๊ตฌ๋ค.
3.1 Source Tree & Build Tree
Source Tree๋ ๋ด๊ฐ ์์ฑํ ์ฝ๋๊ฐ ์๋ ๋๋ ํ ๋ฆฌ๊ณ , Build Tree๋ CMake๊ฐ ์์ฑํ ๋น๋ ์ฐ์ถ๋ฌผ์ด ๋ค์ด๊ฐ๋ ๋๋ ํ ๋ฆฌ๋ค.
cookie-engine/
build/
external/
src/
CMakeLists.txt
๋ค์๊ณผ ๊ฐ์ด ๋น๋ํ๋ค.
cmake -S . -B build
cmake --build build
-S .๋ ํ์ฌ ๋๋ ํ ๋ฆฌ๋ฅผ ์์ค ๋๋ ํ ๋ฆฌ๋ก ์ฌ์ฉํ๋ค๋ ๋ป์ด๊ณ , -B build๋ build ๋๋ ํ ๋ฆฌ๋ฅผ ๋น๋ ๋๋ ํ ๋ฆฌ๋ก ์ฌ์ฉํ๋ค๋ ๋ป์ด๋ค.
3.2 Target
CMake์์๋ ์คํ ํ์ผ์ด๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ target์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
์คํ ํ์ผ target
add_executable(cookie-engine src/main.cpp )์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ target
add_library(glad STATIC external/glad/src/gl.c )
3.3 Include Directory
C++์์ #include <...>๋ฅผ ํ๋ ค๋ฉด ์ปดํ์ผ๋ฌ๊ฐ ํค๋ ํ์ผ์ ์ด๋์ ์ฐพ์์ง ์์์ผ ํ๋ค. GLAD ํค๋๊ฐ external/glad/include/glad/gl.h์ ์๋ค๋ฉด, include directory๋ external/glad/include๊ฐ ๋๋ค.
target_include_directories(glad PUBLIC
external/glad/include
)
3.4 Link Library
์์ค ํ์ผ์ ์ปดํ์ผํ๋ฉด object file์ด ์๊ธฐ๋๋ฐ, ์ค์ ์คํ ๊ฐ๋ฅํ ํ๋ก๊ทธ๋จ์ ๋น๋ํ๋ ค๋ฉด ์ฌ๋ฌ object file๊ณผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ๋๋ก linkํ๋ ์์ ์ด ํ์ํ๋ค. CMake์์๋ ๋ค์๊ณผ ๊ฐ์ด target๋ผ๋ฆฌ ์ฐ๊ฒฐํ๋ค.
target_link_libraries(cookie-engine PRIVATE
SDL3::SDL3
glad
GL
)
Linux์์๋ OpenGL ์์คํ
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ณดํต GL๋ก ๋งํฌํ๊ณ , Windows native์์๋ ๋ณดํต opengl32๋ฅผ ๋งํฌํ๋ค.