비타Cpp

Direct3D 초기화 예제 본문

DirectX12/튜토리얼

Direct3D 초기화 예제

멍C 2021. 12. 4. 14:45

지금 까지 만들어진 응용 프로그램 프레임워크를 이용하여 간단한 예제프로그램을 만들어 보자. 이 프로그램의 주된 기능은 부모 클래스인 D3DApp이 대부분 담당하기 때문에 이 예제만의 특별한 코드는 거의 없다.

 

#include "../../_Common/d3dApp.h"

class InitDirect3DApp : public D3DApp
{
public:
	InitDirect3DApp(HINSTANCE hInstance);
	~InitDirect3DApp();

	virtual bool Initialize()override;

private:
	virtual void OnResize()override;
	virtual void Update(const GameTimer& gt)override;
	virtual void Draw(const GameTimer& gt)override;
};

int WINAPI WinMain(HINSTANCE hInstance,
	HINSTANCE prevInstance,
	PSTR cmdLine,
	int showCmd)
{
	//디버그 빌드에서는 실행시점 메모리 점검 기능을 켠다.
#if defined(DEBUG) | defined(_DEBUG)
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif

	try
	{
		InitDirect3DApp theApp(hInstance);
		if (!theApp.Initialize())
			return 0;

		return theApp.Run();
	}
	catch (DxException& e)
	{
		MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
		return 0;
	}
}

InitDirect3DApp::InitDirect3DApp(HINSTANCE hInstance)
	:D3DApp(hInstance)
{

}

InitDirect3DApp::~InitDirect3DApp()
{
}

bool InitDirect3DApp::Initialize()
{
	if (!D3DApp::Initialize())
		return false;

	return true;
}

void InitDirect3DApp::OnResize()
{
	D3DApp::OnResize();
}

void InitDirect3DApp::Update(const GameTimer& gt)
{

}

void InitDirect3DApp::Draw(const GameTimer& gt)
{
	//명령 기록에 관련된 메모리의 재활용을 위해 명령 할당자를 재설정 한다.
	//재설정은 GPU가 관련 명령 목록들을 모두 처리한 후에 일어난다.
	ThrowIfFailed(mDirectCmdListAlloc->Reset());

	//명령 목록을 ExecuteCommandList를 통해서 명령 대기열에 추가 했다면 명령 목록을 재설정 할 수 있다.
	//명령 목록을 재설정하면 메모리가 재활용된다.
	ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));

	//리소스 용도에 관련된 상태전이를 Direct3D에 통지한다.
	mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
		D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_RENDER_TARGET));

	//뷰포트와 시저렉트를 설정한다.
	//명령 목록을 재설정할 때마다 이들도 재설정해야 한다.
	mCommandList->RSSetViewports(1, &mScreenViewport);
	mCommandList->RSSetScissorRects(1, &mScissorRect);

	//후면버퍼와 깊이버퍼를 지운다.
	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());

	//자원 용도에 관련된 상태 전이를 Direct3D에 알린다.
	mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
		D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_PRESENT));

	//명령들의 기록을 마친다.
	ThrowIfFailed(mCommandList->Close());

	//명령 실행을 위해 명령 목록을 명령 대기열에 추가한다.
	ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
	mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);

	//후면버퍼와 전면버퍼를 교환한다.
	ThrowIfFailed(mSwapChain->Present(0, 0));
	mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;

	FlushCommandQueue();
}

위의 코드에서 새로운 메서드들을 살펴보자.

 

ClearRenderTargetView 메서드는 지정된 렌더 대상을 지정된 색으로 지우고, ClearDepthStencilView는 지정된 깊이·스텐실 버퍼를 지운다. 이 응용프로그램은 업데이트되는 매 프레임마다 Clear명령으로 지운후 Draw명령을 수행한다.


void ClearRenderTargetView(
  [in] D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetView,
  [in] const FLOAT [4]             ColorRGBA,
  [in] UINT                        NumRects,
  [in] const D3D12_RECT            *pRects
);

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12graphicscommandlist-clearrendertargetview

 

ID3D12GraphicsCommandList::ClearRenderTargetView (d3d12.h) - Win32 apps

