Search
Duplicate

Scene View(씬 뷰)

씬뷰는 주로 게임 엔진이나 그래픽 에디터에서 작업 영역을 제공하며, 사용자는 해당 공간에서 드래그 앤 드롭, 키보드 및 마우스 이벤트, 렌더링된 이미지 확인 등을 수행할 수 있습니다.
씬뷰를 분석하기 이전에 스왑체인에 가지고 있는 최종렌더타겟(프레임버퍼)를 텍스처 리소스로 가져와야 imgui창에서 이미지를 그릴 수 있습니다. 추후 디퍼드렌더링 등등 여러가지 렌더타겟을 활용한것들이 많아질수 있기에 RenderTarget클래스를 설계하였습니다.
렌더 타겟은 프레임 버퍼와 유사한 개념으로, 렌더링 결과를 저장하거나 특정 렌더링 작업을 수행하는 데 사용됩니다.

렌더타겟 클래스

1. eRenderTragetFormat (렌더 타겟 포맷)

cpp 코드 복사 enum class eRenderTragetFormat { None = 0, RGBA8, RED_INTEGER, DEPTH24STENCIL8, SHADER_RESOURCE, Depth = DEPTH24STENCIL8 };
C++
복사
렌더 타겟 텍스처의 포맷을 지정하는 열거형.
주요 항목:
RGBA8: 8비트 RGBA 컬러 데이터 저장.
RED_INTEGER: 정수 데이터 저장을 위한 RED 채널 포맷.
DEPTH24STENCIL8: 깊이 및 스텐실 버퍼 포맷.
SHADER_RESOURCE: 셰이더 리소스로 사용할 수 있는 포맷.
Depth: 기본 깊이 포맷으로 DEPTH24STENCIL8을 사용.

2. RenderTargetTextureSpecification

cpp 코드 복사 struct RenderTargetTextureSpecification { eRenderTragetFormat TextureFormat = eRenderTragetFormat::None; };
C++
복사
렌더 타겟 텍스처의 포맷과 특성을 정의.
TextureFormat:
텍스처의 포맷을 지정.
디폴트 값은 None.

3. RenderTargetAttachmentSpecification

cpp 코드 복사 struct RenderTargetAttachmentSpecification { std::vector<RenderTargetTextureSpecification> Attachments; };
C++
복사
여러 렌더 타겟 텍스처를 관리하는 구조체.
Attachments:
텍스처의 설정을 저장하는 리스트.

4. RenderTargetSpecification

cpp 코드 복사 struct RenderTargetSpecification { UINT Width = 0, Height = 0; RenderTargetAttachmentSpecification Attachments; UINT Samples = 1; bool SwapChainTarget = false; };
C++
복사
렌더 타겟의 전반적인 설정을 관리.
주요 항목:
Width, Height:
렌더 타겟의 크기(픽셀 단위).
Attachments:
텍스처 설정을 포함.
Samples:
멀티샘플링의 개수.
기본값은 1.
SwapChainTarget:
렌더 타겟이 스왑 체인(화면 출력용 버퍼)인지 여부.

5. RenderTarget 클래스

렌더 타겟을 생성하고 관리하는 핵심 클래스.

생성자 및 소멸자

cpp 코드 복사 RenderTarget(const RenderTargetSpecification& spec); virtual ~RenderTarget();
C++
복사
RenderTarget 생성자:
RenderTargetSpecification을 인자로 받아 렌더 타겟을 초기화.
소멸자:
메모리 및 리소스를 해제.

정적 생성 함수

cpp 코드 복사 static RenderTarget* Create(const RenderTargetSpecification& spec);
C++
복사
새로운 렌더 타겟 객체를 생성하고 반환.

렌더 타겟 초기화

cpp 코드 복사 void Invalidate();
C++
복사
렌더 타겟을 초기화하거나 다시 생성.
텍스처 및 버퍼를 생성하고 설정.

렌더 타겟 바인딩 및 언바인딩

cpp 코드 복사 void Bind(); void Unbind();
C++
복사
Bind:
렌더 타겟을 활성화하여 현재 렌더링 대상 설정.
Unbind:
렌더 타겟을 비활성화.

크기 조정

cpp 코드 복사 void Resize(UINT width, UINT height);
C++
복사
렌더 타겟 크기를 동적으로 변경.

픽셀 읽기

