DirectX11 - 3D Transformation

Sungsik Bae·2024년 1월 25일

DirectX11

목록 보기
6/6
post-thumbnail

3D Transformation

3차원 Transformation..
매번 영어로만 말해서 한글로 무슨 뜻인지 모르겠다. 변환? 이런 뜻인가
네~ 맞네요 :>

이번 튜토리얼에서는 3차원 변환에 대한 내용이 있나보다.
참고로 DirectX11 SDK에 있는 Tutorial을 따라 공부 중입니다. [링크]

우선, 간단한 예제로 하나의 Cube를 하나 만들어보자.

Translation

void Render()
{
	...
    g_World = XMMatrixTranslation(-4.0f, 1.0f, 1.0f);
	...
}

위의 코드를 보면 간단하게, 월드 좌표의 원점을 이동 시켰다.

[100001000010xyz1]\begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ x & y & z & 1 \end{bmatrix}

위의 행렬이 이동 횡렬이다.

Rotation

void Render()
{
	...
	const XMMATRIX mTranslate = XMMatrixTranslation(-4.0f, 1.0f, 1.0f);
	const XMMATRIX mRotate = XMMatrixRotationZ(-t);

	g_World = mRotate * mTranslate;
	...
}

Rx(θ)=[10000cos(θ)sin(θ)00sin(θ)cos(θ)00001]R_x(\theta) = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & cos(\theta) & -sin(\theta) & 0 \\ 0 & sin(\theta) & cos(\theta) & 0 \\ 0 & 0 & 0 & 1\end{bmatrix}
Ry(θ)=[cos(θ)0sin(θ)00100sin(θ)0cos(θ)00001]R_y(\theta) = \begin{bmatrix} cos(\theta) & 0 & -sin(\theta) & 0 \\ 0 & 1 & 0 & 0 \\ sin(\theta) & 0 & cos(\theta) & 0 \\ 0 & 0 & 0 & 1\end{bmatrix}
Rz(θ)=[cos(θ)sin(θ)00sin(θ)cos(θ)0000100001]R_z(\theta) = \begin{bmatrix} cos(\theta) & -sin(\theta) & 0 & 0 \\ sin(\theta) & cos(\theta) & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1\end{bmatrix}
R=Rz(α)Ry(β)Rx(λ)=[cos(α)cos(β)cos(α)sin(β)sin(λ)sin(α)cos(λ)cos(α)sin(β)cos(λ)+sin(α)sin(λ)0sin(α)cos(β)sin(α)sin(β)sin(λ)+cos(α)cos(λ)sin(α)sin(β)sin(λ)cos(α)cos(λ)0sin(β)cos(β)sin(λ)cos(β)cos(λ)00001]R = R_z(\alpha)R_y(\beta)R_x(\lambda) = \begin{bmatrix} cos(\alpha)cos(\beta) & cos(\alpha)sin(\beta)sin(\lambda) - sin(\alpha)cos(\lambda) & cos(\alpha)sin(\beta)cos(\lambda) + sin(\alpha)sin(\lambda) & 0 \\ sin(\alpha)cos(\beta) & sin(\alpha)sin(\beta)sin(\lambda) + cos(\alpha)cos(\lambda) & sin(\alpha)sin(\beta)sin(\lambda) - cos(\alpha)cos(\lambda) & 0 \\ -sin(\beta) & cos(\beta)sin(\lambda) & cos(\beta)cos(\lambda) & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}

위 행렬이 회전 행렬이다.

여기서 눈여겨 볼 만한 점은, mWorld = mRotate * mTranslate이다.

생각해보면 간단한 점인데, 이동을 하고 회전을 하게 된다면, 원점을 기준으로 회전하게 될 것이다. 즉, 어떤 점을 기준으로 공전을 하게 될 것이다.

Scale

const XMMATRIX mTranslate = XMMatrixTranslation(-4.0f, 1.0f, 1.0f);
const XMMATRIX mRotate = XMMatrixRotationZ(-t);
const XMMATRIX mScale = XMMatrixScaling(0.5f, 0.3f, 1.0f);

g_World = mScale * mRotate * mTranslate;

