씬뷰는 주로 게임 엔진이나 그래픽 에디터에서 작업 영역을 제공하며, 사용자는 해당 공간에서 드래그 앤 드롭, 키보드 및 마우스 이벤트, 렌더링된 이미지 확인 등을 수행할 수 있습니다.
씬뷰를 분석하기 이전에 스왑체인에 가지고 있는 최종렌더타겟(프레임버퍼)를 텍스처 리소스로 가져와야 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 뷰포트 또는 씬 에디터 구현.
•
드래그 앤 드롭을 통한 프로젝트 파일 열기.
•
프레임 버퍼를 활용한 실시간 렌더링 출력.