cpp 코드 복사 int ReadPixel(uint32_t attachmentIndex, int x, int y);
C++
복사
특정 텍스처 첨부물(attachment)의 지정된 픽셀 데이터를 읽어 반환.
주로 디버깅 및 선택 기능(예: 픽킹)에 사용.

첨부물 데이터 초기화

cpp 코드 복사 void ClearAttachment(UINT index, const void* value);
C++
복사
특정 텍스처 첨부물의 데이터를 초기화.
예: 깊이 버퍼를 초기화하거나 특정 색으로 채우기.

렌더타겟 텍스처 가져오기

cpp 코드 복사 Texture* GetAttachmentTexture(UINT index);
C++
복사
특정 렌더타겟 텍스처를 반환.
*index*가 유효 범위를 벗어나면 프로그램이 중단되도록 **assert*로 확인.

사양 반환

cpp 코드 복사 RenderTargetSpecification& GetSpecification();
C++
복사
렌더 타겟의 설정을 반환.

프라이빗 멤버 변수

cpp 코드 복사 RenderTargetSpecification mSpecification; std::vector<RenderTargetTextureSpecification> mSpecifications; RenderTargetTextureSpecification mDepthAttachmentSpecification; std::vector<Texture*> mAttachments; Texture* mDepthAttachment;
C++
복사
mSpecification:
렌더 타겟 전체 사양.
mSpecifications:
텍스처 사양 리스트.
mDepthAttachmentSpecification:
깊이 텍스처 사양.
mAttachments:
렌더 타겟에 첨부된 텍스처 객체 리스트.
mDepthAttachment:
깊이 버퍼에 사용되는 텍스처.

주요 특징 및 활용

1.
렌더링 결과 저장:
프레임 버퍼처럼 동작하며 렌더링 데이터를 저장.
여러 첨부물을 통해 복합 데이터를 저장 가능(예: 색상, 깊이, 스텐실).
2.
동적 크기 조정:
창 크기가 변경되면 렌더 타겟 크기도 동적으로 조정 가능.
3.
데이터 읽기:
특정 픽셀 데이터를 읽어 UI 상호작용(예: 객체 선택)을 구현.
4.
다양한 포맷 지원:
RGBA, 정수 데이터, 깊이/스텐실 등 다양한 포맷 설정 가능.
이 클래스는 그래픽스 파이프라인에서 핵심 역할을 하며, 복잡한 렌더링 효과(예: 셰도우 맵핑, 포스트 프로세싱, 디퍼드 렌더링 등)를 구현할 때 필수적입니다.

윈도우 크기 변경시 예외 처리

윈도우 크기가 변경될 때 그래픽 디바이스 및 렌더링 관련 리소스를 조정하는 함수와 이를 처리하는 메시지 핸들러의 일부입니다.

코드 분석

Application::ReszieGraphicDevice()

cpp 코드 복사 void Application::ReszieGraphicDevice() { if (mGraphicDevice == nullptr) return; RECT winRect; ::GetClientRect(mHwnd, &winRect); D3D11_VIEWPORT viewport = {}; viewport.TopLeftX = 0.0f; viewport.TopLeftY = 0.0f; viewport.Width = static_cast<float>(winRect.right - winRect.left); viewport.Height = static_cast<float>(winRect.bottom - winRect.top); viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; mWidth = viewport.Width; mHeight = viewport.Height; mGraphicDevice->Resize(viewport); renderer::FrameBuffer->Resize(mWidth, mHeight ); }
C++
복사
1.
if (mGraphicDevice == nullptr):
그래픽 디바이스가 생성되지 않은 경우 함수를 종료.
안전성을 위한 체크.
2.
윈도우 크기 가져오기 (GetClientRect):
cpp 코드 복사 RECT winRect; ::GetClientRect(mHwnd, &winRect);
C++
복사
클라이언트 영역의 크기를 가져옵니다.
*winRect.right - winRect.left*와 **winRect.bottom - winRect.top*으로 폭과 높이를 계산.
3.
뷰포트 초기화 (D3D11_VIEWPORT):
cpp 코드 복사 D3D11_VIEWPORT viewport = {}; viewport.TopLeftX = 0.0f; viewport.TopLeftY = 0.0f; viewport.Width = static_cast<float>(winRect.right - winRect.left); viewport.Height = static_cast<float>(winRect.bottom - winRect.top); viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f;
C++
복사
새로운 화면 크기에 맞는 뷰포트를 생성.
DirectX는 뷰포트를 통해 렌더링할 영역을 정의하므로, 크기 조정 시 이를 갱신해야 합니다.
4.
멤버 변수 갱신:
cpp 코드 복사 mWidth = viewport.Width; mHeight = viewport.Height;
C++
복사
애플리케이션의 내부 변수(mWidth, mHeight)를 갱신하여 다른 렌더링 관련 작업에서도 새로운 크기를 참조할 수 있도록 함.
5.
그래픽 디바이스 리소스 조정:
cpp 코드 복사 mGraphicDevice->Resize(viewport);
C++
복사
mGraphicDevice 객체를 통해 DirectX 리소스를 조정.
이 과정에서 스왑 체인, 렌더 타겟 뷰 등이 새 크기에 맞게 재생성될 가능성이 큼.
6.
프레임 버퍼 크기 조정:
cpp 코드 복사 renderer::FrameBuffer->Resize(mWidth, mHeight);
C++
복사
렌더링 출력용 프레임 버퍼의 크기를 조정.
프레임 버퍼는 오프스크린 렌더링(예: 포스트 프로세싱)에서 사용될 가능성이 높음.

