오늘은 삼각형을 그려볼 것이다. 

 

삼각형 하나를 그리더라도 전체 파이프라인은 한번 거쳐야한다. 

 

 

일단 기하학적인 도형을 만들어주는 함수를 만들고 정점을 나타내줄 구조체도 선언해준다.

 

Stuct.h

#pragma once
#include "Types.h"


struct Vertex
{
	Vec3 position;		//12바이트 0부터시작
	Color color;		//12부터시작
};

 

 

정점 선언해주기 

정점은 -1,1 사이의 범위에서 선언해준다. -> 화면 상의 좌표때문에 

정점 정보까지는 아직 CPU에서의 영역, 

RAM<->CPU VRAM<->GPU

->VRAM에도 같은 정보를 만들어줘야한다. 

-> _device->CreateBuffer(); 마지막인자로 정점버퍼를 받는다 -> 이를 통해 정점버퍼 초기화

 

D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Usage = D3D11_USAGE_IMMUTABLE;			//디폴트- GPU만 읽고 쓸수있음 
IMMUTABLE GPU만 읽을 수 있다. 
DYNAMIC- GPU : 읽기 CPU: 쓰기 
STAGING - CPU->GPU 데이터전송

 

메모리에 있는 정점 넘겨주기 전체코드 

이렇게 되면 이제 _vertices가 가지고있던 정점 정보를 gpu쪽으로 넘겨줘서 이후에는 gpu만 read only할 수 있도록 한다. 

//정점정보
{
	_vertices.resize(3);

	_vertices[0].position = Vec3(-0.5f, -0.5f, 0.f);
	_vertices[0].color = Color(1.f, 0.f, 0.f, 1.f);
	_vertices[1].position = Vec3(0.f, 0.5f, 0.f);
	_vertices[1].color = Color(1.f, 0.f, 0.f, 1.f);
	_vertices[2].position = Vec3(0.5f, -0.5f, 0.f);
	_vertices[2].color = Color(1.f, 0.f, 0.f, 1.f);
}

//정점버퍼
{
	D3D11_BUFFER_DESC desc;
	ZeroMemory(&desc, sizeof(desc));
	desc.Usage = D3D11_USAGE_IMMUTABLE;			//gpu만 read only
	desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	desc.ByteWidth = (uint32)(sizeof(Vertex) * _vertices.size());

	D3D11_SUBRESOURCE_DATA data;
	ZeroMemory(&data, sizeof(data));
	data.pSysMem = _vertices.data();			//첫번째 시작주소 cpu값이 복사된다.

	_device->CreateBuffer(&desc,&data, _vertexBuffer.GetAddressOf());
}

 

 

이제 입력에 대한 정보를 명시해줘야한다. 

void Game::CreateInputLayout()
{
	//입력에 대한 정보 ~바이트부터 뛰면 칼러인지 
	D3D11_INPUT_ELEMENT_DESC layout[] =
	{
		{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0},
		{"COLOR",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0}
	};

	const int32 count = sizeof(layout)/sizeof(D3D11_INPUT_ELEMENT_DESC);
	_device->CreateInputLayout(layout,count,);
}

 

하지만 CreateInputLayout 함수의 매개변수에는 쉐이더에 관한 변수가 필요하다. 

그럼 쉐이더를 만들어주자 

쉐이더 -> 관련 코드를 넣어두는 하나의 파일

 

필터를 새로만들고 HLSL파일을 만들어보자 

쉐이더파일 생성

 

쉐이더

-> 1. 먼저 컴파일/ 빌드해서 cso파일을 사용 2.실행 순간에 코드를 읽어서 컴파일 -> 동적으로 사용

->먼저 만들어진걸 사용하는게 좋다. -> 문법적인 /오타 같은 오류를 컴파일 단계에서 알 수 있다. 

 

쉐이더 입력으로 들어오는 구조체부터 선언해주자 이때 InputLayout과 이름을 맞춰주자

struct VS_INPUT
{
    float4 position : POSITIONT;
    float4 color : COLOR;
};

 

쉐이더관련 코드를 완성해보자

정점 쉐이더와 픽셀 쉐이더 단계에 필요한 함수를 추가해준다.

struct VS_INPUT
{
    float4 position : POSITION;
    float4 color : COLOR;
};

struct VS_OUTPUT
{
    float4 position : SV_POSITION;      //시스템 VALUE  무조건 있어야한다.
    float4 color : COLOR;
};

//정점 쉐이더- 위치관련 -> 레스터라이저-정점바탕으로 도형만들고 내/외부 판단 및 보간
VS_OUTPUT VS(VS_INPUT input)
{
    VS_OUTPUT output;
    output.position = input.position;
    output.color = input.color;
    
    return output;
}

//모든 픽셀단위 대상 - 색상관련
float4 PS(VS_OUTPUT input) : SV_Target  //랜더 타켓하는 곳으로 보내주기
{
    
    
    return float4(1, 0, 0, 0);
}

 

그리고 이제 이 쉐이더를 가져올 함수를 만들자