Sets all the elements in a render target to one value.

docs.microsoft.com

1. RenderTargetView : 지울 렌더 대상을 서술하는 RTV.

2. ColorRGBA : 렌더 대상을 지우는데 사용할 색상.

3. NumRects : pRects 배열의 원소 개수, pRects가 널 포인터면 0을 지정하면 된다.

4. pRects : 렌더 대상에서 지울 직사각 영역들을 나타내는 D3D12_RECT들의 배열. 렌더 대상 전체를 지우고 싶으면 nullptr를 지정하면 된다.


void ClearDepthStencilView(
  [in] D3D12_CPU_DESCRIPTOR_HANDLE DepthStencilView,
  [in] D3D12_CLEAR_FLAGS           ClearFlags,
  [in] FLOAT                       Depth,
  [in] UINT8                       Stencil,
  [in] UINT                        NumRects,
  [in] const D3D12_RECT            *pRects
);

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12graphicscommandlist-cleardepthstencilview

 

ID3D12GraphicsCommandList::ClearDepthStencilView (d3d12.h) - Win32 apps

Clears the depth-stencil resource.

docs.microsoft.com

1. DepthStencilView :  지울 깊이·스텐실 버퍼를 서술하는 DSV.

2. ClearFlags : 깊이·스텐실 버퍼중 지우고자 하는 요소(깊이 값 또는 스텐실 값)들을 나타내는 플래그. D3D12_CLEAR_FLAG_DEPTHD3D12_CLEAR_FLAG_STENCIL 또는 그둘을 비트별 OR(논리합)로 결합한 값을 지정하면 된다.

3. Depth : 깊이 버퍼를 지우는데 사용할 깊이값.

4. Stencil : 스텐실 버퍼를 지우는 데 사용할 스텐실 값.

5. NumRects : pRects 배열의 원소 개수. pRects가 널 포인터면 0을 지정하면 된다.

6. pRects : 깊이·스텐실 버퍼에서 지울 직사각 영역들을 나타내는 D3D12_RECT들의 배열. 깊이·스텐실 버퍼 전체를 지우고 싶으면 nullptr를 지정하면 된다.


또 다른 새 메서드는 ID3D12GraphicsCommandList::OMSetRenderTargets이다. 이 메서드는 렌더링에 사용할 렌더 대상과 깊이·스텐실 버퍼를 파이프라인에 묶는다. 일단 지금은 현재 후면 버퍼 하나와 주 깊이·스텐실 버퍼 하나를 각각 렌더 대상과 깊이·스텐실 버퍼로 지정하지만, 이후에는 여러 개의 렌더 대상을 활용 하는 기법들도 나올것이다.

 

void OMSetRenderTargets(
  [in]           UINT                              NumRenderTargetDescriptors,
  [in, optional] const D3D12_CPU_DESCRIPTOR_HANDLE *pRenderTargetDescriptors,
  [in]           BOOL                              RTsSingleHandleToDescriptorRange,
  [in, optional] const D3D12_CPU_DESCRIPTOR_HANDLE *pDepthStencilDescriptor
);

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12graphicscommandlist-omsetrendertargets

 

ID3D12GraphicsCommandList::OMSetRenderTargets (d3d12.h) - Win32 apps

Sets CPU descriptor handles for the render targets and depth stencil.

docs.microsoft.com

1. NumRenderTargetDescriptors : 파이프라인에 묶을 렌더 대상들을 서술하는 RTV들의 개수, 일부 고급 기법은 동시에 여러 개의 렌더 대상을 사용한다.

2. pRenderTargetDescriptors 파이프라인에 묶을 렌더 대상들을 서술하는 RTV들의 배열을 가리키는 포인터.

3. RTsSingleHandleToDescriptorRange : 앞의 배열의 모든 RTV가 서술자 힙 안에 연속적으로 저장되어 있으면 true, 그렇지 않으면 false를 지정한다.

4. pDepthStencilDescriptor : 파이프라인에 묶을 깊이·스텐실 버퍼를 서술하는 DSV를 가리키는 포인터.


마지막으로, IDXGISwapChain::Present 메서드는 후면 버퍼와 전면 버퍼를 교환한다.

Comments