DOTY

DirectX11. 3) Buffer, Shader I 본문

DirectX

DirectX11. 3) Buffer, Shader I

증식세포 2023. 6. 11. 17:09
728x90
반응형

0. Buffer / Shader

  • Buffer : 데이터를 저장하는 메모리 영역
  • Shader : GPU에서 실행되는 경우가 많으며 그래픽스 파이프라인의 각 단계에서 실행된다.

0-1. Vertex Buffer

3D 모델은 여러 개의 삼각형으로 구성된다. 이 모델을 구성하는 삼각형 꼭짓점들에 대한 정보를 Vertex Buffer라고 하는 데이터 배열에 넣어야 한다. 이를 활용해서 렌더링을 한다.

 

0-2. Index Buffer

Vertex Buffer와 비슷하지만 다른 버퍼로 모든 꼭짓점들을 저장하는 것이 아닌 꼭짓점들의 위치를 저장하는 것이다. Vertex Buffer보다 메모리를 절약할 수 있다는 장점이 있다.

 

0-3. Vertex Shader

Vertex Buffer의 꼭짓점을 3D로 변환해주기 위해 사용된다. 꼭짓점에 대한 계산들을 처리하게 된다. 

 

0-4. Pixel Shader

다각형의 색을 처리하기 위해 사용된다. 채색, 텍스쳐링, 조명 의 효과는 Pixel Shader에서 처리하게 된다. 

 

0-5. HLSL

Shader을 코딩하는데 사용되는 언어.

 

※ Model Class, Camera Class, Color Shader Class가 Framework에 추가된다.

 

1. ColorShaderClass.h

#pragma once
#ifndef _COLORSHADERCLASS_H_
#define _COLORSHADERCLASS_H_

#include <d3d11.h>
#include <d3dcompiler.h>
#include <directxmath.h>
#include <fstream>
using namespace DirectX;
using namespace std;

class ColorShaderClass
{
private:
	struct MatrixBufferType
	{
		XMMATRIX world;
		XMMATRIX view;
		XMMATRIX projection;
	};

public:
	ColorShaderClass();
	ColorShaderClass(const ColorShaderClass&);
	~ColorShaderClass();
	bool Initialize(ID3D11Device*, HWND);
	void Shutdown();
	bool Render(ID3D11DeviceContext*, int, XMMATRIX, XMMATRIX, XMMATRIX);

private:
	bool InitializeShader(ID3D11Device*, HWND, WCHAR*, WCHAR*);
	void ShutdownShader();
	void OutputShaderErrorMessage(ID3D10Blob*, HWND, WCHAR*);

	bool SetShaderParameters(ID3D11DeviceContext*, XMMATRIX, XMMATRIX, XMMATRIX);
	void RenderShader(ID3D11DeviceContext*, int);

private:
	ID3D11VertexShader* m_vertexShader;
	ID3D11PixelShader* m_pixelShader;
	ID3D11InputLayout* m_layout;
	ID3D11Buffer* m_matrixBuffer;
};

#endif

HSLS 셰이더를 호출하고 이를 활용해 GPU의 3D 모델을 그린다.

 

1-1. Initialize

셰이더에 대한 초기화 함수를 호출하는데 이를 위해서 color.vs, color.ps라는 HSLS 셰이더 파일의 이름을 전달한다.

 

1-1-1. Color.vs

// VertexShader

cbuffer MatrixBuffer
{
	matrix worldMatrix;
	matrix viewMatrix;
	matrix projectionMatrix;
};

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

 struct PixelInputType
 {
	float4 position : SV_POSITION;
	float4 color : COLOR;
 };

 PixelInputType ColorVertexShader(VertexInputType input)
 {
	PixelInputType output;

	input.position.w = 1.0f;

	output.position = mul(input.position, worldMatrix);
	output.position = mul(output.position, viewMatrix);
   	output.position = mul(output.position, projectionMatrix);
    
	output.color = input.color;
    
	return output;
 }

cBuffer MatrixBuffer : cBuffer은 버퍼의 개체 형식으로 Shader에게 전달되는 상수 데이터의 컨테이너 역할을 한다. 쉽게 말하자면 C++ 에는 struct라는 구조체가 있듯 HSLS에는 cBuffer라는 구조체가 있다고 보면 된다. 따라서 MatrixBuffer은     3개의 행렬을 전달하기 위한 구조체다.

 

struct Vertex(Pixel)InputType : float4 타입 두가지를 전달하기 위한 구조체. position = (x, y, z, 1)과 color = (r, g, b, a)를 전달하게 된다. color은 vertex와 pixel 두 가지에 작동된다. (다르게 사용해도 된다.)

 

PixelInputType ColorVertexShader(VertexInputType input) : 

input으로 처음 점의 위치를 가져와서 3가지의 행렬을 곱해준다. 모델의 변환을 나타내는 WorldMatrix, 뷰(카메라)의 변환을 나타내는 ViewMatrix, 프로젝션의 변환(투영의 변환)을 나타내는 projectionMatrix 가 순서대로 곱해져서 output.position이 정해진다. ( ※ 세 행렬의 곱(MVP Matrix)을 통해서 최종적으로 점이 찍히는 위치를 계산하여 변환하는 것을 MVP Transformation이라고 부른다.)

 

1-1-2. Color.ps

// Pixel Shader

struct PixelInputType
{
    float4 position : SV_POSITION;
    float4 color : COLOR;
};

float4 ColorPixelShader(PixelInputType input) : SV_TARGET
{
    return input.color;
}

화면에 렌더링 될 다각형에 각 픽셀을 그린다.

 