[x0000y0000z00001]\begin{bmatrix} x & 0 & 0 & 0 \\ 0 & y & 0 & 0 \\ 0 & 0 & z & 0 \\ 0 & 0 & 0 & 1\end{bmatrix}

위 행렬이 크기 행렬이다.

이러한 변환 행렬을 SRT변환 행렬이라고 한다. (Scale x Rotation x Translation)

Depth Stencil Buffer

깊이 스텐실 버퍼는 무엇일까?
깊이는 화면에 그려질 때, 어느 것이 먼저 그려지는지에 대한 정보를 담고 있다.
즉, 같은 위치에 그려지는 픽셀의 Depth값에 따라 어느 픽셀이 그려질지를 결정한다.

대충 큐브가 2개 그려졌을 때, z값에 따라(카메라와의 거리) 큐브가 그려져야 하는데 depth buffer를 설정해주지 않으면 Render 함수에서 DrawIndexed 함수의 호출 순서대로 그려진다.

void Render()
{
...
	g_World = XMMatrixRotationY(t) * XMMatrixTranslation(0.0f, 0.0f, 5.0f);

	const XMMATRIX mTranslate = XMMatrixTranslation(-4.0f, 0.0f, 0.0f);
	const XMMATRIX mRotate = XMMatrixRotationZ(-t);
	const XMMATRIX mScale = XMMatrixScaling(0.3f, 0.3f, 0.3f);

	const XMMATRIX mOrbit = XMMatrixRotationY(-t * 2.0f) * XMMatrixTranslation(0.0f, 0.0f, 5.0f);

	g_World2 = mScale * mRotate * mTranslate * mOrbit;

	constexpr float clearColor[4] = { 0.0f, 0.125f,0.3f,1.0f };
	g_pImmediateContext->ClearRenderTargetView(g_pRenterTargetView, clearColor);

	ConstantBuffer cb;
	cb.mWorld = XMMatrixTranspose(g_World);
	cb.mView = XMMatrixTranspose(g_View);
	cb.mProjection = XMMatrixTranspose(g_Projection);
	g_pImmediateContext->UpdateSubresource(g_pConstantBuffer, 0, nullptr, &cb, 0, 0);

	g_pImmediateContext->VSSetShader(g_pVertexShader, nullptr, 0);
	g_pImmediateContext->VSSetConstantBuffers(0, 1, &g_pConstantBuffer);
	g_pImmediateContext->PSSetShader(g_pPixelShader, nullptr, 0);
	g_pImmediateContext->DrawIndexed(36, 0, 0);

	ConstantBuffer cb2;
	cb2.mWorld = XMMatrixTranspose(g_World2);
	cb2.mView = XMMatrixTranspose(g_View);
	cb2.mProjection = XMMatrixTranspose(g_Projection);
	g_pImmediateContext->UpdateSubresource(g_pConstantBuffer, 0, nullptr, &cb2, 0, 0);
	g_pImmediateContext->DrawIndexed(36, 0, 0);
...
}

위와 같이 카메라와의 거리와 상관없이 DrawIndexed 함수의 순서대로 그려지는 모습이다.

D3D11_TEXTURE2D_DESC depthTex;
ZeroMemory(&depthTex, sizeof(D3D11_TEXTURE2D_DESC));
depthTex.Width = width;
depthTex.Height = height;
depthTex.MipLevels = 1;		// mipmap 개수
depthTex.ArraySize = 1;		// array size
depthTex.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;	// depth 24, stencil 8bit
depthTex.SampleDesc.Count = 1;		// 멀티 샘플링 수
depthTex.SampleDesc.Quality = 0;	// 멀티 샘플링 퀄리티
depthTex.Usage = D3D11_USAGE_DEFAULT;	// Default 사용법
depthTex.BindFlags = D3D11_BIND_DEPTH_STENCIL;	// 깊이 / 스텐실 버퍼로 사용
depthTex.CPUAccessFlags = 0;	// cpu 사용 안함.
depthTex.MiscFlags = 0;
hr = g_pDevice->CreateTexture2D(&depthTex, nullptr, &g_pDepthStencil);
if (FAILED(hr))
{
	return hr;
}
	D3D11_DEPTH_STENCIL_VIEW_DESC dsv;
	ZeroMemory(&dsv, sizeof(D3D11_DEPTH_STENCIL_VIEW_DESC));
	dsv.Format = depthTex.Format;	// depth stencil texture format사용
	dsv.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;	// 2d texture 사용
	dsv.Texture2D.MipSlice = 0;
	hr = g_pDevice->CreateDepthStencilView(g_pDepthStencil, &dsv, &g_pDepthStencilView);
	if (FAILED(hr))
	{
		return hr;
	}

	g_pImmediateContext->OMSetRenderTargets(
		1,						// Render target의 개수(최대 8개)
		&g_pRenterTargetView,	// Render target view의 배열
		g_pDepthStencilView		// Depth stencil view 포인터
	);
