5. 프레임워크
https://github.com/Microsoft/DirectX-Graphics-Samples
GitHub - microsoft/DirectX-Graphics-Samples: This repo contains the DirectX Graphics samples that demonstrate how to build graph
This repo contains the DirectX Graphics samples that demonstrate how to build graphics intensive applications on Windows. - GitHub - microsoft/DirectX-Graphics-Samples: This repo contains the Direc...
github.com
1. 프레임 통계치(FPS)
FPS 계산하는법:
일정 기간 t동안 처리한 프레임 n개를 t로 나누면 평균 fps가 된다. 만약 t = 1 일 땐 fps = n / 1 = n 이다. 실제로 예제 프레임워크는 t = 1 (초 단위)로 둔다.
MSPF(프레임 당 밀리초) = 1000.0f(1초 = 1000밀리초) / fps
void D3DApp::CalculateFrameStats()
{
static int frameCount = 0;
static float timeElapsed = 0.0f;
++frameCount;
float fps = (float)frameCount;
float mspf = 1000.0f / fps; // miliseconds per frame
wstring fpsStr = to_wstring(fps);
wstring mspfStr = to_wstring(mspf);
wstring windowText = mCaption + L"fps: " + fpsStr + L" mspf: " + mspfStr;
SetWindowText(mWnd, windowText.c_str());
frameCount = 0;
timeElapsed += 1.0;
}
2. 메시지 처리부(MsgProc)
https://docs.microsoft.com/en-us/windows/win32/inputdev/keyboard-input
Keyboard Input (Keyboard and Mouse Input) - Win32 apps
This section discusses how the system generates keyboard input and how an application receives and processes that input.
docs.microsoft.com
예제 프레임워크의 메시지 처리부가 처리하는 첫 메시지는 WM_ACTIVATE 메시지이다. 이 메시지는 응용 프로그램이 활성/비활성될 때 전달된다.
case WM_ACTIVATE:
if (LOWORD(wParam) == WA_INACTIVE)
{
mAppPaused = true;
mTimer.Stop();
}
else
{
mAppPaused = false;
mTimer.Start();
}
return 0;
그 다음으로 처리하는 메시지는 WM_SIZE이다. 이 메시지를 처리하는 주된 이유는 후면 버퍼와 깊이 · 스텐실 버퍼의 크기를 클라이언트 영역에 맞게 갱신해야 한다는 점이다. 버퍼의 크기는 D3DApp::OnResize()에 구현되어 있다. 후면 버퍼의 크기는 IDXGISwapChain::ResizeBuffers()로 변경할 수 있다. 깊이 · 스텐실 버퍼는 파괴한 후 새 크기로 다시 생성해야 한다. 버퍼 뿐 아니라 rtv, dsv도 다시 생성해야 한다. 창 크기를 끄는동안 계속 갱신하는 것은 비효율적이므로 테두리 끌기를 멈출 때 버퍼들을 갱신한다.
// 테두리를 잡으면 전달된다.
case WM_ENTERSIZEMOVE:
mAppPaused = true;
mResizing = true;
mTimer.Stop();
return 0;
// 테두리를 놓으면 전달된다.
case WM_EXITSIZEMOVE:
mAppPaused = false;
mResizing = false;
mTimer.Start();
OnResize();
return 0;
마우스 메시지들은 다음과 같이 처리한다. (#include <windowsx.h>)
// 마우스 입력 처리
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
OnMouseDown(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0;
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
OnMouseUp(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0;
case WM_MOUSEMOVE:
OnMouseMove(wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0;
3. 화면 재조정(OnResize())
화면 조정 시
1. 울타리 지점을 갱신한다.
2. ID3D12GraphicsCommandList::Reset()로 명령 리스트를 초기화한다.(CommandList->Close() 상태여야 한다.)
3. 전 · 후면 버퍼, 깊이 · 스텐실 버퍼를 초기화 한다.
4. IDXGISwapChain::ResizeBuffer()로 후면 버퍼의 크기를 조정한다.
5. RTV, DSV를 재설정한다.
6. ID3D12GrahicsCommandList::Close()로 명령을 닫는다.
7. ID3D12CommandQueue:ExecuteCommandLists()로 명령을 제출한다.
8. 울타리 지점을 갱신한다.
9. 뷰포트를 설정한다.
void D3DApp::OnResize()
{
assert(mDevice);
assert(mSwapChain);
assert(mCommandAllocator);
FlushCommandQueue();
ThrowIfFailed(mCommandList->Reset(mCommandAllocator.Get(), nullptr));
for (int i = 0; i < SwapChainBufferCount; ++i)
{
mBackBuffer[i].Reset();
}
mDepthStencilBuffer.Reset();
ThrowIfFailed(mSwapChain->ResizeBuffers(
SwapChainBufferCount,
mWidth,
mHeight,
mBackBufferFormat,
DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH));
mCurrentBuffer = 0;
CreateRtv();
CreateDsv();
ThrowIfFailed(mCommandList->Close());
ID3D12CommandList* cmdLists[] = {mCommandList.Get()};
mCommandQueue->ExecuteCommandLists(_countof(cmdLists), cmdLists);
FlushCommandQueue();
ViewPort();
}
4. InitDirect3DApp 예제
#include "d3dApp.h"
#include <DirectXColors.h>
using namespace DirectX;
class InitDirect3DApp : public D3DApp
{
public:
InitDirect3DApp(HINSTANCE hInstance);
~InitDirect3DApp();
virtual bool Initialize() override;
virtual void OnResize() override;
virtual void Update(const GameTimer& timer) override;
virtual void Draw(const GameTimer& timer) override;
virtual void OnMouseDown(WPARAM btnState, int x, int y) override;
virtual void OnMouseUp(WPARAM btnState, int x, int y) override;
virtual void OnMouseMove(WPARAM btnState, int x, int y) override;
};
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int mShowCmd)
{
#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"theApp Initialize 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& timer)
{
}
void InitDirect3DApp::Draw(const GameTimer& timer)
{
// 명령 할당자, 리스트 리셋
ThrowIfFailed(mCommandAllocator->Reset());
ThrowIfFailed(mCommandList->Reset(mCommandAllocator.Get(), nullptr));
// 후면 버퍼 상태 전이(PRESENT->RENDER_TARGET)
mCommandList->ResourceBarrier(
1,
&CD3DX12_RESOURCE_BARRIER::Transition(
GetBackBuffer(),
D3D12_RESOURCE_STATE_PRESENT,
D3D12_RESOURCE_STATE_RENDER_TARGET));
// 뷰포트와 가위직사각형 바인딩
mCommandList->RSSetViewports(1, &mViewport);
mCommandList->RSSetScissorRects(1, &mScissorRect);
// rtv, dsv 설정
mCommandList->ClearRenderTargetView(GetRtvHandle(), DirectX::Colors::Beige, 0, nullptr);
mCommandList->ClearDepthStencilView(GetDsvHandle(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
// rtv 바인딩
mCommandList->OMSetRenderTargets(1, &GetRtvHandle(), true, &GetDsvHandle());
// 후면 버퍼 상태 전이(RENDER_TARGET->PRESENT)
mCommandList->ResourceBarrier(
1,
&CD3DX12_RESOURCE_BARRIER::Transition(
GetBackBuffer(),
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PRESENT));
// 명령 리스트 닫기
ThrowIfFailed(mCommandList->Close());
// 명령 리스트 배열 명령 큐에 제출
ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
ThrowIfFailed(mSwapChain->Present(0, 0));
mCurrentBuffer = (mCurrentBuffer + 1) % SwapChainBufferCount;
FlushCommandQueue();
}
void InitDirect3DApp::OnMouseDown(WPARAM btnState, int x, int y)
{
}
void InitDirect3DApp::OnMouseUp(WPARAM btnState, int x, int y)
{
}
void InitDirect3DApp::OnMouseMove(WPARAM btnState, int x, int y)
{
}