정점 셰이더에서 MVP Transformation을 통해 픽셀의 변환이 일어난 후에 각 정점의 색이 정해진다(ColorVertexShader). 이 점들은 GPU를 통해서 나머지 픽셀의 색들에 대한 보간이 이루어지고 그 점들을 SV_POSITION과 COLOR를 통해 픽셀 셰이더에 전달된다. 마지막으로 픽셀 셰이더는 GPU에서 처리된 픽셀들의 보간 된 값들을 결정짓는 역할을 하게 된다.

 

2. ColorShaderClass.h

#pragma once
#ifndef _COLORSHADERCLASS_H_
#define _COLORSHADERCLASS_H_

#include <d3d11.h>
#include <d3dcompiler.h>
#include <directxmath.h>
#include <fstream>
using namespace DirectX;
using namespace std;

class ColorShaderClass
{
private:
	struct MatrixBufferType
	{
		XMMATRIX world;
		XMMATRIX view;
		XMMATRIX projection;
	};

public:
	ColorShaderClass();
	ColorShaderClass(const ColorShaderClass&);
	~ColorShaderClass();
	bool Initialize(ID3D11Device*, HWND);
	void Shutdown();
	bool Render(ID3D11DeviceContext*, int, XMMATRIX, XMMATRIX, XMMATRIX);

private:
	bool InitializeShader(ID3D11Device*, HWND, WCHAR*, WCHAR*);
	void ShutdownShader();
	void OutputShaderErrorMessage(ID3D10Blob*, HWND, WCHAR*);

	bool SetShaderParameters(ID3D11DeviceContext*, XMMATRIX, XMMATRIX, XMMATRIX);
	void RenderShader(ID3D11DeviceContext*, int);

private:
	ID3D11VertexShader* m_vertexShader;
	ID3D11PixelShader* m_pixelShader;
	ID3D11InputLayout* m_layout;
	ID3D11Buffer* m_matrixBuffer;
};

#endif

 

2-1. Initialize

Color.vs과 Color.ps를 가져오고 InitalizeShader를 호출한다.

 

2-2. Shutdown

ShutdownShader를 호출하여 셰이더를 종료한다.

 

2-3. Render

SetShaderParameters를 먼저 호출하여 셰이더 내부의 파라미터를 호출한다.

 

2-4. InitializeShader

정점 셰이더와 픽셀 셰이더를 초기화하는 함수

  1. D3DCompileFromFile함수를 활용해서 정점 셰이더와 픽셀 셰이더를 컴파일 한다.
  2. 정점 셰이더를 생성하여 CreateVertexShaderCreatePixelShader 함수를 이용하여 셰이더들을 생성한다.
  3. 셰이더에서 처리할 꼭짓점들의 데이터의 레이아웃을 만든다. 각 요소들에 대한 정보를 저장하게 된다. 
  4. CreateInputLayout 함수를 이용하여 정점 입력 레이아웃을 생성한다.
  5. 정점 셰이더에서 활용할 상수 버퍼를 CreateBuffer 함수를 활용하여 상수 버퍼를 생한다.
  6. 상수 버퍼와 셰이더를 클래스 멤버 변수에 저장하고 성공하면 true를 반환한다.

※ 상수 버퍼 : 그래픽스 파이프라인에서 사용되는 상수 데이터를 GPU 전달하고 셰이더에서 불러올 때 쓰인다. 전달되는 정보는 행렬, 라이트, 재질 속성 등이다. 상수 버퍼는 CPU에서 GPU에 저장된 데이터를 가져와 수정 및 업데이트를 하고 다시 GPU에 저장한다.

 

2-5. ShutdownShader

InitializeShader에서 설정된 인터페이스들을 해제한다.

 

2-6. OutputShaderErrorMessage

정점 셰이더와 픽셀 셰이더를 컴파일 할 때 오류가 생길 경우 메세지를 출력한다.

 

2-7. SetShaderParameters

정점 셰이더에서 사용할 3개의 행렬인 WorldMatrix, ViewMatrix, ProjectionMatrix를 상수 버퍼에 설정한다.

worldMatrix = XMMatrixTranspose(worldMatrix);
viewMatrix = XMMatrixTranspose(viewMatrix);
projectionMatrix = XMMatrixTranspose(projectionMatrix);

전달하기 전에는 반드시 전치 행렬을 전달해줘야 한다.

MatrixBufferType의 구조체의 포인터 변수 dataPtr를 선언하고 이 변수를 활용해서 3개의 행렬 데이터를 복사하여 GPU 셰이더에서 사용될 수 있도록 한다.VSSetConstantBuffers 함수를 활용하여 정점 셰이더의 상수 버퍼를 설정하고 m_matrixBuffer를 사용하여 상수 버퍼를 전달하는 과정을 거친다.

 

2-8. RenderShader

이 함수가 호출되면 설정했던 그림을 렌더링 하게 된다. GPU에게 정점 버퍼의 데이터 형식을 알려주고 정점 버퍼에서 렌더링 하는데 필요한 정점 셰이더와 픽셀 셰이더를 설정한다. 이 과정이 끝나면 DrawIndexed함수가 호출되며 렌더링을 한다. 

 

728x90
반응형

'DirectX' 카테고리의 다른 글

DirectX11. 5) Texture  (0) 2023.06.13
DirectX11. 4) Buffer, Shader II  (0) 2023.06.12
DirectX11. 2) D3D11 Initialize  (1) 2023.06.09
DirectX11. 1) 창 띄우기  (0) 2023.06.07
4. DirectXMath - Transform  (1) 2023.05.02
Comments