void Render()
{
...
	g_pImmediateContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);
...
}

위와 같은 과정을 거치면, Depth stencil texture 생성, Depth stencil view 생성, Graphic pipeline에 설정까지 해준다.


#include <Windows.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <DirectXMath.h>

//--------------------------------------------------------------------------------------
// Using namespaces
//--------------------------------------------------------------------------------------
using namespace DirectX;

//--------------------------------------------------------------------------------------
// Structures
//--------------------------------------------------------------------------------------
struct SimpleVertex
{
	XMFLOAT3 Pos;
	XMFLOAT4 Color;
};

struct ConstantBuffer
{
	XMMATRIX mWorld;
	XMMATRIX mView;
	XMMATRIX mProjection;
};

//--------------------------------------------------------------------------------------
// Global Variables
//--------------------------------------------------------------------------------------
HINSTANCE g_hInstance;
HWND g_hWnd;
D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL;
D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0;
ID3D11Device* g_pDevice = nullptr;
ID3D11DeviceContext* g_pImmediateContext = nullptr;
IDXGISwapChain* g_pSwapChain = nullptr;
ID3D11RenderTargetView* g_pRenterTargetView = nullptr;
ID3D11Texture2D* g_pDepthStencil = nullptr;
ID3D11DepthStencilView* g_pDepthStencilView = nullptr;
ID3D11VertexShader* g_pVertexShader = nullptr;
ID3D11InputLayout* g_pVertexLayout = nullptr;
ID3D11PixelShader* g_pPixelShader = nullptr;
ID3D11Buffer* g_pVertexBuffer = nullptr;
ID3D11Buffer* g_pIndexBuffer = nullptr;
ID3D11Buffer* g_pConstantBuffer = nullptr;
XMMATRIX g_World;
XMMATRIX g_World2;
XMMATRIX g_View;
XMMATRIX g_Projection;

//--------------------------------------------------------------------------------------
// Forward declarations
//--------------------------------------------------------------------------------------
HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow);
HRESULT InitDevice();
void CleanupDevice();
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void Render();

//--------------------------------------------------------------------------------------
// Entry point to the program. Initializes everything and goes into a message processing 
// loop. Idle time is used to render the scene.
//--------------------------------------------------------------------------------------
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
	if (FAILED(InitWindow(hInstance, nCmdShow)))
	{
		return 0;
	}

	if (FAILED(InitDevice()))
	{
		CleanupDevice();
		return 0;
	}

	MSG msg = { nullptr };
	while (WM_QUIT != msg.message)
	{
		if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			Render();
		}
	}

	CleanupDevice();

	return static_cast<int>(msg.wParam);
}

HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow)
{
	// Register Window class
	WNDCLASSEX wcex;
	ZeroMemory(&wcex, sizeof(wcex));

	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc = WndProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
	wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
	wcex.hbrBackground = reinterpret_cast<HBRUSH>((COLOR_WINDOW + 1));
	wcex.lpszMenuName = nullptr;
	wcex.lpszClassName = L"TutorialWindowClass";
	wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);

	if (!RegisterClassEx(&wcex))
	{
		return E_FAIL;
	}

	g_hInstance = hInstance;
	RECT rc = { 0, 0, 640, 480 };
	AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
	g_hWnd = CreateWindowEx(NULL,
		L"TutorialWindowClass",
		L"Direct3D 11 Tutorial 1: Direct3D 11 Basics",
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		rc.right - rc.left,
		rc.bottom - rc.top,
		nullptr,
		nullptr,
		hInstance,
		nullptr);

	if (g_hWnd == nullptr)
	{
		return E_FAIL;
	}

	ShowWindow(g_hWnd, nCmdShow);

	return S_OK;
}