만들기전에 정점/ 픽셀 쉐이더 관련 변수를 추가해준다. 

	//VS
	ComPtr<ID3D11VertexShader> _vertexShader = nullptr;
	ComPtr<ID3DBlob> _vsBlob = nullptr;
	//PS
	ComPtr<ID3D11PixelShader> _pixelShader = nullptr;
	ComPtr<ID3DBlob> _psBlob = nullptr;
void Game::LoadShaderFromFile(const wstring& path, const string& name, const string& version, ComPtr<ID3DBlob>& blob)
{
	const uint32 compileFlag = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;		//디버그 최적화 건너뛰기
	HRESULT hr = ::D3DCompileFromFile(
		path.c_str(),
		nullptr,
		D3D_COMPILE_STANDARD_FILE_INCLUDE,
		name.c_str(),
		version.c_str(),
		compileFlag,
		0,
		blob.GetAddressOf(),
		nullptr
	);

	CHECK(hr);
}

 

파일에 있던걸 가져와서 어떻게 작동하게 할지 건내줘야해서 가져오는 함수를

VS와 PS에서도 해야하기 때문에 관련 함수를 만들어 준다. 

void Game::CreateVS()
{
	LoadShaderFromFile(L"Default.hlsl", "VS", "vs_5_0", _vsBlob);

	HRESULT hr = _device->CreateVertexShader(_vsBlob->GetBufferPointer(),
		_vsBlob->GetBufferSize(), nullptr, _vertexShader.GetAddressOf());
	CHECK(hr);
}

void Game::CreatePS()
{
	LoadShaderFromFile(L"Default.hlsl", "PS", "ps_5_0", _psBlob);

	HRESULT hr = _device->CreatePixelShader(_psBlob->GetBufferPointer(),
		_psBlob->GetBufferSize(), nullptr, _pixelShader.GetAddressOf());
	CHECK(hr);
}

 

 

이제  Init 부분에 만든 함수들을 실행시키도록 넣어준다 .

 

void Game::Init(HWND hwnd)
{
	_hwnd = hwnd;
	_width = GWinSizeX;
	_height = GwinSizeY;


	CreateDeviceAndSwapChain();
	CreateRenderTargetView();
	SetViewport();

	//삼각형 그리기 파트
	CreateGeometry();
	CreateVS();
	CreateInputLayout();
	CreatePS();
}

 

 

그리고 실제로 그리기 부분은 렌더부분에서 이루어 지기때문에 파이프라인 단계에 맞게 채워준다.

void Game::Render()
{
	RenderBegin();			//초기화

	// IA - VS - RS - PS -OM
	//TODO : 그리기
	{
		uint32 stride = sizeof(Vertex);
		uint32 offset = 0;
		//IA - 세팅부분
		_deviceContext->IASetVertexBuffers(0, 1, _vertexBuffer.GetAddressOf(),&stride, &offset);
		_deviceContext->IASetInputLayout(_inputLayout.Get());
		_deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);		//삼각형으로 만들어주기

		//VS
		_deviceContext->VSSetShader(_vertexShader.Get(), nullptr, 0);		//이걸로 일하게 

		//RS

		//PS
		_deviceContext->PSSetShader(_pixelShader.Get(), nullptr, 0);
		//OM

		_deviceContext->Draw(_vertices.size(), 0);
	}

	RenderEnd();			//제출
}

 

실행화면 

 

 

만약 PS 단계에서 입력의 색을 따라 만들고 세 점을 RGB 하나씩 가지고 있도록 한다면 

 

//모든 픽셀단위 대상 - 색상관련
float4 PS(VS_OUTPUT input) : SV_Target  //랜더 타켓하는 곳으로 보내주기
{
    
    
    return input.color;
}

 

이런식으로 그라데이션 삼각형이 나오게 된다. 

-> 보간이 잘 이루어졌다. 

 

정점 / 자원 -> cpu만 가지고 있었는데 createVertexBuffer을 통해 gpu로 복사가 이루어진다.

gpu도 해당 자원을 가지고 있게 된다. 

IA - createVertexBuffer를 통해 자원을 사용하겠다는 의미

VS- 정점을 gpu에서 연산 처리 -> 정점에 대한 정보가 확정되어서 나가게 된다.

Rasterize- 삼각형있을 때 내/외부 판단, 보간 진행

PS- 모든 픽셀에 대한 색상 - 빛 / 그림자

랜더타켓 - 어디에다 그려줘

 

VS,PS- 세부적인 옵션을 건드릴 수 있도록하는 툴로 만들면 -> 머테리얼 

 

'게임공부 > Directx11' 카테고리의 다른 글

[Directx11][C++]4. 텍스처와 UV  (0) 2024.07.01
[Directx11]3.장치초기화  (0) 2024.06.27
[Directx11]2.초기설정  (0) 2024.06.26
[Directx11]그래픽스OT  (0) 2024.06.25
[Directx11]2.랜더링 파이프라인2  (0) 2024.06.21

+ Recent posts