DXR프로젝트에서 실시간 프레임 확인 + 기능 on/off를 손쉽게 하기 위해서 GUI를 도입하고자 하였다.
그렇게 적용하고싶은 GUI오픈소스를 찾다가 Imgui를 알게 되었다.
https://github.com/ocornut/imgui
52.4k의 별개수에서 신뢰감도 좀 왔고
'프로그래머를 위한 가볍고 쉬운 테스트용 UI'를 목표로 만들어진 오픈소스라고 해서
내 DXR프로젝트에 적합하다고 판단해서 적용하고자 하였다.
->디자인은 별로일 수 있어도 간단하게 프로그램을 조작하는 측면에서 아주 좋아보인다.
imgui의 파일들을 프로젝트에 포함하기
imgui는 별도의 라이브러리를 프로젝트에 포함하지 않고 소스코드 전체를 프로젝트에 넣어서 구동하는 오픈소스이다.
imgui 초기화하기
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
ImGui_ImplWin32_Init(m_hWnd);
->win32 초기화 호출
ImGui_ImplDX12_Init(
m_dxrDevice.Get(),
3,
DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_UNORM,
m_renderingResources.GetImguiDescriptorHeap().GetDescriptorHeap().Get(),
m_renderingResources.GetImguiDescriptorHeap().GetDescriptorHeap()->GetCPUDescriptorHandleForHeapStart(),
m_renderingResources.GetImguiDescriptorHeap().GetDescriptorHeap()->GetGPUDescriptorHandleForHeapStart()
);
->DX12 초기화 호출
위 과정을 통해서 imgui backend가 초기화 된다. DX12버전에서는 imgui backend에서 사용될 별도의 Shader Resource View Descriptor Heap을 만들어주기만 하면 별도의 초기화 작업은 없다.
while(true)
{//매 프레임 호출
...
ImGui_ImplDX12_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
ImGui::ShowDemoWindow();
ImGui::Render();
m_renderer->Render();
}
//DXR렌더링 코드
//...
{//imgui render(m_renderer->Render()함수 내부에서 호출)
pCommandList->SetDescriptorHeaps(1,m_renderingResources.GetImguiDescriptorHeap().GetDescriptorHeap().GetAddressOf());
D3D12_CPU_DESCRIPTOR_HANDLE rtvCPUHandle = m_renderingResources.GetRTVDescriptorHeap().GetRTVCPUHandle(m_renderingResources.GetFrameIndex());
pCommandList->OMSetRenderTargets(1u,&rtvCPUHandle,FALSE,nullptr);
ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), pCommandList.Get());
}
//백버퍼 교체
Imgui의 함수들을 매 프레임호출해주며 GUI를 렌더링한다.
이 때, 실질적으로 UI를 백버퍼에 그리는 함수는 ImGui_ImplDX12_RenderDrawData
함수인데,
이 함수에서 GUI렌더링을 위한 별도의 SRVDescriptorHeap을 사용하기 때문에 DescriptorHeap을 설정해주고 Imgui가 그릴 렌더타겟을 OMSetRenderTargets함수로 설정해준다.