HRESULT CompileShaderFromFile(LPCTSTR szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut)
{
	HRESULT hr = S_OK;

	DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR;
#if defined( DEBUG ) || defined( _DEBUG )
	// Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
	// Setting this flag improves the shader debugging experience, but still allows 
	// the shaders to be optimized and to run exactly the way they will run in 
	// the release configuration of this program.
	dwShaderFlags |= D3DCOMPILE_DEBUG;
#endif

	ID3DBlob* pErrorBlob;
	hr = D3DCompileFromFile(
		szFileName,						// 파일명
		nullptr,						// 매크로 정의
		nullptr,						// Include 파일 정의
		szEntryPoint,					// 셰이더 Entry point 이름(메인 함수 이름)
		szShaderModel,					// 셰이더 컴파일 버전(vs_4_0 = Vertex shader version 4.0)
		dwShaderFlags,					// 컴파일 옵션
		0,								// 이펙트 컴파일 옵션
		ppBlobOut,						// 컴파일 된 Byte코드
		&pErrorBlob						// 에러 메세지
	);
	if (FAILED(hr))
	{
		if (pErrorBlob != nullptr)
		{
			OutputDebugStringA(static_cast<LPCSTR>(pErrorBlob->GetBufferPointer()));
		}
		else
		{
			pErrorBlob->Release();
		}
		return hr;
	}

	if (pErrorBlob)
	{
		pErrorBlob->Release();
	}

	return S_OK;
}

