///
Search
Duplicate

씬뷰(Scene View)와 게임뷰(Game View) 분리 작업

전체 구조 흐름 요약

1. SceneWindow 클래스 구조 정리

SceneWindow는 에디터 내에서 씬(Scene)을 시각적으로 편집할 수 있는 뷰포트입니다.
EditorCamera를 이용해 별도의 렌더 타겟에 씬을 렌더링하고,
해당 이미지를 ImGui 위에 출력합니다.

멤버 변수 정리

멤버
설명
mEditorCameraObject
씬뷰 전용 카메라가 부착된 GameObject
mEditorCamera
실제 렌더링을 담당하는 EditorCamera 컴포넌트
GuizmoType
현재 활성화된 변환 Gizmo (이동, 회전, 스케일)
ViewportBounds[2]
뷰포트의 좌상단, 우하단 ImGui 위치
ViewportSize
ImGui 내 SceneView의 크기
ViewportFocused / Hovered
현재 마우스 포커스 여부 (입력 판단용)

주요 함수 역할

함수
설명
Initialize()
에디터 카메라 객체 생성, 렌더타겟 초기화
Run()
카메라 업데이트, 씬 렌더링, Gizmo 출력, ImGui 이미지 출력
OnGUI()
SceneView 내 추가적인 UI 편집 요소 (없으면 생략 가능)
SetGuizmoType()
Gizmo 조작 모드 설정

2. GameView ImGui 렌더링 코드 설명

코드 요약:

cpp 복사편집 ImGui::Begin("Game"); ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail(); ViewportSize = Vector2{ viewportPanelSize.x, viewportPanelSize.y }; ya::graphics::Texture* texture = FrameBuffer->GetAttachmentTexture(0); ImGui::Image((ImTextureID)texture->GetSRV().Get(), ImVec2{ ViewportSize.x, ViewportSize.y }); if (ImGui::BeginDragDropTarget()) { if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("PROJECT_ITEM")) { const auto path = static_cast<const wchar_t*>(payload->Data); OpenScene(path); } ImGui::EndDragDropTarget(); } for (auto& iter : EditorWindows) iter.second->Run(); ImGui::End();
C++
복사

핵심 동작 순서 설명

단계
설명
ImGui::Begin("Game")
GameView 창 시작
GetContentRegionAvail()
ImGui 내부에서 사용 가능한 영역 크기 (픽셀) 계산
FrameBuffer->GetAttachmentTexture(0)
게임 카메라가 렌더링한 이미지(Texture) 가져오기
ImGui::Image(...)
해당 Texture를 GameView에 출력
ImGui::BeginDragDropTarget()
드래그 앤 드롭 지원 (예: 프로젝트 창에서 씬 드래그)
EditorWindows 루프
에디터 내 다른 창들(Inspector, Hierarchy 등)도 실행
ImGui::End()
GameView 창 종료

씬뷰 vs 게임뷰 차이 정리

항목
Scene View
Game View
사용 카메라
EditorCamera (사용자가 조작)
mainCamera (게임 로직 기준)
렌더 타겟
Editor 전용 RenderTarget
공용 FrameBuffer
목적
편집기에서 오브젝트 확인/이동/회전
최종 게임 플레이 화면
입력 우선순위
Hover 여부로 차단/허용
별도로 관리 필요
Gizmo 사용
가능 (ImGuizmo::Manipulate)
일반적으로 없음

핵심 로직

1. 렌더 타겟(RenderTarget) 분리

목적:

게임 뷰와 에디터 뷰의 결과가 겹치지 않게 별도의 출력 버퍼를 사용
각각 다른 뷰포트 크기, 카메라 행렬을 사용하므로 완전한 분리가 필요함

구현 요약

EditorCamera::CreateRenderTarget(width, height)
SceneWindow에서는 EditorCamera의 RenderTarget 사용
GameViewrenderer::FrameBuffer (main camera 기준의 RT) 사용
graphics::RenderTargetSpecification spec; spec.Attachments = { RGBA8, Depth }; mRenderTarget = new RenderTarget(spec);
C++
복사
각 뷰가 자신만의 GPU 출력 버퍼를 가지고 렌더링 → 서로 덮어쓰거나 공유하는 문제 없음

2. 카메라 행렬(View/Projection) 분리

목적:

SceneView는 오브젝트 조작에 최적화된 카메라 (예: 고정된 시야, 자유 회전 등)
GameView는 게임 안에서 실제 사용하는 시점 (캐릭터 따라다니기, 1인칭 등)
EditorCamera
// render the scene Matrix viewMatrix = mEditorCamera->GetViewMatrix(); Matrix projectionMatrix = mEditorCamera->GetProjectionMatrix(); Vector3 cameraPos = mEditorCamera->GetOwner()->GetComponent<ya::Transform>()->GetPosition(); std::vector<ya::GameObject*> opaqueList = {}; std::vector<ya::GameObject*> cutoutList = {}; std::vector<ya::GameObject*> transparentList = {}; // collect randerables(game objects) ya::Scene* scene = ya::SceneManager::GetActiveScene(); ya::renderer::CollectRenderables(scene, opaqueList, cutoutList, transparentList); // soring renderables by distance (between camera and game object) ya::renderer::SortByDistance(opaqueList, cameraPos, true); ya::renderer::SortByDistance(cutoutList, cameraPos, true); ya::renderer::SortByDistance(transparentList, cameraPos, false); //render game objects ya::renderer::RenderRenderables(opaqueList, viewMatrix, projectionMatrix); ya::renderer::RenderRenderables(cutoutList, viewMatrix, projectionMatrix); ya::renderer::RenderRenderables(transparentList, viewMatrix, projectionMatrix);
C++
복사
SceneCamera
void Scene::Render() { for (Camera* camera : mCameras) { if (camera == nullptr) continue; Matrix viewMatrix = camera->GetViewMatrix(); Matrix projectionMatrix = camera->GetProjectionMatrix(); Vector3 cameraPos = camera->GetOwner()->GetComponent<Transform>()->GetPosition(); std::vector<GameObject*> opaqueList = {}; std::vector<GameObject*> cutoutList = {}; std::vector<GameObject*> transparentList = {}; // collect randerables(game objects) renderer::CollectRenderables(this, opaqueList, cutoutList, transparentList); // soring renderables by distance (between camera and game object) renderer::SortByDistance(opaqueList, cameraPos, true); renderer::SortByDistance(cutoutList, cameraPos, true); renderer::SortByDistance(transparentList, cameraPos, false); // render game objects renderer::RenderRenderables(opaqueList, viewMatrix, projectionMatrix); renderer::RenderRenderables(cutoutList, viewMatrix, projectionMatrix); renderer::RenderRenderables(transparentList, viewMatrix, projectionMatrix); } }
C++
복사

3. 렌더 파이프라인 호출

씬 뷰에서 다음과 같은 과정을 독립적으로 실행:
씬뷰(타겟에) 물체를 그리기 전에 새로운 뷰행렬을 적용 시키기 위한 기초 작업
렌더타겟을 세팅해주고, 렌더타겟과 뎁스스텐실을 초기화해준다.
void SceneWindow::Run() { bool Active = (bool)GetState(); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{ 0, 0 }); ImGui::Begin(GetName().c_str(), &Active, GetFlag()); Update(); OnGUI(); // Calculate view, projection, and camera position ya::Transform* cameraTr = mEditorCamera->GetOwner()->GetComponent<ya::Transform>(); cameraTr->LateUpdate(); mEditorCamera->LateUpdate(); // clear the render target view & depth stencil view ya::graphics::RenderTarget* rt = mEditorCamera->GetRenderTarget(); Microsoft::WRL::ComPtr<ID3D11RenderTargetView> rtv = rt->GetAttachmentTexture(0)->GetRTV(); ya::graphics::GetDevice()->ClearRenderTargetView(rtv); Microsoft::WRL::ComPtr<ID3D11DepthStencilView> dsv = rt->GetDepthAttachment()->GetDSV(); ya::graphics::GetDevice()->ClearDepthStencilView(dsv); // set scene view render target & depth stencil view ya::graphics::GetDevice()->BindRenderTargets(1, rtv.GetAddressOf(), dsv.Get()); ....
C++
복사
이 과정을 SceneWindowGameWindow에서 각자 따로 수행합니다.

4. ImGui를 통한 최종 출력

각각의 뷰는 RenderTarget이 갖는 SRV를 ImGui Image()로 출력
ImGui::Image((ImTextureID)editorCameraRT->GetSRV().Get(), viewportSize); .... ImGui::Image((ImTextureID)gameRT->GetSRV().Get(), viewportSize);
C++
복사
→ 결국 GPU 버퍼에 그린 결과를 에디터 UI 내에서 이미지처럼 시각화하는 구조
씬뷰와 게임뷰는 각자 다른 카메라, 다른 렌더 타겟, 다른 뷰 행렬을 갖는 완전히 독립된 렌더 파이프라인이며, 최종 결과는 ImGui에서 각각 다른 뷰포트에 출력된다.