
이번에는 삼각형 대신 입체적인 큐브를 구현해보려고 한다
삼각형과 달리 큐브는 6개의 면을 가지고 있지만 이를 삼각형으로 구현하면 12개의 삼각형이 필요하고
단순히 계산하면 12*3 = 36개의 버텍스가 필요하게 된다
하지만 큐브는 8개의 버텍스만 가지고 구현하게 되는데
동일한 버텍스를 여러 삼각형에서 재사용 하기 위해 필요한것이 인덱스 버퍼이다
먼저 큐브의 버텍스들을 만들어준다
Vertex vertices[8] =
{
{ -0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f },
{ 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f },
{ 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f },
{ -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f },
{ -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f },
{ 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 1.0f },
{ 0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 1.0f },
{ -0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f }
};
이제 인덱스 버퍼를 전역변수로 추가해야 한다
ID3D11Buffer* g_IndexBuffer = nullptr;
그리고 인덱스 버퍼에 들어갈 인덱스를 만들어야 한다
버텍스를 3가지씩 묶어서 삼각형을 만들어야 한다
unsigned int indices[] =
{
0, 1, 2,
0, 2, 3,
4, 6, 5,
4, 7, 6,
4, 0, 3,
4, 3, 7,
1, 5, 6,
1, 6, 2,
4, 5, 1,
4, 1, 0,
3, 2, 6,
3, 6, 7
};
이제 렌더링하기 전에 InitGeometry 함수에서 인덱스 버퍼를 생성해야한다
DXGI_FORMAT_R32_UINT는 Index 하나를 32비트 Unsigned integer로 해석한다는 의미이다
D3D11_BUFFER_DESC ibd = {};
ibd.Usage = D3D11_USAGE_DEFAULT;
ibd.ByteWidth = sizeof(indices);
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
D3D11_SUBRESOURCE_DATA indexData = {};
indexData.pSysMem = indices;
HRESULT ihr = g_Device->CreateBuffer(
&ibd,
&indexData,
&g_IndexBuffer);
if (FAILED(ihr))
{
return false;
}
Render함수에서 인덱스 버퍼를 Input Assembler에 바인딩해야한다
g_Context->IASetIndexBuffer(
g_IndexBuffer,
DXGI_FORMAT_R32_UINT,
0);
DrawCube 함수를 생성한다
DrawIndexed 함수의 매개변수는 사용할 인덱스 개수, 시작 인덱스의 위치, 버텍스 버퍼의 시작 위치를 의미한다
void DrawCube(XMMATRIX world, XMMATRIX view, XMMATRIX projection)
{
ConstantBuffer cb;
XMStoreFloat4x4(
&cb.World,
XMMatrixTranspose(world));
XMStoreFloat4x4(
&cb.View,
XMMatrixTranspose(view));
XMStoreFloat4x4(
&cb.Projection,
XMMatrixTranspose(projection));
g_Context->UpdateSubresource(
g_ConstantBuffer,
nullptr,
&cb,
0,
0);
g_Context->VSSetConstantBuffers(
0,
&g_ConstantBuffer);
g_Context->DrawIndexed(
36,
0,
0);
}
Render에서 삼갹형을 그리던걸 큐브로 고쳐준다
XMMATRIX world =
XMMatrixScaling(
1.0f,
1.0f,
1.0f) *
XMMatrixRotationX(g_Angle) *
XMMatrixRotationY(g_Angle) *
XMMatrixRotationZ(g_Angle) *
XMMatrixTranslation(
0.0f,
0.0f,
0.0f);
XMMATRIX projection =
XMMatrixPerspectiveFovLH(
XMConvertToRadians(60.0f),
1280.0f / 720.0f,
0.1f,
20.0f);
DrawCube(world, view,projection);
마지막으로 프로그램 종료시 인덱스 버퍼의 해제를 위해 Cleanup 함수를 수정한다
if (g_IndexBuffer) g_IndexBuffer->Release();
이로써 8개의 버텍스를 여러 삼각형에서 재사용하면서 12개의 삼각형을 구성할 수 잇기 때문에 버텍스 데이터를 36개까지 중복해서 저장할 필요가 없어졌다
더보기
#include <Windows.h> // win32 api 헤더
#include <d3d11.h> // dx11 헤더
#include <dxgi.h> // dxgi 헤더
#include <d3dcompiler.h> // 쉐이더 컴파일러 헤더
#include <DirectXMath.h> // DirectX 수학 라이브러리 헤더
#include <algorithm> // std::clamp를 사용하기 위한 헤더
#pragma comment(lib, "d3d11.lib") // 링크
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "d3dcompiler.lib")
using namespace DirectX; // DirectX 수학 라이브러리 네임스페이스
ID3D11Device* g_Device = nullptr; // GPU 장치
ID3D11DeviceContext* g_Context = nullptr; // GPU 컨텍스트
IDXGISwapChain* g_SwapChain = nullptr; // 화면에 그려질 버퍼를 관리하는 객체 (더블 버퍼링 구현에 사용)
ID3D11RenderTargetView* g_RTV = nullptr; // 렌더 타겟 뷰 (화면에 그려질 버퍼를 GPU가 인식할 수 있도록 하는 객체)
ID3D11Buffer* g_VertexBuffer = nullptr; // 정점 버퍼 (3D 모델의 정점 데이터를 GPU에 저장하는 객체)
ID3D11VertexShader* g_VertexShader = nullptr; // 정점 쉐이더 (3D 모델의 정점 데이터를 처리하는 GPU 프로그램)
ID3D11PixelShader* g_PixelShader = nullptr; // 픽셀 쉐이더 (화면에 그려질 픽셀의 색상을 계산하는 GPU 프로그램)
ID3D11InputLayout* g_InputLayout = nullptr; // 입력 레이아웃 (GPU가 정점 데이터를 어떻게 해석할지 정의하는 객체)
ID3D11Buffer* g_ConstantBuffer = nullptr; // 상수 버퍼 (쉐이더에서 사용할 상수 데이터를 GPU에 저장하는 객체)
ID3D11Texture2D* g_DepthStencilBuffer = nullptr; // 깊이 스텐실 버퍼 (깊이 테스트와 스텐실 테스트를 위한 버퍼)
ID3D11DepthStencilView* g_DSV = nullptr; // 깊이 스텐실 뷰 (깊이 스텐실 버퍼를 GPU가 인식할 수 있도록 하는 객체)
ID3D11Buffer* g_IndexBuffer = nullptr; // 인덱스 버퍼 (3D 모델의 정점 데이터를 인덱스로 참조하여 그리는 객체)
float g_Angle = 0.0f; // 회전 각도 (삼각형 회전을 구현하기 위해 사용할 변수)
bool g_IsRightMouseDown = false; // 마우스 오른쪽 버튼이 눌렸는지 여부를 저장하는 변수 (카메라 회전을 구현하기 위해 사용할 변수)
POINT g_LastMousePos = {}; // 마우스의 마지막 위치를 저장하는 변수 (카메라 회전을 구현하기 위해 사용할 변수)
float g_Yaw = 0.0f; // Yaw (카메라의 좌우 회전을 구현하기 위해 사용할 변수)
float g_Pitch = 0.0f; // Pitch (카메라의 상하 회전을 구현하기 위해 사용할 변수)
XMVECTOR worldUp = XMVectorSet(0, 1, 0, 0); // 월드 좌표계에서의 상방 방향 벡터를 저장할 XMVECTOR 타입 변수 (Y축 방향)
// 언리얼 엔진에서는 카메라가 회전해도 상방 방향이 항상 Y축 방향이므로 up 벡터는 항상 (0, 1, 0)으로 설정
XMFLOAT3 g_CameraLocation = // 카메라 위치 (카메라의 위치를 저장하는 변수)
{
0.0f, // 카메라의 x 좌표
0.0f, // 카메라의 y 좌표
-3.0f // 카메라의 z 좌표
};
struct ConstantBuffer // 상수 버퍼 구조체 (쉐이더에서 사용할 상수 데이터를 저장하는 구조체)
{
//float angle; // 회전 각도 (쉐이더에서 사용할 회전 각도를 저장하는 변수)
//float padding[3]; // 상수 버퍼 구조체의 크기를 16바이트 단위로 맞추기 위한 패딩 (Direct3D 11에서는 상수 버퍼의 크기가 16바이트 단위로 정렬되어야 함)
XMFLOAT4X4 World; // 회전 행렬 (쉐이더에서 사용할 회전 행렬을 저장하는 변수)
XMFLOAT4X4 View; // 뷰 행렬 (쉐이더에서 사용할 뷰 행렬을 저장하는 변수)
XMFLOAT4X4 Projection; // 투영 행렬 (쉐이더에서 사용할 투영 행렬을 저장하는 변수)
};
struct Vertex // 정점 구조체 (3D 모델의 정점 정보를 저장하는 구조체)
{
float x;
float y;
float z;
float r;
float g;
float b;
};
//Vertex vertices[3] = // 삼각형을 구성하는 3개의 정점 데이터 (각 정점의 x, y, z 좌표를 저장하는 배열)
//{
// { 0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f }, // 빨강
// { 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f }, // 초록
// {-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f } // 파랑
//};
//정육면체를 구성하는 8개의 정점 데이터 (각 정점의 x, y, z 좌표와 r, g, b 색상값을 저장하는 배열)
Vertex vertices[8] =
{
// 앞면
{ -0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f },
{ 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f },
{ 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f },
{ -0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f },
// 뒷면
{ -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f },
{ 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 1.0f },
{ 0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 1.0f },
{ -0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f }
};
// 인덱스 버퍼를 구성하는 36개의 인덱스 데이터 (정육면체를 구성하는 삼각형의 정점 인덱스를 저장하는 배열)
unsigned int indices[] =
{
// 앞면
0, 1, 2,
0, 2, 3,
// 뒷면
4, 6, 5,
4, 7, 6,
// 왼쪽
4, 0, 3,
4, 3, 7,
// 오른쪽
1, 5, 6,
1, 6, 2,
// 위
4, 5, 1,
4, 1, 0,
// 아래
3, 2, 6,
3, 6, 7
};
void DrawTriangle(XMMATRIX world, XMMATRIX view, XMMATRIX projection) // 삼각형을 그리는 함수 (월드 행렬과 뷰 행렬을 인자로 받아 삼각형을 그리는 함수)
{
ConstantBuffer cb; // 상수 버퍼 구조체 생성 (쉐이더에서 사용할 상수 데이터를 저장하는 구조체)
XMStoreFloat4x4( // 회전 행렬을 상수 버퍼 구조체에 저장하는 함수
&cb.World, // 상수 버퍼 구조체의 World 멤버 변수에 회전 행렬 저장
XMMatrixTranspose(world)); // 회전 행렬을 전치(transpose)하여 상수 버퍼 구조체에 저장 (Direct3D 11에서는 행렬을 전치하여 저장해야 함)
XMStoreFloat4x4( // 뷰 행렬을 상수 버퍼 구조체에 저장하는 함수
&cb.View, // 상수 버퍼 구조체의 View 멤버 변수에 뷰 행렬 저장
XMMatrixTranspose(view)); // 뷰 행렬을 전치하여 상수 버퍼 구조체에 저장 (Direct3D 11에서는 행렬을 전치하여 저장해야 함)
XMStoreFloat4x4( // 투영 행렬을 상수 버퍼 구조체에 저장하는 함수
&cb.Projection, // 상수 버퍼 구조체의 Projection 멤버 변수에 투영 행렬 저장
XMMatrixTranspose(projection)); // 투영 행렬을 전치하여 상수 버퍼 구조체에 저장 (Direct3D 11에서는 행렬을 전치하여 저장해야 함)
g_Context->UpdateSubresource( // 상수 버퍼의 데이터를 업데이트하는 함수
g_ConstantBuffer, // 업데이트할 상수 버퍼 객체
0, // 업데이트할 서브리소스 인덱스 (0이면 첫 번째 서브리소스)
nullptr, // 업데이트할 영역 (nullptr이면 전체 영역 업데이트)
&cb, // 업데이트할 데이터의 포인터 (상수 버퍼 구조체의 주소)
0, // 행렬의 행 크기 (0이면 기본값 사용)
0); // 행렬의 열 크기 (0이면 기본값 사용)
g_Context->VSSetConstantBuffers( // 상수 버퍼를 정점 쉐이더에 바인딩하는 함수
0, // 상수 버퍼 슬롯 번호 (0이면 첫 번째 슬롯)
1, // 상수 버퍼의 개수 (1이면 하나의 상수 버퍼 사용)
&g_ConstantBuffer); // 상수 버퍼 배열 (하나의 상수 버퍼를 사용할 때는 버퍼 포인터의 주소를 전달)
g_Context->Draw( // 정점 데이터를 사용하여 도형을 그리는 함수
3, // 그릴 정점의 개수 (삼각형을 그리기 위해 3개의 정점 사용)
0); // 정점 데이터의 시작 위치 (버퍼의 처음부터 사용)
}
void DrawCube(XMMATRIX world, XMMATRIX view, XMMATRIX projection) // 큐브를 그리는 함수 (월드 행렬과 뷰 행렬을 인자로 받아 큐브를 그리는 함수)
{
ConstantBuffer cb; // 상수 버퍼 구조체 생성 (쉐이더에서 사용할 상수 데이터를 저장하는 구조체)
XMStoreFloat4x4( // 회전 행렬을 상수 버퍼 구조체에 저장하는 함수
&cb.World, // 상수 버퍼 구조체의 World 멤버 변수에 회전 행렬 저장
XMMatrixTranspose(world)); // 회전 행렬을 전치(transpose)하여 상수 버퍼 구조체에 저장 (Direct3D 11에서는 행렬을 전치하여 저장해야 함)
XMStoreFloat4x4( // 뷰 행렬을 상수 버퍼 구조체에 저장하는 함수
&cb.View, // 상수 버퍼 구조체의 View 멤버 변수에 뷰 행렬 저장
XMMatrixTranspose(view)); // 뷰 행렬을 전치하여 상수 버퍼 구조체에 저장 (Direct3D 11에서는 행렬을 전치하여 저장해야 함)
XMStoreFloat4x4( // 투영 행렬을 상수 버퍼 구조체에 저장하는 함수
&cb.Projection, // 상수 버퍼 구조체의 Projection 멤버 변수에 투영 행렬 저장
XMMatrixTranspose(projection)); // 투영 행렬을 전치하여 상수 버퍼 구조체에 저장 (Direct3D 11에서는 행렬을 전치하여 저장해야 함)
g_Context->UpdateSubresource( // 상수 버퍼의 데이터를 업데이트하는 함수
g_ConstantBuffer, // 업데이트할 상수 버퍼 객체
0, // 업데이트할 서브리소스 인덱스 (0이면 첫 번째 서브리소스)
nullptr, // 업데이트할 영역 (nullptr이면 전체 영역 업데이트)
&cb, // 업데이트할 데이터의 포인터 (상수 버퍼 구조체의 주소)
0, // 행렬의 행 크기 (0이면 기본값 사용)
0); // 행렬의 열 크기 (0이면 기본값 사용)
g_Context->VSSetConstantBuffers( // 상수 버퍼를 정점 쉐이더에 바인딩하는 함수
0, // 상수 버퍼 슬롯 번호 (0이면 첫 번째 슬롯)
1, // 상수 버퍼의 개수 (1이면 하나의 상수 버퍼 사용)
&g_ConstantBuffer); // 상수 버퍼 배열 (하나의 상수 버퍼를 사용할 때는 버퍼 포인터의 주소를 전달)
g_Context->DrawIndexed( // 인덱스 버퍼를 사용하여 도형을 그리는 함수
36, // 그릴 인덱스의 개수 (정육면체를 그리기 위해 36개의 인덱스 사용)
0, // 인덱스 버퍼의 시작 위치 (0이면 버퍼의 처음부터 사용)
0); // 정점 데이터의 시작 위치 (버퍼의 처음부터 사용)
}
bool InitShader()
{
ID3DBlob* vsBlob = nullptr; // 정점 쉐이더 컴파일 결과를 저장할 Blob 객체 포인터
// =========================
// Vertex Shader
// =========================
HRESULT hr = D3DCompileFromFile(
L"VertexShader.hlsl", // 컴파일할 쉐이더 파일 경로
nullptr, // 쉐이더 컴파일에 사용할 매크로 정의 (nullptr이면 매크로 정의 없음)
nullptr, // 쉐이더 컴파일에 사용할 포함 파일 시스템 (nullptr이면 기본 포함 파일 시스템 사용)
"VSMain", // 쉐이더의 진입점 함수 이름 (쉐이더 코드에서 VSMain이라는 함수가 정점 쉐이더의 진입점으로 정의되어 있어야 함)
"vs_5_0", // 쉐이더 모델 버전 (vs_5_0은 Direct3D 11에서 지원하는 정점 쉐이더 모델 버전)
0, // 컴파일 옵션 (0이면 기본 옵션 사용)
0, // 컴파일 옵션 (0이면 기본 옵션 사용)
&vsBlob, // 컴파일된 쉐이더 코드를 저장할 Blob 객체 포인터
nullptr); // 컴파일 에러 메시지를 저장할 Blob 객체 포인터 (nullptr이면 에러 메시지 저장 안함)
if (FAILED(hr)) // 쉐이더 컴파일이 실패하면 false 반환
{
return false; // 초기화 실패
}
hr = g_Device->CreateVertexShader( // 컴파일된 쉐이더 코드를 사용하여 정점 쉐이더 객체를 생성하는 함수
vsBlob->GetBufferPointer(), // 컴파일된 쉐이더 코드의 포인터
vsBlob->GetBufferSize(), // 컴파일된 쉐이더 코드의 크기
nullptr, // 클래스 인스턴스화 인터페이스 (nullptr이면 사용 안함)
&g_VertexShader); // 생성된 정점 쉐이더 객체를 g_VertexShader 포인터에 저장
if (FAILED(hr)) // 정점 쉐이더 객체 생성이 실패하면 false 반환
{
return false; // 초기화 실패
}
D3D11_INPUT_ELEMENT_DESC layout[] = // 정점 데이터의 구조를 GPU에 알려주는 입력 레이아웃 설명 배열 (각 요소는 정점 데이터의 한 속성을 설명)
{
{
"POSITION", // 정점 데이터의 의미 (쉐이더 코드에서 POSITION이라는 의미로 사용됨)
0, // 정점 데이터의 인덱스 (같은 의미의 데이터가 여러 개 있을 때 구분하기 위한 인덱스, 0이면 첫 번째 POSITION 데이터)
DXGI_FORMAT_R32G32B32_FLOAT, // 정점 데이터의 형식 (3개의 float으로 x, y, z 좌표를 나타냄)
0, // 정점 버퍼의 슬롯 번호 (0번 정점 버퍼)
0, // 정점 데이터 시작 위치
D3D11_INPUT_PER_VERTEX_DATA, // 정점마다 하나씩 데이터를 제공하는 방식
0 // Instance Data Step Rate (인스턴스 데이터 사용 안함)
},
{
"COLOR", // 정점 데이터의 의미 (쉐이더 코드에서 COLOR이라는 의미로 사용됨)
0, // 정점 데이터의 인덱스 (같은 의미의 데이터가 여러 개 있을 때 구분하기 위한 인덱스, 0이면 첫 번째 COLOR 데이터)
DXGI_FORMAT_R32G32B32_FLOAT, // 정점 데이터의 형식 (3개의 float으로 r, g, b 색상값을 나타냄)
0, // 정점 버퍼의 슬롯 번호 (0번 정점 버퍼)
12, // 정점 데이터 시작 위치 (POSITION 데이터가 float x,y,z 12바이트이므로 COLOR 데이터는 12바이트 뒤에 시작)
D3D11_INPUT_PER_VERTEX_DATA, // 정점마다 하나씩 데이터를 제공하는 방식
0 // Instance Data Step Rate (인스턴스 데이터 사용 안함)
}
};
// =========================
// Input Layout
// =========================
hr = g_Device->CreateInputLayout( // 입력 레이아웃 객체 생성
layout, // 입력 레이아웃 설명 배열
2, // 입력 레이아웃 설명 배열의 요소 개수 (POSITION, COLOR)
vsBlob->GetBufferPointer(), // 컴파일된 쉐이더 코드의 포인터 (입력 레이아웃이 어떤 쉐이더와 호환되는지 확인하기 위해 필요)
vsBlob->GetBufferSize(), // 컴파일된 쉐이더 코드의 크기 (입력 레이아웃이 어떤 쉐이더와 호환되는지 확인하기 위해 필요)
&g_InputLayout); // 생성된 입력 레이아웃 객체를 g_InputLayout 포인터에 저장
if(FAILED(hr))
{
return false;
}
vsBlob->Release(); // 컴파일된 쉐이더 코드를 저장한 Blob 객체 해제 (메모리 누수 방지)
// =========================
// Pixel Shader
// =========================
ID3DBlob* psBlob = nullptr; // 픽셀 쉐이더 컴파일 결과를 저장할 Blob 객체 포인터
hr = D3DCompileFromFile( // 픽셀 쉐이더 컴파일 함수
L"PixelShader.hlsl", // 컴파일할 쉐이더 파일 경로
nullptr, // 쉐이더 컴파일에 사용할 매크로 정의 (nullptr이면 매크로 정의 없음)
nullptr, // 쉐이더 컴파일에 사용할 포함 파일 시스템 (nullptr이면 기본 포함 파일 시스템 사용)
"PSMain", // 쉐이더의 진입점 함수 이름 (쉐이더 코드에서 PSMain이라는 함수가 픽셀 쉐이더의 진입점으로 정의되어 있어야 함)
"ps_5_0", // 쉐이더 모델 버전 (ps_5_0은 Direct3D 11에서 지원하는 픽셀 쉐이더 모델 버전)
0, // 컴파일 옵션 (0이면 기본 옵션 사용)
0, // 컴파일 옵션 (0이면 기본 옵션 사용)
&psBlob, // 컴파일된 쉐이더 코드를 저장할 Blob 객체 포인터
nullptr); // 컴파일 에러 메시지를 저장할 Blob 객체 포인터 (nullptr이면 에러 메시지 저장 안함)
if (FAILED(hr))
{
psBlob->Release(); // 컴파일된 쉐이더 코드를 저장한 Blob 객체 해제 (메모리 누수 방지)
return false;
}
hr = g_Device->CreatePixelShader( // 컴파일된 쉐이더 코드를 사용하여 픽셀 쉐이더 객체를 생성하는 함수
psBlob->GetBufferPointer(), // 컴파일된 쉐이더 코드의 포인터
psBlob->GetBufferSize(), // 컴파일된 쉐이더 코드의 크기
nullptr, // 클래스 인스턴스화 인터페이스 (nullptr이면 사용 안함)
&g_PixelShader); // 생성된 픽쉘 쉐이더 객체를 g_PixelShader 포인터에 저장
if(FAILED(hr))
{
return false;
}
psBlob->Release(); // 컴파일된 쉐이더 코드를 저장한 Blob 객체 해제 (메모리 누수 방지)
return true; // 초기화 성공
}
bool InitGeometry() // 버퍼를 초기화하는 함수 (삼각형을 그리기 위한 정점 데이터를 GPU에 업로드하는 함수)
{
// 정점 버퍼
D3D11_BUFFER_DESC bd = {}; // 버퍼 설명 구조체 (GPU 버퍼를 생성하기 위한 설정을 저장하는 구조체)
bd.Usage = D3D11_USAGE_DEFAULT; // 버퍼 기본 사용 방식 (CPU가 자주 접근하지 않고 GPU가 주로 사용하는 버퍼)
bd.ByteWidth = sizeof(vertices); // 버퍼의 크기 (정점 데이터의 전체 크기)
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; // 버퍼의 용도 (정점 버퍼로 사용)
D3D11_SUBRESOURCE_DATA initData = {}; // 초기 데이터 구조체 (버퍼에 업로드할 초기 데이터를 저장하는 구조체)
initData.pSysMem = vertices; // 초기 데이터로 사용할 정점 데이터의 포인터
HRESULT hr = g_Device->CreateBuffer( // GPU 버퍼를 생성하는 함수
&bd, // 버퍼 설명 구조체
&initData, // 초기 데이터 구조체
&g_VertexBuffer); // 생성된 버퍼 객체를 g_VertexBuffer 포인터에 저장
if (FAILED(hr)) // 버퍼 생성이 실패하면 false 반환
{
return false; // 초기화 실패
}
// 상수 버퍼
D3D11_BUFFER_DESC cbd = {}; // 상수 버퍼 설명 구조체 (GPU 상수 버퍼를 생성하기 위한 설정을 저장하는 구조체)
cbd.Usage = D3D11_USAGE_DEFAULT; // 상수 버퍼 기본 사용 방식 (CPU가 자주 접근하지 않고 GPU가 주로 사용하는 버퍼)
cbd.ByteWidth = sizeof(ConstantBuffer); // 상수 버퍼의 크기 (상수 버퍼 구조체의 크기)
cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; // 상수 버퍼의 용도 (상수 버퍼로 사용)
HRESULT chr = g_Device->CreateBuffer( // GPU 상수 버퍼를 생성하는 함수
&cbd, // 상수 버퍼 설명 구조체
nullptr, // 초기 데이터 구조체 (nullptr이면 초기 데이터 없음)
&g_ConstantBuffer); // 생성된 상수 버퍼 객체를 g_ConstantBuffer 포인터에 저장
if (FAILED(chr)) // 상수 버퍼 생성이 실패하면 false 반환
{
return false;
}
// 인덱스 버퍼
D3D11_BUFFER_DESC ibd = {}; // 인덱스 버퍼 설명 구조체 (GPU 인덱스 버퍼를 생성하기 위한 설정을 저장하는 구조체)
ibd.Usage = D3D11_USAGE_DEFAULT; // 인덱스 버퍼 기본 사용 방식 (CPU가 자주 접근하지 않고 GPU가 주로 사용하는 버퍼)
ibd.ByteWidth = sizeof(indices); // 인덱스 버퍼의 크기 (인덱스 데이터의 전체 크기)
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER; // 인덱스 버퍼의 용도 (인덱스 버퍼로 사용)
D3D11_SUBRESOURCE_DATA indexData = {}; // 초기 데이터 구조체 (버퍼에 업로드할 초기 데이터를 저장하는 구조체)
indexData.pSysMem = indices; // 초기 데이터로 사용할 인덱스 데이터의 포인터
HRESULT ihr = g_Device->CreateBuffer( // GPU 인덱스 버퍼를 생성하는 함수
&ibd, // 인덱스 버퍼 설명 구조체
&indexData, // 초기 데이터 구조체
&g_IndexBuffer); // 생성된 인덱스 버퍼 객체를 g_IndexBuffer 포인터에 저장
if (FAILED(ihr)) // 인덱스 버퍼 생성이 실패하면 false 반환
{
return false;
}
D3D11_VIEWPORT vp = {}; // 뷰포트 구조체 (화면에 그려질 영역을 정의하는 구조체)
vp.Width = 1280.0f; // 뷰포트의 너비 (화면에 그려질 영역의 너비)
vp.Height = 720.0f; // 뷰포트의 높이
vp.MinDepth = 0.0f; // 뷰포트의 최소 깊이 (화면에 그려질 영역의 깊이 범위의 최소값)
vp.MaxDepth = 1.0f; // 뷰포트의 최대 깊이 (화면에 그려질 영역의 깊이 범위의 최대값)
vp.TopLeftX = 0.0f; // 뷰포트의 왼쪽 상단 X 좌표 (화면에 그려질 영역의 왼쪽 상단 모서리의 X 좌표)
vp.TopLeftY = 0.0f; // 뷰포트의 왼쪽 상단 Y 좌표 (화면에 그려질 영역의 왼쪽 상단 모서리의 Y 좌표)
g_Context->RSSetViewports( // GPU에 뷰포트를 설정하는 함수
1, // 설정할 뷰포트의 개수 (1이면 하나의 뷰포트 설정)
&vp); // 설정할 뷰포트 배열 (하나의 뷰포트를 사용할 때는 뷰포트 구조체의 주소를 전달)
return true; // 초기화 성공
}
// Direct3D 11 초기화 함수
bool InitD3D(HWND hwnd)
{
DXGI_SWAP_CHAIN_DESC sd = {}; // swap chain을 생성하기 위한 구조체
sd.BufferCount = 1; // 버퍼 개수 (더블 버퍼링이므로 1)
sd.BufferDesc.Width = 1280; // 버퍼의 너비
sd.BufferDesc.Height = 720; // 버퍼의 높이
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // 버퍼의 픽셀 형식 (RGBA 각각 8비트)
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // 버퍼의 용도 (렌더 타겟으로 사용)
sd.OutputWindow = hwnd; // 버퍼가 그려질 윈도우 핸들
sd.SampleDesc.Count = 1; // 멀티샘플링 카운트 (1이면 멀티샘플링 사용 안함. MSAA는 안티앨리어싱 게임에서 계단현상 제거하는 옵션)
sd.Windowed = TRUE; // 창 모드로 실행
HRESULT hr = D3D11CreateDeviceAndSwapChain( // Direct3D 11 장치와 swap chain을 생성하는 함수
nullptr, // 기본 어댑터 사용 (첫 번째 GPU)
D3D_DRIVER_TYPE_HARDWARE, // 하드웨어 가속을 사용하는 드라이버 타입 (GPU 사용)
nullptr, // 소프트웨어 렌더러 사용 안함
0, // 생성 옵션 (디버그 모드 등)
nullptr, // 피처 레벨 배열 (Direct3D 11.0, 11.1 등 지원하는 피처 레벨을 지정할 수 있음)
0, // 피처 레벨 (Direct3D 11.0, 11.1 등)
D3D11_SDK_VERSION, // SDK 버전 (항상 D3D11_SDK_VERSION 사용)
&sd, // swap chain 설명 구조체
&g_SwapChain, // 생성된 swap chain 객체를 받을 포인터
&g_Device, // 생성된 Direct3D 장치 객체를 받을 포인터
nullptr, // 피처 레벨을 받을 포인터 (필요 없으면 nullptr)
&g_Context); // 생성된 Direct3D 컨텍스트 객체를 받을 포인터
if (FAILED(hr)) // 생성이 실패하면 false 반환
return false;
ID3D11Texture2D* backBuffer = nullptr; // back buffer를 저장할 포인터
g_SwapChain->GetBuffer( // swap chain이 가지고 있는 back buffer를 가져오는 함수
0, // 버퍼 인덱스 (0이면 첫 번째 버퍼)
__uuidof(ID3D11Texture2D), // 가져올 버퍼의 인터페이스 ID (ID3D11Texture2D)
(void**)&backBuffer); // 가져온 버퍼를 저장할 포인터
g_Device->CreateRenderTargetView( // back buffer를 렌더 타겟 뷰로 만드는 함수
backBuffer, // 렌더 타겟 뷰로 만들 텍스처 (back buffer)
nullptr, // 렌더 타겟 뷰 설명 (nullptr이면 기본값 사용)
&g_RTV); // 생성된 렌더 타겟 뷰 객체를 g_RTV 포인터에 저장
backBuffer->Release(); // Back buffer는 더 이상 필요 없으므로 해제
D3D11_TEXTURE2D_DESC depthDesc = {}; // 깊이 스텐실 버퍼를 생성하기 위한 구조체
depthDesc.Width = 1280; // 깊이 스텐실 버퍼의 너비
depthDesc.Height = 720; // 깊이 스텐실 버퍼의 높이
depthDesc.MipLevels = 1; // 깊이 스텐실 버퍼의 MIP 맵 레벨 수 (1이면 MIP 맵 사용 안함)
depthDesc.ArraySize = 1; // 깊이 스텐실 버퍼의 배열 크기 (1이면 단일 텍스처)
depthDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; // 깊이 스텐실 버퍼의 픽셀 형식 (24비트 깊이 + 8비트 스텐실)
depthDesc.SampleDesc.Count = 1; // 멀티샘플링 카운트 (1이면 멀티샘플링 사용 안함)
depthDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; // 깊이 스텐실 버퍼의 용도 (깊이 스텐실 버퍼로 사용)
g_Device->CreateTexture2D(
&depthDesc, // 깊이 스텐실 버퍼 설명 구조체
nullptr, // 초기 데이터 (nullptr이면 초기 데이터 없음)
&g_DepthStencilBuffer); // 생성된 깊이 스텐실 버퍼 객체를 g_DepthStencilBuffer 포인터에 저장
g_Device->CreateDepthStencilView( // 깊이 스텐실 뷰를 생성하는 함수
g_DepthStencilBuffer, // 깊이 스텐실 버퍼를 뷰로 만들 텍스처
nullptr, // 깊이 스텐실 뷰 설명 (nullptr이면 기본값 사용)
&g_DSV); // 생성된 깊이 스텐실 뷰 객체를 g_DSV 포인터에 저장
return true; // 초기화 성공
}
void Render() // RGB 색상값과 알파값을 포함하는 4개의 요소로 구성된 배열 (RGBA)
{
XMVECTOR camPos = // 카메라 위치를 저장할 XMVECTOR 타입 변수
XMLoadFloat3(&g_CameraLocation); // XMFLOAT3 타입의 g_CameraLocation 변수를 XMVECTOR 타입으로 변환하여 camPos에 저장
XMVECTOR forward = // 카메라의 전방 방향을 저장할 XMVECTOR 타입 변수
XMVectorSet( // 카메라의 전방 방향 벡터를 계산하는 함수
cosf(g_Pitch) * sinf(g_Yaw), // X 좌표 (카메라의 피치와 요를 이용하여 계산)
sinf(g_Pitch), // Y 좌표 (카메라의 피치를 이용하여 계산)
cosf(g_Pitch) * cosf(g_Yaw), // Z 좌표 (카메라의 피치와 요를 이용하여 계산)
0.0f); // W 좌표 (카메라의 전방 방향 벡터는 방향 벡터이므로 W 좌표는 0으로 설정)
forward = XMVector3Normalize(forward); // 카메라의 전방 방향 벡터를 정규화하여 forward에 저장 (정규화는 벡터의 길이를 1로 만드는 과정)
XMVECTOR right = // 카메라의 우방 방향을 저장할 XMVECTOR 타입 변수
XMVector3Normalize( // 카메라의 우방 방향 벡터를 정규화하여 right에 저장
XMVector3Cross(worldUp, forward)); // 카메라의 우방 방향 벡터를 계산하는 함수 (월드 좌표계에서의 상방 방향 벡터와 전방 방향 벡터의 외적을 계산하여 우방 방향 벡터를 구함)
XMVECTOR up = XMVector3Cross(forward, right); // 카메라의 상방 방향을 저장할 XMVECTOR 타입 변수 (우방 방향 벡터와 전방 방향 벡터의 외적을 계산하여 상방 방향 벡터를 구함)
XMVECTOR lookAt = camPos + forward; // 카메라가 바라보는 지점을 저장할 XMVECTOR 타입 변수 (카메라 위치 + 전방 방향 벡터)
float speed = 0.01f; // 카메라 이동 속도 (키보드 입력에 따라 카메라가 이동하는 속도를 조절하는 변수)
if (GetAsyncKeyState('W') & 0x8000) // W 키가 눌렸는지 확인하는 함수 (0x8000은 키가 눌렸음을 나타내는 비트 마스크)
camPos += forward * speed; // 카메라 위치를 전방 방향으로 이동 (W 키를 누르면 카메라가 전방으로 이동)
if (GetAsyncKeyState('S') & 0x8000)
camPos -= forward * speed;
if (GetAsyncKeyState('A') & 0x8000)
camPos -= right * speed;
if (GetAsyncKeyState('D') & 0x8000)
camPos += right * speed;
if (GetAsyncKeyState('Q') & 0x8000)
camPos -= worldUp * speed;
if (GetAsyncKeyState('E') & 0x8000)
camPos += worldUp * speed;
if (GetAsyncKeyState(VK_RBUTTON) & 0x8000) // 마우스 오른쪽 버튼이 눌렸는지 확인
{
if (!g_IsRightMouseDown) // 마우스 오른쪽 버튼이 처음 눌렸을 때만 처리
{
g_IsRightMouseDown = true; // 마우스 오른쪽 버튼이 눌렸음을 표시
GetCursorPos(&g_LastMousePos); // 마우스 커서의 현재 위치를 g_LastMousePos에 저장
}
POINT curMousePos; // 마우스 커서의 현재 위치를 저장할 POINT 구조체
GetCursorPos(&curMousePos); // 마우스 커서의 현재 위치를 currentPos에 저장
int deltaX = curMousePos.x - g_LastMousePos.x; // 마우스 커서의 X축 이동 거리 계rm
int deltaY = curMousePos.y - g_LastMousePos.y; // 마우스 커서의 Y축 이동 거리 계산
float sensitivity = 0.003f; // 마우스 이동 감도 설정
g_Yaw += deltaX * sensitivity; // 마우스 이동 거리에 따라 Yaw 값 변경
g_Pitch -= deltaY * sensitivity; // 마우스 이동 거리에 따라 Pitch 값 변경
g_Pitch = std::clamp( // Pitch 값을 -90도에서 90도로 제한
g_Pitch, // 현재 Pitch 값
-XM_PIDIV2 + 0.01f, // 최소값 (-90도 + 0.01)
XM_PIDIV2 - 0.01f); // 최대값 (90도 - 0.01)
g_LastMousePos = curMousePos; // g_LastMousePos를 현재 마우스 위치로 업데이트
}
else
{
g_IsRightMouseDown = false; // 마우스 오른쪽 버튼이 눌리지 않았음을 표시
}
XMMATRIX view = // 뷰 공간의 좌표를 정의하는 행렬
XMMatrixLookAtLH( // 왼손 좌표계 기준의 뷰 행렬 생성 함수
camPos, // 카메라의 위치 벡터
lookAt, // 카메라가 바라보는 지점 벡터 (카메라 위치 + 전방 방향 벡터)
up); // 카메라의 상방 방향 벡터 (월드 좌표계에서의 상방 방향 벡터)
float color[4] =
{
0.0f,
0.3f,
0.8f,
1.0f
};
g_Context->OMSetRenderTargets( // 렌더 타겟을 설정하는 함수
1, // 렌더 타겟의 개수 (1이면 하나의 렌더 타겟 사용)
&g_RTV, // 출력 대상
g_DSV); // DepthStencilBuffer (깊이 버퍼 사용 안함)
g_Context->ClearRenderTargetView( // 렌더 타겟 뷰를 지정된 색상으로 지우는 함수
g_RTV, // 지울 렌더 타겟 뷰
color); // 지울 색상 (RGBA)
g_Context->ClearDepthStencilView( // 깊이 스텐실 뷰를 지우는 함수
g_DSV, // 지울 깊이 스텐실 뷰
D3D11_CLEAR_DEPTH, // 지울 깊이 스텐실 뷰의 종류 (깊이 버퍼만 지움)
1.0f, // 깊이 버퍼를 지울 때 사용할 값 (1.0f이면 가장 먼 거리)
0); // 스텐실 버퍼를 지울 때 사용할 값 (0이면 스텐실 버퍼를 지우지 않음)
g_Context->IASetInputLayout(g_InputLayout); // 입력 레이아웃 설정 (GPU가 정점 데이터를 어떻게 해석할지 설정)
UINT stride = sizeof(Vertex); // 정점 데이터의 크기 (한 정점이 차지하는 바이트 수)
UINT offset = 0; // 정점 데이터의 시작 위치 (버퍼의 처음부터 사용)
g_Context->IASetVertexBuffers( // 정점 버퍼 설정 (GPU에 정점 데이터를 제공하는 함수)
0, // 정점 버퍼 슬롯 번호 (0이면 첫 번째 슬롯)
1, // 정점 버퍼의 개수 (1이면 하나의 버퍼 사용)
&g_VertexBuffer, // 정점 버퍼 배열 (하나의 버퍼를 사용할 때는 버퍼 포인터의 주소를 전달)
&stride, // 정점 데이터의 크기 (한 정점이 차지하는 바이트 수)
&offset); // 정점 데이터의 시작 위치 (버퍼의 처음부터 사용)
g_Context->IASetIndexBuffer( // 인덱스 버퍼 설정 (GPU에 인덱스 데이터를 제공하는 함수)
g_IndexBuffer, // 사용할 인덱스 버퍼 객체
DXGI_FORMAT_R32_UINT, // 인덱스 데이터의 형식 (32비트 부호 없는 정수)
0); // 인덱스 데이터의 시작 위치 (버퍼의 처음부터 사용)
g_Context->IASetPrimitiveTopology( // 정점 데이터를 어떻게 연결하여 도형을 만들지 설정하는 함수
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // 정점 데이터를 3개씩 묶어서 삼각형을 만드는 방식 (각 3개의 정점이 하나의 삼각형을 형성)
g_Context->VSSetShader( // 정점 쉐이더 설정 (GPU에 정점 쉐이더를 사용하도록 하는 함수)
g_VertexShader, // 사용할 정점 쉐이더 객체
nullptr, // 클래스 인스턴스화 인터페이스 (nullptr이면 사용 안함)
0); // 추가 옵션 (0이면 기본값 사용)
g_Context->PSSetShader( // 픽셀 쉐이더 설정 (GPU에 픽셀 쉐이더를 사용하도록 하는 함수)
g_PixelShader, // 사용할 픽셀 쉐이더 객체
nullptr, // 클래스 인스턴스화 인터페이스 (nullptr이면 사용 안함)
0); // 추가 옵션 (0이면 기본값 사용)
g_Context->IASetIndexBuffer( // 인덱스 버퍼 설정 (GPU에 인덱스 데이터를 제공하는 함수)
g_IndexBuffer, // 사용할 인덱스 버퍼 객체
DXGI_FORMAT_R32_UINT, // 인덱스 데이터의 형식 (32비트 부호 없는 정수)
0); // 인덱스 데이터의 시작 위치 (버퍼의 처음부터 사용)
g_Angle = XMConvertToRadians(45.0f); // 회전 각도를 라디안 단위로 변환하여 g_Angle 변수에 저장 (45도)
XMMATRIX world = // 월드공간의 좌표를 정의하는 행렬
XMMatrixScaling( // 크기 조절
1.0f, // x축 크기
1.0f, // y축 크기
1.0f) * // z축 크기
XMMatrixRotationX(g_Angle) * // 회전
XMMatrixRotationY(g_Angle) * // 회전
XMMatrixRotationZ(g_Angle) * // 회전
XMMatrixTranslation( // 이동
0.0f, // 이동할 x 좌표
0.0f, // 이동할 y 좌표
0.0f); // 이동할 z 좌표
XMMATRIX projection = // 투영 공간의 좌표를 정의하는 행렬
XMMatrixPerspectiveFovLH( // 원근 투영 행렬 생성 함수 (왼손 좌표계 기준)
XMConvertToRadians(60.0f), // 수직 시야각 (60도)
1280.0f / 720.0f, // 화면의 가로 세로 비율 (1280 / 720)
0.1f, // 근평면 (카메라에서 가장 가까운 거리), 이상의 값만 렌더링
20.0f); // 원평면 (카메라에서 가장 먼 거리), 미만의 값만 렌더링
DrawCube(world, view,projection);
//g_Angle = XMConvertToRadians(90.0f);
//world = // 월드공간의 좌표를 정의하는 행렬
// XMMatrixScaling( // 크기 조절
// 1.0f, // x축 크기
// 1.0f, // y축 크기
// 1.0f) * // z축 크기
// XMMatrixRotationZ(g_Angle) * // 회전
// XMMatrixTranslation( // 이동
// 5.0f, // 이동할 x 좌표
// 0.0f, // 이동할 y 좌표
// 0.0f); // 이동할 z 좌표
//DrawCube(world, view, projection);
//world = // 월드공간의 좌표를 정의하는 행렬
// XMMatrixScaling( // 크기 조절
// 1.0f, // x축 크기
// 1.0f, // y축 크기
// 1.0f) * // z축 크기
// XMMatrixRotationZ(g_Angle) * // 회전
// XMMatrixTranslation( // 이동
// -5.0f, // 이동할 x 좌표
// 0.0f, // 이동할 y 좌표
// 0.0f); // 이동할 z 좌표
//DrawCube(world, view, projection);
//world = // 월드공간의 좌표를 정의하는 행렬
// XMMatrixScaling( // 크기 조절
// 1.0f, // x축 크기
// 1.0f, // y축 크기
// 1.0f) * // z축 크기
// XMMatrixRotationZ(g_Angle) * // 회전
// XMMatrixTranslation( // 이동
// 0.0f, // 이동할 x 좌표
// 0.0f, // 이동할 y 좌표
// 5.0f); // 이동할 z 좌표
//DrawCube(world, view, projection);
g_SwapChain->Present( // 화면에 그려진 버퍼를 표시하는 함수
1, // VSync 사용 (1이면 모니터의 수직 동기화에 맞춰 버퍼를 교체, 0이면 즉시 교체)
0); // 추가 옵션 (0이면 기본값 사용)
XMStoreFloat3(&g_CameraLocation, camPos); // XMVECTOR 타입의 camPos를 XMFLOAT3 타입으로 변환하여 g_CameraLocation에 저장
}
void Cleanup() // 객체 해제 함수
{
if (g_VertexBuffer) g_VertexBuffer->Release(); // 정점 버퍼 해제
if (g_InputLayout) g_InputLayout->Release(); // 입력 레이아웃 해제
if (g_VertexShader) g_VertexShader->Release(); // 정점 쉐이더 해제
if (g_PixelShader) g_PixelShader->Release(); // 픽셀 쉐이더 해제
if (g_RTV) g_RTV->Release(); // 렌더 타겟 뷰 해제
if (g_SwapChain) g_SwapChain->Release(); // swap chain 해제
if (g_Context) g_Context->Release(); // GPU 컨텍스트 해제
if (g_Device) g_Device->Release(); // GPU 장치 해제
if (g_ConstantBuffer) g_ConstantBuffer->Release(); // 상수 버퍼 해제
if (g_DSV) g_DSV->Release(); // 깊이 스텐실 뷰 해제
if (g_DepthStencilBuffer) g_DepthStencilBuffer->Release(); // 깊이 스텐실 버퍼 해제
if (g_IndexBuffer) g_IndexBuffer->Release(); // 인덱스 버퍼 해제
}
LRESULT CALLBACK WndProc( // 윈도우 메시지를 처리하는 함수
HWND hwnd, // 윈도우 핸들
UINT msg, // 메시지 코드
WPARAM wParam, // 메시지에 대한 추가 정보 (예: 키보드 입력, 마우스 클릭 등)
LPARAM lParam) // 메시지에 대한 추가 정보 (예: 키보드 입력, 마우스 클릭 등)
{
switch (msg) // 메시지 코드에 따라 처리할 작업을 결정
{
case WM_DESTROY: // 윈도우가 파괴될 때 발생하는 메시지
PostQuitMessage(0); // 메시지 루프에 WM_QUIT 메시지를 보내서 프로그램 종료를 알리는 함수
return 0; // 메시지 처리 완료를 알리는 반환값
}
return DefWindowProc( // 기본 윈도우 프로시저를 호출하여 처리되지 않은 메시지를 처리 (개발자가 직접 처리하지 않은 메시지는 운영체제가 기본적으로 처리하도록 하는 함수)
hwnd, // 윈도우 핸들
msg, // 메시지 코드
wParam, // 메시지에 대한 추가 정보
lParam); // 메시지에 대한 추가 정보
}
int WINAPI wWinMain( // 윈도우 애플리케이션 진입점 함수
HINSTANCE hInstance, // 프로그램 인스턴스 핸들
HINSTANCE, // 이전 인스턴스 핸들 (윈도우 95/98에서는 사용되었지만 현대 윈도우에서는 항상 nullptr)
PWSTR, // 명령줄 인수 (유니코드 문자열로 전달, 일반적으로 사용되지 않음)
int nCmdShow) // 창의 초기 표시 방법을 나타내는 정수 (예: SW_SHOW, SW_HIDE 등)
{
WNDCLASS wc = {}; // 윈도우 클래스 구조체 (윈도우의 속성과 동작을 정의하는 구조체)
wc.lpfnWndProc = WndProc; // 윈도우 프로시저 함수 포인터 (윈도우 메시지를 처리하는 함수)
wc.hInstance = hInstance; // 프로그램 인스턴스 핸들
wc.lpszClassName = L"MyWindow"; // 윈도우 클래스 이름 (윈도우를 생성할 때 이 이름을 사용하여 어떤 클래스의 윈도우를 생성할지 지정)
RegisterClass(&wc); // 윈도우 클래스를 등록하는 함수 (윈도우를 생성하기 전에 클래스 정보를 운영체제에 등록하여 나중에 이 클래스를 기반으로 윈도우를 생성할 수 있도록 하는 함수)
HWND hwnd = CreateWindow( // 윈도우를 생성하는 함수
L"MyWindow", // 생성할 윈도우의 클래스 이름 (RegisterClass에서 등록한 클래스 이름)
L"DX11 Study", // 생성할 윈도우의 제목 (윈도우 상단에 표시되는 텍스트)
WS_OVERLAPPEDWINDOW, // 윈도우 스타일 (WS_OVERLAPPEDWINDOW는 일반적인 창 모양을 나타내는 스타일로, 제목 표시줄, 테두리, 최소화/최대화 버튼 등이 포함됨)
100, // 윈도우의 초기 X 위치
100, // 윈도우의 초기 Y 위치
1280, // 윈도우의 너비
720, // 윈도우의 높이
nullptr, // 부모 윈도우 핸들 (nullptr이면 부모 윈도우가 없음)
nullptr, // 메뉴 핸들 (nullptr이면 메뉴가 없음)
hInstance, // 프로그램 인스턴스 핸들
nullptr); // 추가 매개변수 (일반적으로 사용되지 않음)
ShowWindow(hwnd, nCmdShow); // 윈도우를 화면에 표시하는 함수 (생성된 윈도우를 실제로 화면에 보이도록 하는 함수)
// nCmdShow 매개변수는 창의 초기 표시 방법을 나타내며, 일반적으로 wWinMain 함수의 매개변수로 전달된 값을 사용
if (!InitD3D(hwnd)) // Direct3D 11 초기화에 실패하면 프로그램을 종료하는 조건문
return -1; // 초기화 실패 시 -1을 반환하여 프로그램 종료
if(!InitShader()) // 쉐이더 초기화에 실패하면 프로그램을 종료하는 조건문
return -1; // 초기화 실패 시 -1을 반환하여 프로그램 종료
if(!InitGeometry()) // 정점 버퍼 초기화에 실패하면 프로그램을 종료하는 조건문
return -1; // 초기화 실패 시 -1을 반환하여 프로그램 종료
MSG msg = {}; // 윈도우 메시지를 저장하는 구조체 (윈도우 메시지 루프에서 메시지를 받아 처리하는 데 사용)
while (msg.message != WM_QUIT) // 프로그램이 종료될 때까지 메시지 루프를 계속 실행하는 조건문 (WM_QUIT 메시지가 발생하면 루프 종료)
{
if (PeekMessage( // 메시지 큐에서 메시지를 확인하는 함수
&msg, // 메시지를 저장할 구조체 포인터
nullptr, // 윈도우 핸들 (nullptr이면 모든 윈도우의 메시지를 확인)
0, // 메시지 범위의 최소값 (0이면 모든 메시지를 확인)
0, // 메시지 범위의 최대값 (0이면 모든 메시지를 확인)
PM_REMOVE)) // 메시지를 큐에서 제거하는 옵션 (PM_REMOVE는 메시지를 확인한 후 큐에서 제거, PM_NOREMOVE는 메시지를 확인하지만 큐에서 제거하지 않음)
{
TranslateMessage(&msg); // 키보드 입력 메시지를 문자 메시지로 변환하는 함수 (예: WM_KEYDOWN을 WM_CHAR로 변환)
DispatchMessage(&msg); // 메시지를 해당 윈도우 프로시저로 전달하는 함수 (예: WndProc 함수로 메시지를 전달하여 처리)
}
else
{
Render(); // 화면에 그리는 함수 (Direct3D 11을 사용하여 화면에 그래픽을 렌더링하는 함수)
// 메시지 큐에 처리할 메시지가 없을 때 Render 함수를 호출하여 화면을 계속 업데이트 (게임 루프의 핵심 부분)
}
}
Cleanup(); // Direct3D 11에서 사용한 리소스를 해제하는 함수 (프로그램 종료 전에 GPU 리소스를 정리하여 메모리 누수 방지)
return 0; // 프로그램이 정상적으로 종료되었음을 나타내는 반환값 (0은 성공적으로 종료되었음을 의미)
}
'그래픽' 카테고리의 다른 글
| Direct3D (13) / 큐브 여러개 생성하기 (0) | 2026.08.17 |
|---|---|
| 행렬을 Transpose하는 이유 (0) | 2026.07.07 |
| 'clamp': 'std'의 멤버가 아닙니다 에러코드 E0135 (0) | 2026.07.03 |
| Direct3D (11) / 카메라 이동 수정 (0) | 2026.07.03 |
| Direct3D (10) / 카메라 회전 (0) | 2026.07.02 |