HRESULT InitDevice()
{
	HRESULT hr = S_OK;

	RECT rc;
	GetClientRect(g_hWnd, &rc);
	const UINT width = rc.right - rc.left;
	const UINT height = rc.bottom - rc.top;

	UINT createDeviceFlags = 0;
#ifdef _DEBUG
	createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

	D3D_DRIVER_TYPE driverTypes[] =
	{
		D3D_DRIVER_TYPE_HARDWARE,
		D3D_DRIVER_TYPE_WARP,
		D3D_DRIVER_TYPE_REFERENCE,
	};
	constexpr UINT numDriverTypes = ARRAYSIZE(driverTypes);

	D3D_FEATURE_LEVEL featureLevels[] =
	{
		D3D_FEATURE_LEVEL_11_0,
		D3D_FEATURE_LEVEL_10_1,
		D3D_FEATURE_LEVEL_10_0,
	};
	constexpr UINT numFeatureLevels = ARRAYSIZE(featureLevels);

	DXGI_SWAP_CHAIN_DESC sd;
	ZeroMemory(&sd, sizeof(DXGI_SWAP_CHAIN_DESC));
	sd.BufferCount = 1;
	sd.BufferDesc.Width = width;
	sd.BufferDesc.Height = height;
	sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	sd.BufferDesc.RefreshRate.Numerator = 60;
	sd.BufferDesc.RefreshRate.Denominator = 1;
	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sd.OutputWindow = g_hWnd;
	sd.SampleDesc.Count = 1;
	sd.SampleDesc.Quality = 0;
	sd.Windowed = TRUE;

	for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++)
	{
		g_driverType = driverTypes[driverTypeIndex];
		hr = D3D11CreateDeviceAndSwapChain(
			nullptr,						// device를 생성하기 위한 video adapter(nullptr = default adapter)
			g_driverType,					// driver type
			nullptr,						// software handle
			createDeviceFlags,				// device flag
			featureLevels,					// feature level array
			numFeatureLevels,				// feature level array length
			D3D11_SDK_VERSION,				// sdk version
			&sd,							// swap chain structure
			&g_pSwapChain,					// 생성된 swap chain 
			&g_pDevice,						// 생성된 device
			&g_featureLevel,				// 생성된 feature level
			&g_pImmediateContext);			// 생성된 device context

		if (SUCCEEDED(hr))
		{
			break;
		}
	}

	if (FAILED(hr))
	{
		return hr;
	}

	ID3D11Texture2D* pBackBuffer = nullptr;
	hr = g_pSwapChain->GetBuffer(
		0,													// 백버퍼 index
		__uuidof(ID3D11Texture2D),							// back buffer를 다루기 위한 interface
		reinterpret_cast<LPVOID*>(&pBackBuffer)				// back buffer interface output
	);
	if (FAILED(hr))
	{
		return hr;
	}

	hr = g_pDevice->CreateRenderTargetView(
		pBackBuffer,			// View에서 접근할 리소스
		nullptr,				// RTV 정의
		&g_pRenterTargetView);	// RTV를 받아올 변수
	// 사용한 back buffer를 Release 
	pBackBuffer->Release();
	if (FAILED(hr))
	{
		return hr;
	}

	D3D11_TEXTURE2D_DESC depthTex;
	ZeroMemory(&depthTex, sizeof(D3D11_TEXTURE2D_DESC));
	depthTex.Width = width;
	depthTex.Height = height;
	depthTex.MipLevels = 1;
	depthTex.ArraySize = 1;
	depthTex.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	depthTex.SampleDesc.Count = 1;
	depthTex.SampleDesc.Quality = 0;
	depthTex.Usage = D3D11_USAGE_DEFAULT;
	depthTex.BindFlags = D3D11_BIND_DEPTH_STENCIL;
	depthTex.CPUAccessFlags = 0;
	depthTex.MiscFlags = 0;
	hr = g_pDevice->CreateTexture2D(&depthTex, nullptr, &g_pDepthStencil);
	if (FAILED(hr))
	{
		return hr;
	}

	D3D11_DEPTH_STENCIL_VIEW_DESC dsv;
	ZeroMemory(&dsv, sizeof(D3D11_DEPTH_STENCIL_VIEW_DESC));
	dsv.Format = depthTex.Format;
	dsv.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
	dsv.Texture2D.MipSlice = 0;
	hr = g_pDevice->CreateDepthStencilView(g_pDepthStencil, &dsv, &g_pDepthStencilView);
	if (FAILED(hr))
	{
		return hr;
	}

	g_pImmediateContext->OMSetRenderTargets(
		1,						// Render target의 개수(최대 8개)
		&g_pRenterTargetView,	// Render target view의 배열
		g_pDepthStencilView		// Depth stencil view 포인터
	);

	D3D11_VIEWPORT vp;
	vp.Width = static_cast<FLOAT>(width);
	vp.Height = static_cast<FLOAT>(height);
	vp.MinDepth = 0.0f;
	vp.MaxDepth = 1.0f;
	vp.TopLeftX = 0;
	vp.TopLeftY = 0;
	g_pImmediateContext->RSSetViewports(1, &vp);

	// compile the vertex shader
	ID3DBlob* pVSBlob = nullptr;
	hr = CompileShaderFromFile(L"Tutorial04.fx", "VS", "vs_4_0", &pVSBlob);
	if (FAILED(hr))
	{
		MessageBox(nullptr, L"The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.",
			L"Error", MB_OK);
		return hr;
	}

	// create the vertex shader
	hr = g_pDevice->CreateVertexShader(pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), nullptr, &g_pVertexShader);
	if (FAILED(hr))
	{
		pVSBlob->Release();
		return hr;
	}

	// define the input layout (정점 데이터를 GPU에게 알려주는 구조체)
	D3D11_INPUT_ELEMENT_DESC layout[] =
	{
		{"POSITION",					// Element의 목적이 무엇인이 알려주는 문자열 (POSITION, NORMAL, ...)
		0,								// 동일한 Element의 목적을 가진 정점의 Index
		DXGI_FORMAT_R32G32B32_FLOAT,	// 자료형
		0,								// 정점 버퍼 슬롯 index
		0,								// 정점 버퍼 offset
		D3D11_INPUT_PER_VERTEX_DATA,	// D3D11_INPUT_PER_VERTEX_DATA를 사용함.
		0								// Instancing에 사용됨
		},
		{
			"COLOR",
			0,
			DXGI_FORMAT_R32G32B32A32_FLOAT,
			0,
			12,
			D3D11_INPUT_PER_VERTEX_DATA,
			0
		}
	};
	constexpr UINT numElements = ARRAYSIZE(layout);

	// create the input layout
	hr = g_pDevice->CreateInputLayout(layout, numElements, pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), &g_pVertexLayout);
	pVSBlob->Release();
	if (FAILED(hr))
	{
		return hr;
	}

	// set the input layout
	g_pImmediateContext->IASetInputLayout(g_pVertexLayout);

	// compile the pixel shader
	ID3DBlob* pPSBlob = nullptr;
	hr = CompileShaderFromFile(L"Tutorial04.fx", "PS", "ps_4_0", &pPSBlob);
	if (FAILED(hr))
	{
		MessageBox(nullptr, L"The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.",
			L"Error", MB_OK);
		return hr;
	}

	// create the pixel shader
	hr = g_pDevice->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), nullptr, &g_pPixelShader);
	pPSBlob->Release();
	if (FAILED(hr))
	{
		return hr;
	}

	// create vertex buffer
	constexpr SimpleVertex vertices[] =
	{
		{ XMFLOAT3(-1.0f, 1.0f, -1.0f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f) },
		{ XMFLOAT3(1.0f, 1.0f, -1.0f), XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f) },
		{ XMFLOAT3(1.0f, 1.0f, 1.0f), XMFLOAT4(0.0f, 1.0f, 1.0f, 1.0f) },
		{ XMFLOAT3(-1.0f, 1.0f, 1.0f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f) },
		{ XMFLOAT3(-1.0f, -1.0f, -1.0f), XMFLOAT4(1.0f, 0.0f, 1.0f, 1.0f) },
		{ XMFLOAT3(1.0f, -1.0f, -1.0f), XMFLOAT4(1.0f, 1.0f, 0.0f, 1.0f) },
		{ XMFLOAT3(1.0f, -1.0f, 1.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f) },
		{ XMFLOAT3(-1.0f, -1.0f, 1.0f), XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f) },
	};
	D3D11_BUFFER_DESC bd;
	ZeroMemory(&bd, sizeof(D3D11_BUFFER_DESC));
	bd.Usage = D3D11_USAGE_DEFAULT;				// default로 사용
	bd.ByteWidth = sizeof(SimpleVertex) * 8;	// vertex
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;	// vertex buffer로 바인드
	bd.CPUAccessFlags = 0;						// cpu access하지 않음.

	D3D11_SUBRESOURCE_DATA initData;
	ZeroMemory(&initData, sizeof(D3D11_SUBRESOURCE_DATA));
	initData.pSysMem = vertices;	// 버퍼 데티
	hr = g_pDevice->CreateBuffer(&bd, &initData, &g_pVertexBuffer);
	if (FAILED(hr))
	{
		return hr;
	}

	// set vertex buffer
	UINT stride = sizeof(SimpleVertex);
	UINT offset = 0;
	g_pImmediateContext->IASetVertexBuffers(0, 1, &g_pVertexBuffer, &stride, &offset);

	// Create index buffer
	WORD indices[] =
	{
		3,1,0,
		2,1,3,

		0,5,4,
		1,5,0,

		3,4,7,
		0,4,3,

		1,6,5,
		2,6,1,

		2,7,6,
		3,7,2,

		6,4,5,
		7,4,6,
	};
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(WORD) * 36;
	bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
	bd.CPUAccessFlags = 0;
	initData.pSysMem = indices;
	hr = g_pDevice->CreateBuffer(&bd, &initData, &g_pIndexBuffer);
	if (FAILED(hr))
	{
		return hr;
	}

	g_pImmediateContext->IASetIndexBuffer(g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);

	// set primitive topology
	g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(ConstantBuffer);
	bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	bd.CPUAccessFlags = 0;
	hr = g_pDevice->CreateBuffer(&bd, nullptr, &g_pConstantBuffer);
	if (FAILED(hr))
	{
		return hr;
	}

	g_World = XMMatrixIdentity();

	XMVECTOR eye = XMVectorSet(0.0f, 1.0f, -5.0f, 0.0f);
	XMVECTOR at = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
	XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
	g_View = XMMatrixLookAtLH(eye, at, up);

	g_Projection = XMMatrixPerspectiveFovLH(XM_PIDIV2, static_cast<float>(width) / height, 0.01f, 100.0f);

	return S_OK;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hdc;

	switch (uMsg)
	{
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		EndPaint(hWnd, &ps);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, uMsg, wParam, lParam);
	}

	return 0;
}