윈도우 메시지 처리 (WM_SIZE)

cpp 코드 복사 case WM_SIZE: { application.ReszieGraphicDevice(); }
C++
복사
윈도우 메시지 WM_SIZE:
윈도우 크기가 변경되면 전달되는 메시지.
클라이언트 영역의 크기 변화에 반응하여 애플리케이션의 그래픽 리소스를 조정.
application.ReszieGraphicDevice():
애플리케이션 객체의 **ReszieGraphicDevice()*를 호출하여 크기 변화에 대응.

작동 흐름

1.
사용자가 창 크기를 변경하면 WM_SIZE 메시지가 전달됩니다.
2.
메시지 핸들러에서 **application.ReszieGraphicDevice()*를 호출합니다.
3.
함수 내부에서:
윈도우 크기를 가져와 뷰포트를 새로 설정.
멤버 변수를 갱신하여 새로운 크기를 참조 가능하게 설정.
그래픽 디바이스 및 프레임 버퍼 크기를 조정.

유의점

1.
스왑 체인 리소스 관리:
스왑 체인(DirectX의 화면 출력용 버퍼) 재생성이 필요한 경우, ResizeBuffers() 같은 메서드를 호출해야 할 수 있음.
2.
성능 고려:
크기 조정이 빈번하게 발생할 경우(예: 사용자가 마우스로 창 크기를 계속 변경하는 경우), 불필요한 리소스 재생성이 성능 저하를 유발할 수 있음.
이를 방지하려면 타이머를 활용하여 크기 조정을 지연 처리하거나, 변경 완료 이벤트를 확인한 뒤 처리하는 방식이 좋습니다.
3.
비율 유지:
필요할 경우 창의 폭/높이를 특정 비율로 고정하여 UI 왜곡을 방지해야 함.
4.
다른 렌더링 리소스 동기화:
프레임 버퍼 외에도, 셰이더, 렌더 타겟, 깊이 스텐실 버퍼 등 추가 리소스도 재생성해야 할 수 있음.

결론

이 코드 구조는 DirectX11 기반 애플리케이션에서 창 크기 변경에 유연하게 대응할 수 있도록 설계되었습니다. 크기 조정 후에도 렌더링 과정이 정확히 동작하며, 추가적인 리소스 생성 및 동기화를 쉽게 확장할 수 있습니다.

씬뷰

1. 씬뷰 스타일 설정

cpp 코드 복사 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{ 0, 0 }); ImGui::Begin("Scene");
C++
복사
PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{ 0, 0 }):
씬뷰 내부의 패딩(여백)을 제거하여 콘텐츠가 창에 딱 맞도록 설정.
예: 이미지 또는 기타 UI 요소가 창의 경계에 정확히 위치하도록 함.
ImGui::Begin("Scene"):
"Scene"이라는 이름의 새 창을 생성. 이 창은 씬뷰를 나타냄.

2. 씬뷰 좌표 및 크기 계산

cpp 코드 복사 auto viewportMinRegion = ImGui::GetWindowContentRegionMin(); auto viewportMaxRegion = ImGui::GetWindowContentRegionMax(); auto viewportOffset = ImGui::GetWindowPos(); const int letTop = 0; mViewportBounds[letTop] = { viewportMinRegion.x + viewportOffset.x, viewportMinRegion.y + viewportOffset.y }; const int rightBottom = 1; mViewportBounds[rightBottom] = { viewportMaxRegion.x + viewportOffset.x, viewportMaxRegion.y + viewportOffset.y };
C++
복사

