Object ID Picking
- Object Picking을 하기위해선 화면상의 현재 Mouse Position에 위치하는 Face를 모두 검사하는 방식을 사용했었는데, 생각해보니 굳이 CPU 측에서 모든 Object의 Face를 검색하는 것보단 간단한 Object ID를 화면상에 그리는 방식이 빠를것이라 생각이 들었다. Staging Buffer를 활용하면 해당 영역의 GPU Resource Data를 Copy 할 수 있다는 것을 알게되어 활용해보기로 하였다.
Picking 방식
- Object 생성시 부여되는 고유 Number를 활용하여 Hash Color를 생성
- Picking Event 실행시 화면상에 모든 Object Hash Color를 Draw 실행
- Staging Buffer를 통해 해당 Mouse Position에 위치한 1x1 Pixel의 Hash Color를 추출
- 추출한 Hash Color에 해당하는 Object 검색 및 선택
// Picking 전용 Texture 2D
// 해당 Texture는 데이터 입력은 Shader에서 하되, 해당 값을 CPU에서 읽을수 있어야 하므로
// Usage Option을 D3D11_USAGE_STAGING으로 설정..
D3D11_TEXTURE2D_DESC texCopyDesc;
ZeroMemory(&texCopyDesc, sizeof(texCopyDesc));
texCopyDesc.Width = 1;
texCopyDesc.Height = 1;
texCopyDesc.MipLevels = 1;
texCopyDesc.ArraySize = 1;
texCopyDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texCopyDesc.SampleDesc.Count = 1;
texCopyDesc.SampleDesc.Quality = 0;
texCopyDesc.Usage = D3D11_USAGE_STAGING;
texCopyDesc.BindFlags = 0;
texCopyDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
texCopyDesc.MiscFlags = 0;
D3D11_TEXTURE2D_DESC texDesc;
ZeroMemory(&texDesc, sizeof(texDesc));
texDesc.Width = width;
texDesc.Height = height;
texDesc.MipLevels = 1;
texDesc.ArraySize = 1;
texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D11_USAGE_DEFAULT;
texDesc.BindFlags = D3D11_BIND_RENDER_TARGET;
texDesc.CPUAccessFlags = 0;
texDesc.MiscFlags = 0;
/// RenderTargetView 2D
D3D11_RENDER_TARGET_VIEW_DESC rtvDesc;
ZeroMemory(&rtvDesc, sizeof(rtvDesc));
rtvDesc.Format = texDesc.Format;
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
rtvDesc.Texture2D.MipSlice = 0;
// RenderTarget 생성..
g_Factory->CreateRenderTexture<RT_ID_Copy>(&texCopyDesc, nullptr, nullptr, nullptr, nullptr);
g_Factory->CreateRenderTexture<RT_ID>(&texDesc, nullptr, &rtvDesc, nullptr, nullptr);
- Object ID를 그릴 RenderTarget 생성 및 Mouse Position Pixel을 가져오기 위한 1x1 Staging Buffer 생성
UINT PickingPass::FindPick(int x, int y)
{
m_PickPointBox.left = x,
m_PickPointBox.right = x + 1;
m_PickPointBox.top = y,
m_PickPointBox.bottom = y + 1;
m_PickPointBox.front = 0;
m_PickPointBox.back = 1;
g_Context->OMSetRenderTargets(0, nullptr, nullptr);
g_Context->CopySubresourceRegion(m_ID_CopyTex2D, 0, 0, 0, 0, m_ID_Tex2D, 0, &m_PickPointBox);
// 현재 선택한 Object ID..
UINT pickID = 0;
// Mapping SubResource Data..
D3D11_MAPPED_SUBRESOURCE mappedResource;
ZeroMemory(&mappedResource, sizeof(D3D11_MAPPED_SUBRESOURCE));
// GPU Access Lock Texture Data..
g_Context->Map(m_ID_CopyTex2D, 0, D3D11_MAP_READ, 0, &mappedResource);
// 해당 Pixel Copy가 잘못 되었을 경우..
if (mappedResource.pData == nullptr) return 0;
pickID = ((UINT*)mappedResource.pData)[0];
// GPU Access UnLock Texture Data..
g_Context->Unmap(m_ID_CopyTex2D, 0);
return pickID;
}
- 모든 Object ID를 그린 후 Mouse Position의 Pixel을 Copy 하여 해당 ID 반환하는 과정
적용 화면
'DirectX 11' 카테고리의 다른 글
[DirectX 11] Vertex Texture Fetch Skinning Animation Instancing (0) | 2022.04.21 |
---|---|
[DirectX 11] Hierarchical Z-Buffer Occlusion Culling (0) | 2022.04.04 |
[DirectX 11] Game Engine Render Resource 동기화 방식 및 Resource 관리 방식 (0) | 2022.03.16 |
[DirectX 11] Game Engine & Graphic Engine 분리 및 Render Data 전달 방식 (0) | 2022.03.07 |
[DirectX 11] Hardware Instancing (0) | 2022.03.02 |