m_context->ResolveSubresource(m_tempTexture.Get(), 0,
backBuffer.Get(), 0,
DXGI_FORMAT_R8G8B8A8_UNORM);
D3D11Utils::WriteToFile(m_device, m_context, m_tempTexture,
"captured.png");
context->ResolveSubResource
GPU내부에서 텍스쳐를 복사하는 함수이다. 그리고 captured.png 파일을 만들기 위해 복사한 m_tempTexture을
이용해서 WriteToFile함수를 실행한다. 백버퍼를 바로 넣는 게 아니라 ResolveSubResource로 복사하는 이유는
첫번째로 멀티 샘플링 요소가 포함되어 있기 때문에 Texture2D형식으로 바꾸기 위함이고,
두번째로 GPU의 최적화 때문에 텍스쳐의 용도를 명확히 하기 위함이다.
D3D11_TEXTURE2D_DESC desc;
textureToWrite->GetDesc(&desc);
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.BindFlags = 0;
desc.MiscFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; // CPU에서 읽기 가능
desc.Usage = D3D11_USAGE_STAGING; // GPU에서 CPU로 보낼 데이터를 임시 보관
ComPtr<ID3D11Texture2D> stagingTexture;
if (FAILED(device->CreateTexture2D(&desc, nullptr,
stagingTexture.GetAddressOf()))) {
cout << "Failed()" << endl;
}
// 참고: 전체 복사할 때
// context->CopyResource(stagingTexture.Get(), pTemp.Get());
// 일부만 복사할 때 사용
D3D11_BOX box;
box.left = 0;
box.right = desc.Width;
box.top = 0;
box.bottom = desc.Height;
box.front = 0;
box.back = 1;
context->CopySubresourceRegion(stagingTexture.Get(), 0, 0, 0, 0,
textureToWrite.Get(), 0, &box);
WriteToFile은 맨 밑줄의 textureToWrite를 매개변수로 받고 있는데 여기 복사한 m_tempTexture을 넣는다.
함수의 처음에 StagingTexture을 만들고, 이 텍스쳐는 CPU에서 읽기 가능하고 GPU에서 CPU로 보낼 데이터를 보관하는 용이라고 Desc에서 설정한다. 그리고 m_tempTexture의 일부를 CopySubResourceRegion으로 복사한다.
이렇게 하면 텍스쳐가 GPU에서 CPU로 보낼 데이터를 보관하는 용도라고 명확히 할 수 있다.
// R8G8B8A8 이라고 가정
std::vector<uint8_t> pixels(desc.Width * desc.Height * 4);
D3D11_MAPPED_SUBRESOURCE ms;
context->Map(stagingTexture.Get(), NULL, D3D11_MAP_READ, NULL,
&ms); // D3D11_MAP_READ 주의
// 텍스춰가 작을 경우에는
// ms.RowPitch가 width * sizeof(uint8_t) * 4보다 클 수도 있어서
// for문으로 가로줄 하나씩 복사
uint8_t *pData = (uint8_t *)ms.pData;
for (unsigned int h = 0; h < desc.Height; h++) {
memcpy(&pixels[h * desc.Width * 4], &pData[h * ms.RowPitch],
desc.Width * sizeof(uint8_t) * 4);
}
context->Unmap(stagingTexture.Get(), NULL);
그리고 GPU(pData)에서 CPU(pixels)로 복사를 한다. ms.RowPitch는 한 행당 너비(바이트)이고
for문으로 루프를 돌며 가로줄 하나씩 데이터를 복사하고 있다.
------- 지금까지 GPU에서 CPU로 데이터를 복사하는 것에 대해 알아봤는데 이것을 활용해 Picking을 해보자.
ID3D11RenderTargetView *targets[] = {m_renderTargetView.Get(),
m_indexRenderTargetView.Get()};
m_context->OMSetRenderTargets(2, targets, m_depthStencilView.Get());
이번에는 렌더타겟을 두개 이용해서 Picking을 할 것이다. 첫번째 렌더타겟은 기본적으로 쉐이딩 되어 있는 것이고,
두번째 렌더타겟은 구는 빨간색, 큐브는 초록색으로 되어있는 렌더타겟이다.
struct PixelShaderOutput
{
float4 pixelColor : SV_Target0;
float4 indexColor : SV_Target1;
};
Pixel Shader에서 Output 구조체를 이렇게 정하면 첫번째 렌더타겟의 Output을 pixelColor에, 두번째 렌더타겟의
Output을 indexColor에 넣어주면 된다.
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.Usage = D3D11_USAGE_STAGING;
desc.Width = 1;
desc.Height = 1;
if (FAILED(m_device->CreateTexture2D(
&desc, nullptr, m_indexStagingTexture.GetAddressOf()))) {
cout << "Failed()" << endl;
}
Picking할 픽셀을 1x1 텍스쳐로 만든다. GPU에서 CPU로 보내는 Staging 형식이다.
그리고 Picking에 사용할 indexColor을 PS로 보내는 BasicPixelConstantData에 추가한다.
m_context->ResolveSubresource(m_indexTempTexture.Get(), 0,
m_indexTexture.Get(), 0,
DXGI_FORMAT_R8G8B8A8_UNORM);
// 일부만 복사할 때 사용
D3D11_BOX box;
box.left = m_cursorX;
box.right = m_cursorX + 1;
box.top = m_cursorY;
box.bottom = m_cursorY + 1;
box.front = 0;
box.back = 1;
m_context->CopySubresourceRegion(m_indexStagingTexture.Get(), 0, 0, 0, 0,
m_indexTempTexture.Get(), 0, &box);
아까 백버퍼와 같은 원리로 indexRenderTarget에서 사용되는 indexTexture는 멀티샘플링 요소가 포함되어 있으므로
indexTempTexture의 형식(Texture2D)으로 ResolveSubresource를 통해 변환한다. 그리고 indexTempTexture에서 커서가 있는 위치만 1x1 텍스쳐로 잘라내 indexStagingTexture에 복사한다.
D3D11_MAPPED_SUBRESOURCE ms;
m_context->Map(m_indexStagingTexture.Get(), NULL, D3D11_MAP_READ, NULL,
&ms); // D3D11_MAP_READ 주의
memcpy(m_pickColor, ms.pData, sizeof(uint8_t) * 4);
m_context->Unmap(m_indexStagingTexture.Get(), NULL);
GPU의 indexStagingTexture을 CPU의 m_pickColor로 복사한다.
m_pickColor는 uint8_t[4] 형식이다.
이제 구와 큐브를 초기화 할때 PixelConstantBuffer.indexColor에서 원하는 색을 지정해주고 렌더링할 색을 결정하는
Update함수에서 pickColor[0] == 255 (pickColor가 빨간색)이라면 PixelConstantBuffer.material.diffuse를 빨간색으로
바꿔서 마우스가 구에 닿으면 빨간색으로 바뀌게 표현할 수 있다.
'그래픽스' 카테고리의 다른 글
| [그래픽스] 쿼터니언(실습) (0) | 2023.07.19 |
|---|---|
| [그래픽스] 쿼터니언(이론) (0) | 2023.07.19 |
| [그래픽스] 후처리 - 이미지 필터 (0) | 2023.07.19 |
| [그래픽스] Texturing (0) | 2023.07.18 |
| [그래픽스] 투영 변환에서 z값을 나누는 시점 (0) | 2023.07.18 |