주요 함수:

GetWindowContentRegionMin / GetWindowContentRegionMax:
창 내부의 콘텐츠 영역 좌표를 반환.
viewportMinRegion: 콘텐츠 시작 좌표.
viewportMaxRegion: 콘텐츠 끝 좌표.
GetWindowPos:
현재 창의 화면 상 위치를 반환.

계산 결과:

mViewportBounds:
씬뷰의 화면 상 절대 좌표를 계산하여 저장.
mViewportBounds[0]: 왼쪽 위 좌표.
mViewportBounds[1]: 오른쪽 아래 좌표.

3. 씬뷰 상태 확인

cpp 코드 복사 mViewportFocused = ImGui::IsWindowFocused(); mViewportHovered = ImGui::IsWindowHovered();
C++
복사
IsWindowFocused:
현재 창(Scene View)이 키보드 입력을 받을 수 있는 상태인지 확인.
사용자가 창을 클릭하거나 활성화한 경우 true 반환.
IsWindowHovered:
마우스가 현재 창 위에 있는지 확인.
드래그 또는 클릭 이벤트 처리에 사용.

결과:

*mViewportFocused*와 **mViewportHovered*를 통해 마우스 및 키보드 입력 처리 여부를 결정.

4. 씬뷰 크기 계산

cpp 코드 복사 ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail(); mViewportSize = { viewportPanelSize.x, viewportPanelSize.y };
C++
복사
GetContentRegionAvail:
현재 창 내부에서 사용할 수 있는 공간(너비와 높이)을 반환.
mViewportSize:
씬뷰의 크기를 저장.

5. 이미지 렌더링

cpp 코드 복사 ya::graphics::Texture* texture = mFrameBuffer->GetAttachmentTexture(0); ImGui::Image((ImTextureID)texture->GetSRV().Get(), ImVec2{ mViewportSize.x, mViewportSize.y }, ImVec2{ 0, 0 }, ImVec2{ 1, 1 });
C++
복사
mFrameBuffer:
렌더링된 프레임 데이터를 포함하는 프레임 버퍼 객체.
GetAttachmentTexture(0):
프레임 버퍼의 텍스처를 가져옴. (여기서 0은 첫 번째 텍스처)
ImGui::Image:
씬뷰 영역에 해당 텍스처를 이미지로 출력.
텍스처 크기는 mViewportSize로 설정.
ImVec2{ 0, 0 }에서 ImVec2{ 1, 1 }로 텍스처 좌표를 맵핑.

6. 드래그 앤 드롭 처리

cpp 코드 복사 if (ImGui::BeginDragDropTarget()) { if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("PROJECT_ITEM")) { const wchar_t* path = (const wchar_t*)payload->Data; OpenScene(path); } ImGui::EndDragDropTarget(); }
C++
복사
BeginDragDropTarget:
드래그 앤 드롭을 수신할 수 있는 대상 영역을 설정.
AcceptDragDropPayload:
드래그 앤 드롭 데이터(PROJECT_ITEM)를 수락.
여기서는 드롭된 데이터를 파일 경로로 간주하여 OpenScene(path)를 호출.

7. GUI 종료 및 스타일 복구

cpp 코드 복사 ImGui::End(); ImGui::PopStyleVar();
C++
복사
End:
"Scene" 창을 종료.
PopStyleVar:
PushStyleVar로 변경한 스타일 설정을 복구.

전체 동작 요약

1.
씬뷰 창 생성 및 패딩 제거.
2.
씬뷰 영역의 절대 좌표 및 크기를 계산.
3.
현재 씬뷰가 마우스 및 키보드 입력을 받을 수 있는지 확인.
4.
프레임 버퍼 텍스처를 씬뷰 영역에 렌더링.
5.
드래그 앤 드롭을 통해 파일을 열 수 있는 기능 제공.
6.
GUI 종료 및 스타일 설정 복구.

활용 시나리오

게임 엔진에서 3D 뷰포트 또는 씬 에디터 구현.
드래그 앤 드롭을 통한 프로젝트 파일 열기.
프레임 버퍼를 활용한 실시간 렌더링 출력.