서브모듈 정리
d3dx12.h는 2023년경부터 한 파일 구조에서 여러 파일로 분할됐습니다(d3dx12_core.h, d3dx12_barriers.h, d3dx12_root_signature.h 등). 파일을 손으로 복사해 쓰면 버전이 섞이거나 일부가 빠지기 쉽습니다. 게다가 신버전은 최신 d3d12.h를 전제로 작성돼 있어서, Windows SDK 버전과도 어긋날 수 있습니다.
해당 문제를 해결할 방법은 총 두가지입니다.
| 방식 | 내용 | 한계 |
| DirectX-Headers 서브모듈 | d3d12.h와 d3dx12를 같은 버전으로 통일 | 헤더만 최신, 런타임은 OS것(옛날 버전과 호환이 안될 수 있음) |
| Agility SDK | 헤더와 D3D12Core.dll을 앱에 포함 | DLL 배포와 export 심볼 선언이 필요 |
현재 상황에서는 기본 런타임으로 충분하기 때문에 서브모듈로 적용하여 다음과 같이 적용하여 수정했다.
bash.
git submodule add https://github.com/microsoft/DirectX-Headers.git ThirdParty/DirectX-Headers
CMakeLists.
# ThirdParty/CMakeLists.txt
add_subdirectory(DirectX-Headers)
# Engine/CMakeLists.txt
target_link_libraries(Engine PUBLIC DirectX-Headers DirectX-Guids d3d12 dxgi dxguid d3dcompiler imgui)
DxUtils.h 로 통일 후 기존 다른 파일의 <d3d12.h>, "d3dx12.h" 삭제.
// DxUtil.h
#include <directx/d3d12.h> // 서브모듈 것, 반드시 맨 먼저
#include <directx/d3dx12.h>
#include <dxgi1_6.h> // DXGI는 Windows SDK 것
이후 다른 환경에서 .git을 가져올때 재귀적으로 pull.
git pull
git submodule update --init --recursive
카메라
조작방식
| 입력 | 동작 |
| 우클릭 + 마우스 이동 | 시점 회전 |
| 우클릭 + WASD | 플라이 이동 (Shift를 누르면 3배 가속) |
| Alt + 좌클릭 드래그 | 피벗 중심 오비트 |
| 휠 | 줌 (전진 / 후퇴) |
Camera 클래스 (Engine/Scene/Camera)
카메라 상태는 위치와 yaw/pitch 두 각도로만 저장합니다. 행렬은 필요할 때마다 계산합니다.
| 멤버 | 의미 |
| mPos | 월드 위치. |
| mYaw | 좌우 각도. 0이면 +Z를 봄 |
| mPicth | 상하 각도. 음수면 아래를 봄. ±89로 제한 |
| mOrbitDist | 오비트 피벗까지의 거리 |
| mFovY, mAspect, mNear, mFar | 투영 파라미터 |
전방 벡터는 구면좌표로 구합니다(왼손 좌표계 기준).
forward = (cos(pitch) * sin(yaw), sin(pitch), cos(pitch) * cos(yaw))
- View: XMMatrixLookToLH(pos, forward, up). 목표 지점이 아니라 방향을 넘김
- Right: normalize(cross(worldUp, forward)). 왼손 좌표계에서는 upxforward가 right입니다.
- Pitch 제한: ±90을 넘으면 forward가 up과 평행해져서 화면이 뒤짚히므로 89로 제한합니다.
오비트는 피벗을 고정한 채 카메라를 돌린다는 뜻입니다. 총 세 단계로 구현됐습니다.
pivot = pos + forward * dist; // 1. 현재 보고 있는 지점을 피벗으로
Rotate(dYaw, dPitch); // 2. 각도 변경
pos = pivot - forward * dist; // 3. 새 방향 기준으로 위치 재계산
줌을 전방으로 이동하면 mOrbitDist도 같이 줄어듭니다. 피벗을 뚫고 지나가지 않도록 최소 거리(0.2)를 둡니다.
입력 처리: Viewport 위에서만
에디터 카메라에서 가장 중요한 규칙은 다른 패널을 조작할때 카메라가 움직이면 안 된다는 것입니다.
// 시작은 Viewport 위에서만, 유지는 버튼을 누르고 있는 동안
if (hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) flying = true;
if (!ImGui::IsMouseDown(ImGuiMouseButton_Right)) flying = false;
- Camera 인스턴스는 main에 생성합니다. 그 후 ImGui 바인딩을 호출하며 Camera를 업데이트 합니다.
- 시작 조건은 ImGui::IsWindowHovered() 로 Viewport 패널 위에서 클릭했는지 봅니다.
- 유지 조건은 버튼을 누르고 있느지만 봅니다. 드래그하다 커서가 패널 밖으로 나가면 조작이 끊기지 않습니다.
- 이동 속도에는 io.DeltaTime을 곱해서 프레임률과 무관하게 만듭니다.
- 회전은 io.MouseDelta(프레임 간 이동량)에 감도(0.004rad/pixel)를 곱합니다.
- io.ConfigWindowsMoveFromTitleBarOnly = true을 통해 Viewport를 플로팅 창으로 쓸때 Alt+좌클릭 드래그가 창 이동 되는것을 막습니다.
SceneRenderer 변경
Render(cmd, aspect, time)을 Render(cmd, viewProj)로 바꿨습니다.
카메라 행렬을 밖에서 받습니다. 렌더러가 카메라를 소유하지 않고 입력으로 받기 때문에, 나중에 뷰포트가 여러 개가 되어도 같은 렌더러를 재사용할 수 있습니다.
'DirectX12 > 엔진 만들어보기' 카테고리의 다른 글
| cgltf API 정리 (사용한것 기준) (0) | 2026.10.09 |
|---|---|
| 라이팅에서 PBR 머티리얼까지 (0) | 2026.10.06 |
| 그리드, Scene/Entity, Hierarchy·Inspector, 기즈모 (0) | 2026.10.05 |
| Viewport 만들기 (0) | 2026.10.02 |
| 엔진 구상 (0) | 2026.10.01 |