void Render()
{
	// Update our time
	static float t = 0.0f;
	if (g_driverType == D3D_DRIVER_TYPE_REFERENCE)
	{
		t += static_cast<float>(XM_PI) * 0.0125f;
	}
	else
	{
		static DWORD dwTimeStart = 0;
		const DWORD dwTimeCur = GetTickCount();
		if (dwTimeStart == 0)
			dwTimeStart = dwTimeCur;
		t = (dwTimeCur - dwTimeStart) / 1000.0f;
	}

	g_World = XMMatrixRotationY(t) * XMMatrixTranslation(0.0f, 0.0f, 5.0f);

	const XMMATRIX mTranslate = XMMatrixTranslation(-4.0f, 0.0f, 0.0f);
	const XMMATRIX mRotate = XMMatrixRotationZ(-t);
	const XMMATRIX mScale = XMMatrixScaling(0.3f, 0.3f, 0.3f);

	const XMMATRIX mOrbit = XMMatrixRotationY(-t * 2.0f) * XMMatrixTranslation(0.0f, 0.0f, 5.0f);

	g_World2 = mScale * mRotate * mTranslate * mOrbit;

	constexpr float clearColor[4] = { 0.0f, 0.125f,0.3f,1.0f };
	g_pImmediateContext->ClearRenderTargetView(g_pRenterTargetView, clearColor);

	g_pImmediateContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);

	ConstantBuffer cb;
	cb.mWorld = XMMatrixTranspose(g_World);
	cb.mView = XMMatrixTranspose(g_View);
	cb.mProjection = XMMatrixTranspose(g_Projection);
	g_pImmediateContext->UpdateSubresource(g_pConstantBuffer, 0, nullptr, &cb, 0, 0);

	g_pImmediateContext->VSSetShader(g_pVertexShader, nullptr, 0);
	g_pImmediateContext->VSSetConstantBuffers(0, 1, &g_pConstantBuffer);
	g_pImmediateContext->PSSetShader(g_pPixelShader, nullptr, 0);
	g_pImmediateContext->DrawIndexed(36, 0, 0);

	ConstantBuffer cb2;
	cb2.mWorld = XMMatrixTranspose(g_World2);
	cb2.mView = XMMatrixTranspose(g_View);
	cb2.mProjection = XMMatrixTranspose(g_Projection);
	g_pImmediateContext->UpdateSubresource(g_pConstantBuffer, 0, nullptr, &cb2, 0, 0);
	g_pImmediateContext->DrawIndexed(36, 0, 0);

	g_pSwapChain->Present(0, 0);
}

void CleanupDevice()
{
	if (g_pImmediateContext)
	{
		g_pImmediateContext->ClearState();
	}

	if (g_pConstantBuffer)
	{
		g_pConstantBuffer->Release();
	}
	if (g_pVertexBuffer)
	{
		g_pVertexBuffer->Release();
	}
	if (g_pVertexLayout)
	{
		g_pVertexLayout->Release();
	}
	if (g_pVertexShader)
	{
		g_pVertexShader->Release();
	}
	if (g_pPixelShader)
	{
		g_pPixelShader->Release();
	}
	if (g_pDepthStencil)
	{
		g_pDepthStencil->Release();
	}
	if (g_pDepthStencilView)
	{
		g_pDepthStencilView->Release();
	}
	if (g_pRenterTargetView)
	{
		g_pRenterTargetView->Release();
	}
	if (g_pSwapChain)
	{
		g_pSwapChain->Release();
	}
	if (g_pImmediateContext)
	{
		g_pImmediateContext->Release();
	}
	if (g_pDevice)
	{
		g_pDevice->Release();
	}
}

profile
Game Developer

0개의 댓글