🎯 game engine/◽ directX12

[DirectX12] 원기둥의 정점 찍기/렌더링 과정 이해하기

핑크코냥 2023. 12. 12. 17:37
728x90

위 내용에 맞춰 버텍스를 만들어보자. 인덱스는 생략함.

float stackheight = height / stackCount; 

// 한 층 위의 더미로 올라 갈 때의 반지를 변화량
float radiusStep = (topRadius - bottomRadius) / stackCount;
uint32 ringCount = stackCount + 1;

for( uint32 i = 0; i < ringCount; ++i )
{
	float y = - 0.5f + i * stackHeight; 
    float r = bottomRadius + i * radiusStep;
    
    float dTheta = 2.0f * XM_PI/sliceCount; 
    
    for(uint32 j = 0; j <=sliceCount; ++j) 
    {
    	Vertex vertex; 
        
        float c = cosf(j*dTheta); 
        float s = sinf(j*dTheta); 
        
        vertex.Position = XMFLOAT3(r*c, y, r*s); 
        vertex.TangentU = XMFLOAT3(-s, 0.0f, c); 
        
        float dr = bottomRadius - topRadius; 
        
        XMFLOAT3 bitangent(dr*c, -height, dr*s); 
        
        XMVECTOR T = XMLoadFloat3(&vertex.TangentU); 
        XMVECTOR B = XMLoadFloat3(&bitangent); 
        XMVECTOR N = XMVertor3Normalize(XMVector3Cross(T,B)); 
    }
}

 

위와 같이 정점을 구하고 인덱스를 찍었다면 배열에 담아 그림을 그려달라고 GPU에게 요청해야한다. DirectX12에서 GPU에게 요청하는 과정을 알아보자. 

이전의 [Prev]CommandList를 CommandQueue(GPU가 실행하도록)에 제출하고 새롭게 그릴 명령들을 [New]CommandList에 담아 CommnadQueue에 제출하는 과정을 정리하고 이해해보자. 아래는 Draw의 과정을 단순하게 그림으로 나타내보았다.  

렌더링 과정

1.ExecuteCommandList를 통해 커맨드 큐에 제출한 다음에 커맨드 리스트를 리셋할 수 있다. 

2. 다시 GPU에 제출할 commandList를 생성하기 전에 리스트리 ID3D12GraphicsCommandList::Reset() 해준다. 

3. commandList에 렌더링을 위한 과정 함수를 실행하여 리스트에 넣는다. 


[ Command List 대표 함수 /* 순서 중요 */ 

A : ID3D12GraphicsCommandList::RSSetViewports( 1, &D3D12_VIEWPORT

B : ID3D12GraphicsCommandList::RSSetScissorRects( 1, & D3D12_RECT )

C : ID3D12GraphicsCommandList::ResourceBarrier (1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
D3D12_RESOURCE_STATE_PRESENT,
D3D12_RESOURCE_STATE_RENDER_TARGET));
리소스의 상태를 렌더링을 할 수 있도록 변경함. (리소스 상태를 장벽을 사용하여 동기화 함.)

* CD3DX12_RESOURCE_BARRIER::Transition
전환 장벽: 서로 다른 사용간에 전환함을 나타냄.
위 예제는 백 버퍼가 렌더링 대상으로 사용됨을 나타냄. 

D : ID3D12GraphicsCommandList::ClearRenderTargetView( ) 
E : ID3D12GraphicsCommandList::ClearDepthStencilView( )
백 버퍼와 뎁스 버퍼를 클리어 함.

F : ID3D12GraphicsCommandList::OMSetRenderTargets( )
어디에 렌더링을 할지 설정함.

G : ID3D12GraphicsCommandList::SetDescriptorHeaps( )

H : ID3D12GraphicsCommandList::SetGraphicsRootSignature( )

I : ID3D12GraphicsCommandList::SetGraphicsRootDescriptorTable( ) 

********* Draw **********

ID3D12GraphicsCommandList::IASetVertexBuffers ( )

ID3D12GraphicsCommandList::IASetIndexBuffer ( )

ID3D12GraphicsCommandList::IASetPrimitiveTopology ( )
정점 자료를 이용하여 기하학적 기본 도형을 형성하는 방법을 설정해준다. 

ID3D12GraphicsCommandList::SetGraphicsRootDescriptorTable ( )

ID3D12GraphicsCommandList::DrawIndexedInstanced ( )

***************************

G:ID3D12GraphicsCommandList::ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PRESENT));
리소스의 상태를 출력할 수 있도록 변경함.


4. commandList에 기록을 종료함.
ID3D12GraphicsCommandList::Close()

5. 커맨드 리스트의 실행을 위해 큐에 제출함.

6. 백 버퍼와 프론트 버퍼를 교체함. [스왑체인 swapchain]

7. 이 펜스 지점까지 커맨드들을 표시하기 위해 펜스 값을 증가함.

8. 새 펜스 지점을 설정하는 인스트럭션을 커맨드 큐에 추가함. GPU가 모든 커맨드들의 처리가 완료되기 전까지 Signal()을 처리하지 않음.

auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
	 ThrowIfFailed(cmdListAlloc->Reset());

    if (mIsWireframe)
    {
        ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque_wireframe"].Get()));
    }
    else
    {
        ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].Get()));
    }
    
    mCommandList->RSSetViewports(1, &mScreenViewport);
    mCommandList->RSSetScissorRects(1, &mScissorRect);
    mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
                                                                           D3D12_RESOURCE_STATE_PRESENT,
                                                                           D3D12_RESOURCE_STATE_RENDER_TARGET));

    mCommandList->ClearRenderTargetView(CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr);
    mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);

    mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());

    ID3D12DescriptorHeap* descriptorHeaps[] = {mCbvHeap.Get()};
    mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);

    mCommandList->SetGraphicsRootSignature(mRootSignature.Get());

    int passCbvIndex = mPassCbvOffset + mCurrFrameResourceIndex;
    auto passCbvHandle = CD3DX12_GPU_DESCRIPTOR_HANDLE(mCbvHeap->GetGPUDescriptorHandleForHeapStart());
    passCbvHandle.Offset(passCbvIndex, mCbvSrvUavDescriptorSize);
    mCommandList->SetGraphicsRootDescriptorTable(1, passCbvHandle);

    DrawRenderItems(mCommandList.Get(), mOpaqueRitems);
    mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
                                                                           D3D12_RESOURCE_STATE_RENDER_TARGET,
                                                                           D3D12_RESOURCE_STATE_PRESENT));

    ThrowIfFailed(mCommandList->Close());
    ID3D12CommandList* cmdLists[] = {mCommandList.Get()};
    mCommandQueue->ExecuteCommandLists(1, cmdLists);
    ThrowIfFailed(mSwapChain->Present(0, 0));
    mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
    mCurrFrameResource->Fence = ++mCurrentFence;
    mCommandQueue->Signal(mFence.Get(), mCurrentFence);

Direct3D의 그리기 연산 제2부 연습문제 3번 적용함.

 

728x90