Skip to content

Commit 2bdf8cf

Browse files
CDDingkarnkaul
andauthored
ko-translate (#20)
* ko-translate getting_started * ko-translate initialization.md * ko-translate rendering * ko-translate ImGui * ko-translate shader_objects * ko-translate memory * ko-translate descriptorSets * revise and summary * fix --------- Co-authored-by: Karn Kaul <karnkaul@gmail.com>
1 parent 280677e commit 2bdf8cf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+3694
-1
lines changed

guide/build.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/theme" DESTINATION "${CMAKE_CURRENT_SOURC
2525

2626
BuildBook("en" "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/book")
2727
BuildBook("zh-TW" "${CMAKE_CURRENT_SOURCE_DIR}/translations/zh-TW" "${CMAKE_CURRENT_SOURCE_DIR}/book/zh-TW")
28+
BuildBook("ko-KR" "${CMAKE_CURRENT_SOURCE_DIR}/translations/ko-KR" "${CMAKE_CURRENT_SOURCE_DIR}/book/ko-KR")

guide/theme/index.hbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@
144144
<ul id="lang-list" class="theme-popup" aria-label="Languages" role="menu">
145145
<li role="none"><button role="menuitem" class="theme" data-lang="en">English</button></li>
146146
<li role="none"><button role="menuitem" class="theme" data-lang="zh-TW">中文</button></li>
147+
<li role="none"><button role="menuitem" class="theme" data-lang="ko-KR">한글</button></li>
147148
</ul>
148149
{{#if search_enabled}}
149150
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">

guide/theme/lang_toggle.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
document.addEventListener('click', function (e) {
3131
if (e.target && e.target.matches('button[data-lang]')) {
3232
const chosenLang = e.target.getAttribute('data-lang');
33-
const supportedLangs = ['en', 'zh-TW']; // Add translated languages here
33+
const supportedLangs = ['en', 'zh-TW', 'ko-KR']; // Add translated languages here
3434

3535
let currentPath = window.location.pathname;
3636

guide/translations/ko-KR/book.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[book]
2+
authors = ["Karnage", "DDing"]
3+
language = "ko-KR"
4+
src = "src"
5+
title = "Learn Vulkan"
6+
7+
[output.html]
8+
theme = "../theme"
9+
additional-js = ["../theme/lang_toggle.js"]
10+
additional-css = ["../theme/lang_toggle.css"]
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# 소개
2+
3+
Vulkan은 매우 명시적이고 어려운 API로 알려져 있습니다. 하지만 버전이 거듭될수록 새로운 기능이 추가되고 기존 확장 기능들이 핵심 API에 통합되면서, 필수적인 어려움은 점차 줄어들고 있습니다. RAII는 C++의 핵심 개념 중 하나이지만, 대부분의 Vulkan 가이드에서는 이를 제대로 활용하지 않고, 자원을 수동으로 해제하는 방식으로 오히려 명시성을 강조하는 경우가 많습니다.
4+
5+
이러한 격차를 메우기 위해 이 가이드는 다음과 같은 목표를 가지고 있습니다.
6+
7+
- 모던 C++, VulkanHPP, Vulkan 1.3 기능을 적극 활용합니다.
8+
- 성능이 아닌, 단순하고 직관적인 접근에 초점을 맞춥니다.
9+
- 기본적인 렌더링 기능을 갖춘 동적 렌더링 기반을 구축합니다.
10+
11+
다시 한번 말하자면, 이 가이드의 목적은 성능이 아닙니다. 이 가이드는 현대 패러다임과 도구를을 활용해 현재 표준으로 자리잡은 멀티 플랫폼 그래픽스 API를 빠르게 소개하는 데 중점을 둡니다. 성능을 고려하지 않더라도 Vulkan은 OpenGL보다 현대적이고 우수한 설계를 갖추고 있습니다. 예를 들어, Vulkan에는 전역 상태 기계가 없고, 파라미터는 의미있는 멤버로 구성된 구조체를 통해 전달되며, 멀티쓰레딩 역시 상당히 간단하게 구현할 수 있습니다(실제로 OpenGL보다 Vulkan에서 멀티쓰레딩이 더 쉽습니다). 또한, 애플리케이션 코드를 변경하지 않고도 오용을 가밎할 수 있는 강력한 검증 레이어를 활성화할 수 있습니다.
12+
13+
더 깊이 Vulkan에 대해 학습하고 싶다면 [공식 튜토리얼](https://docs.vulkan.org/tutorial/latest/00_Introduction.html)이 권장됩니다. [vkguide](https://vkguide.dev/)[Vulkan Tutorial](https://vulkan-tutorial.com/) 또한 많이 참고되는 자료로, 내용이 매우 자세하게 정리되어 있습니다.
14+
15+
## 대상 독자
16+
17+
이 가이드는 이런 분들께 추천합니다.
18+
19+
- 모던 C++의 원리와 사용법을 이해하시는 분
20+
- 써드파티 라이브러리를 사용해 C++ 프로젝트를 진행해보신 분
21+
- 그래픽스에 어느 정도 익숙하신 분
22+
- OpenGL 튜토리얼을 따라 해본 경험이 있다면 이상적입니다
23+
- SFML / SDL과 같은 프레임워크를 사용해본 경험도 도움이 됩니다
24+
- 필요한 모든 정보가 이 가이드 하나에 전부 담겨 있지 않아도 괜찮으신 분
25+
26+
이 책은 다음 내용을 다루지 않습니다.
27+
28+
- GPU 기반 렌더링 기법
29+
- 그래픽스 시스템의 근본적인 구조부터 시작하는 실시간 렌더링
30+
- 타일 기반 GPU(예: 모바일 기기나 Android)를 위한 고려 사항
31+
32+
## 소스코드
33+
34+
프로젝트의 소스코드와 본 가이드는 여기에서 확인할 수 있습니다. `section/*` 브랜치는 각 섹션의 끝에서의 코드 상태를 반영하는 것을 목표로 합니다. 버그 수정이나 일부 변경사항은 가능한 한 반영하지만, `main`브랜치의 최신 상태와는 일부 차이가 있을 수 있습니다. 가이드 자체의 소스는 오직 `main` 브랜치에만 최신 상태로 유지되며, 변경사항은 다른 브랜치로 반영되지 않습니다.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Summary
2+
3+
[소개](README.md)
4+
5+
# 기초
6+
7+
- [시작하기](getting_started/README.md)
8+
- [프로젝트 레이아웃](getting_started/project_layout.md)
9+
- [검증 레이어](getting_started/validation_layers.md)
10+
- [class App](getting_started/class_app.md)
11+
- [초기화](initialization/README.md)
12+
- [GLFW Window](initialization/glfw_window.md)
13+
- [Vulkan 인스턴스](initialization/instance.md)
14+
- [Vulkan Surface](initialization/surface.md)
15+
- [Vulkan 물리 디바이스](initialization/gpu.md)
16+
- [Vulkan 디바이스](initialization/device.md)
17+
- [Scoped Waiter](initialization/scoped_waiter.md)
18+
- [스왑체인](initialization/swapchain.md)
19+
20+
# Hello Triangle
21+
22+
- [렌더링](rendering/README.md)
23+
- [스왑체인 루프](rendering/swapchain_loop.md)
24+
- [렌더 싱크](rendering/render_sync.md)
25+
- [스왑체인 업데이트](rendering/swapchain_update.md)
26+
- [동적 렌더링](rendering/dynamic_rendering.md)
27+
- [Dear ImGui](dear_imgui/README.md)
28+
- [class DearImGui](dear_imgui/dear_imgui.md)
29+
- [ImGui 통합](dear_imgui/imgui_integration.md)
30+
- [셰이더 오브젝트](shader_objects/README.md)
31+
- [에셋 위치](shader_objects/locating_assets.md)
32+
- [셰이더 프로그램](shader_objects/shader_program.md)
33+
- [GLSL 에서 SPIR-V](shader_objects/glsl_to_spir_v.md)
34+
- [삼각형 그리기](shader_objects/drawing_triangle.md)
35+
- [그래픽스 파이프라인](shader_objects/pipelines.md)
36+
37+
# 셰이더 자원
38+
39+
- [메모리 할당](memory/README.md)
40+
- [Vulkan Memory Allocator](memory/vma.md)
41+
- [버퍼](memory/buffers.md)
42+
- [정점 버퍼](memory/vertex_buffer.md)
43+
- [Command Block](memory/command_block.md)
44+
- [디바이스 버퍼](memory/device_buffers.md)
45+
- [이미지](memory/images.md)
46+
- [디스크립터 셋](descriptor_sets/README.md)
47+
- [파이프라인 레이아웃](descriptor_sets/pipeline_layout.md)
48+
- [Descriptor Buffer](descriptor_sets/descriptor_buffer.md)
49+
- [텍스쳐](descriptor_sets/texture.md)
50+
- [뷰 행렬](descriptor_sets/view_matrix.md)
51+
- [인스턴스 렌더링](descriptor_sets/instanced_rendering.md)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Dear ImGui
2+
3+
Dear ImGui는 네이티브 CMake를 지원하지 않기 때문에, 소스를 실행 파일에 직접 추가하는 방법도 있지만, 컴파일 경고 등에서 우리 코드와 분리하기 위해 외부 라이브러리 타겟인 `imgui`로 추가할 예정입니다. 이를 위해 `imgui`는 GLFW 및 Vulkan-Headers에 연결되어야 하고, `VK_NO_PROTOTYPES`도 정의되어야 하므로 `ext` 타겟 구조에 약간의 변경이 필요합니다. 이후 `learn-vk-ext``imgui` 및 기타 라이브러리들(현재는 `glm`만 있음)과 연결됩니다. 우리는 동적 렌더링을 지원하는 Dear ImGui v1.91.9 버전을 사용할 예정입니다.
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# class DearImGui
2+
3+
Dear ImGui는 자체적인 초기화 과정과 렌더링 루프를 가지고 있으며, 이를 `class DearImGui`로 캡슐화하겠습니다.
4+
5+
```cpp
6+
struct DearImGuiCreateInfo {
7+
GLFWwindow* window{};
8+
std::uint32_t api_version{};
9+
vk::Instance instance{};
10+
vk::PhysicalDevice physical_device{};
11+
std::uint32_t queue_family{};
12+
vk::Device device{};
13+
vk::Queue queue{};
14+
vk::Format color_format{}; // single color attachment.
15+
vk::SampleCountFlagBits samples{};
16+
};
17+
18+
class DearImGui {
19+
public:
20+
using CreateInfo = DearImGuiCreateInfo;
21+
22+
explicit DearImGui(CreateInfo const& create_info);
23+
24+
void new_frame();
25+
void end_frame();
26+
void render(vk::CommandBuffer command_buffer) const;
27+
28+
private:
29+
enum class State : std::int8_t { Ended, Begun };
30+
31+
struct Deleter {
32+
void operator()(vk::Device device) const;
33+
};
34+
35+
State m_state{};
36+
37+
Scoped<vk::Device, Deleter> m_device{};
38+
};
39+
```
40+
41+
생성자에서는 ImGui 컨텍스트를 생성하고, Vulkan 함수를 불러와 Vulkan을 위한 GLFW 초기화를 진행합니다
42+
43+
```cpp
44+
IMGUI_CHECKVERSION();
45+
ImGui::CreateContext();
46+
47+
static auto const load_vk_func = +[](char const* name, void* user_data) {
48+
return VULKAN_HPP_DEFAULT_DISPATCHER.vkGetInstanceProcAddr(
49+
*static_cast<vk::Instance*>(user_data), name);
50+
};
51+
auto instance = create_info.instance;
52+
ImGui_ImplVulkan_LoadFunctions(create_info.api_version, load_vk_func,
53+
&instance);
54+
55+
if (!ImGui_ImplGlfw_InitForVulkan(create_info.window, true)) {
56+
throw std::runtime_error{"Failed to initialize Dear ImGui"};
57+
}
58+
```
59+
60+
그 후 Vulkan용 Dear ImGui를 초기화합니다.
61+
62+
```cpp
63+
auto init_info = ImGui_ImplVulkan_InitInfo{};
64+
init_info.ApiVersion = create_info.api_version;
65+
init_info.Instance = create_info.instance;
66+
init_info.PhysicalDevice = create_info.physical_device;
67+
init_info.Device = create_info.device;
68+
init_info.QueueFamily = create_info.queue_family;
69+
init_info.Queue = create_info.queue;
70+
init_info.MinImageCount = 2;
71+
init_info.ImageCount = static_cast<std::uint32_t>(resource_buffering_v);
72+
init_info.MSAASamples =
73+
static_cast<VkSampleCountFlagBits>(create_info.samples);
74+
init_info.DescriptorPoolSize = 2;
75+
auto pipline_rendering_ci = vk::PipelineRenderingCreateInfo{};
76+
pipline_rendering_ci.setColorAttachmentCount(1).setColorAttachmentFormats(
77+
create_info.color_format);
78+
init_info.PipelineRenderingCreateInfo = pipline_rendering_ci;
79+
init_info.UseDynamicRendering = true;
80+
if (!ImGui_ImplVulkan_Init(&init_info)) {
81+
throw std::runtime_error{"Failed to initialize Dear ImGui"};
82+
}
83+
ImGui_ImplVulkan_CreateFontsTexture();
84+
```
85+
86+
sRGB 포맷을 사용하고 있지만 Dear ImGui는 색상 공간에 대한 인식이 없기 때문에, 스타일 색상들을 선형 공간으로 변환해주어야 합니다. 이렇게 하면 감마 보정 과정을 통해 의도한 색상이 출력됩니다.
87+
88+
```cpp
89+
ImGui::StyleColorsDark();
90+
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
91+
for (auto& colour : ImGui::GetStyle().Colors) {
92+
auto const linear = glm::convertSRGBToLinear(
93+
glm::vec4{colour.x, colour.y, colour.z, colour.w});
94+
colour = ImVec4{linear.x, linear.y, linear.z, linear.w};
95+
}
96+
ImGui::GetStyle().Colors[ImGuiCol_WindowBg].w = 0.99f; // more opaque
97+
```
98+
99+
마지막으로 삭제자(Deleter)를 생성하고 구현합니다.
100+
101+
```cpp
102+
m_device = Scoped<vk::Device, Deleter>{create_info.device};
103+
104+
// ...
105+
void DearImGui::Deleter::operator()(vk::Device const device) const {
106+
device.waitIdle();
107+
ImGui_ImplVulkan_DestroyFontsTexture();
108+
ImGui_ImplVulkan_Shutdown();
109+
ImGui_ImplGlfw_Shutdown();
110+
ImGui::DestroyContext();
111+
}
112+
```
113+
114+
이 외의 나머지 함수들은 비교적 단순합니다.
115+
116+
```cpp
117+
void DearImGui::new_frame() {
118+
if (m_state == State::Begun) { end_frame(); }
119+
ImGui_ImplGlfw_NewFrame();
120+
ImGui_ImplVulkan_NewFrame();
121+
ImGui::NewFrame();
122+
m_state = State::Begun;
123+
}
124+
125+
void DearImGui::end_frame() {
126+
if (m_state == State::Ended) { return; }
127+
ImGui::Render();
128+
m_state = State::Ended;
129+
}
130+
131+
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
132+
void DearImGui::render(vk::CommandBuffer const command_buffer) const {
133+
auto* data = ImGui::GetDrawData();
134+
if (data == nullptr) { return; }
135+
ImGui_ImplVulkan_RenderDrawData(data, command_buffer);
136+
}
137+
```
23.5 KB
Loading
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# ImGui 통합
2+
3+
`Swapchain`이 이미지 포맷을 외부에 노출하도록 수정하겠습니다.
4+
5+
```cpp
6+
[[nodiscard]] auto get_format() const -> vk::Format {
7+
return m_ci.imageFormat;
8+
}
9+
```
10+
11+
`class App`은 이제 `std::optional<DearImGui>` 멤버를 담을 수 있으며, 이를 생성하는 함수를 추가하고 호출할 수 있습니다.
12+
13+
```cpp
14+
void App::create_imgui() {
15+
auto const imgui_ci = DearImGui::CreateInfo{
16+
.window = m_window.get(),
17+
.api_version = vk_version_v,
18+
.instance = *m_instance,
19+
.physical_device = m_gpu.device,
20+
.queue_family = m_gpu.queue_family,
21+
.device = *m_device,
22+
.queue = m_queue,
23+
.color_format = m_swapchain->get_format(),
24+
.samples = vk::SampleCountFlagBits::e1,
25+
};
26+
m_imgui.emplace(imgui_ci);
27+
}
28+
```
29+
30+
렌더 패스를 리셋한 이후에 새로운 ImGui 프레임을 시작하고, 데모 창을 띄워봅시다.
31+
32+
```cpp
33+
m_device->resetFences(*render_sync.drawn);
34+
m_imgui->new_frame();
35+
36+
// ...
37+
command_buffer.beginRendering(rendering_info);
38+
ImGui::ShowDemoWindow();
39+
// draw stuff here.
40+
command_buffer.endRendering();
41+
```
42+
43+
ImGui는 이 시점에서는 아무것도 그리지 않습니다(실제 그리기 명령은 커맨드 버퍼가 필요합니다). 이 부분은 상위 로직을 구성하기 위한 커스터마이징 지점입니다.
44+
45+
우리는 Dear ImGui를 위한 별도의 렌더 패스를 사용합니다. 이는 코드의 분리를 위한 목적도 있고, 메인 렌더 패스를 나중에 깊이 버퍼를 추가하는 것과 같은 상황에 변경할 수 있도록 하기 위함입니다 `DearImGui`는 하나의 색상 어태치먼트만 사용하는 전용 렌더 패스를 설정한다고 간주합니다.
46+
47+
```cpp
48+
m_imgui->end_frame();
49+
// we don't want to clear the image again, instead load it intact after the
50+
// previous pass.
51+
color_attachment.setLoadOp(vk::AttachmentLoadOp::eLoad);
52+
rendering_info.setColorAttachments(color_attachment)
53+
.setPDepthAttachment(nullptr);
54+
command_buffer.beginRendering(rendering_info);
55+
m_imgui->render(command_buffer);
56+
command_buffer.endRendering();
57+
```
58+
59+
![ImGui Demo](./imgui_demo.png)

0 commit comments

Comments
 (0)