평생 공부하는 빠타박스 블로그 : Learning is Happiness
article thumbnail
SMALL

ImGui활용한 DirectX 11 3D 를 이용한 2D 를 만드는 내용입니다.
본 내용은 똑같이 사용할 수 없음을 알립니다. (참고및 공부자료로 만들어진 내용임을 밝힙니다.)
전 과정에 대해 이해를 해야 다음 이 부분에 대한 이해를 할 수 있음을 밝힙니다. 
https://ppatabox.tistory.com/17

 

1) Vertex_Color 정점에 색상을 넣어보자 (라인-> 쉐이더) 

2) Shader (Class로 분할해보까?)  1편 -> 다음시간 (링크수정) 

 

=====================================================================

 

 

 

 

우리가 이제 자료형으로 묶을 것이다. 

 

D3DXVECTOR3 Location[MAX_LINE_COUNT]; 기존에는 정점 위치가 1개 였다. 

우리는 이제 자료형으로 묶을 것이다. 정점하나의 자료형으로 

 

1) Line.h를 변경하자

Line.h에서 private 새로 하나 지정해주고 struct 구조체로 묶자

D3DXCOLOR 에서 이것은 RGBA이다.  = 이것은 A 가 ALpha 반투명 이다.

범위 : 0 ~ 1 까지 RGB 만 사용하겠음 

 

Vertex Vertices[배열] 

 

구조체 안에 COLOR부분에 (0, 0, 0, 1) 마지막 a는 1로 지정해서 불투명으로 처리 

 

2) Line.cpp / zeroMemory부분을 삭제해준다. 

 

Line.h

#pragma once

#define MAX_LINE_COUNT 1000

class Line
{
public:
	Line();
	~Line();

	void Add(D3DXVECTOR2 start, D3DXVECTOR2 end, D3DXCOLOR color); //컬러를 받자
	void Render();

private:
	float GetWidth(float position) { return position / (float)Width * 2.0f - 1.0f; }
	float GetHeight(float position) { return -(position / (float)Height * 2.0f - 1.0f);};

private:
	struct Vertex //구조체로 묶음 
	{
		D3DXVECTOR3 Location;
		D3DXCOLOR Color;

		Vertex()
		{
			D3DXVECTOR3 Location;
			D3DXCOLOR Color;

		};
	};
	private:
	
		UINT DrawCount = 0;

		Vertex Vertices[MAX_LINE_COUNT]; //배열로 지정 

		ID3D11Buffer* VertexBuffer;
		ID3D11InputLayout* InputLayout;
	};

Line.h 에서 Vertices가 배열이 선언되면서  안에 Vertex() 생성자를 자동으로 전체를 다 포갠다. [안에 배열의 갯수 만큼)

위에 그런 생성자 안에서 초기화가 일어난다. 

 

3) 이제 POSITION하나만 넣는게 아니라 그대로 복사해서 아래 하나더 추가 한다. 

   COLOR로 바꿔주고. Float 3개 12byte 부터 넣겠다고 지정 해준다. 

 

예제 1) 만약 COLOR2를 만들어 주었다면 저곳에는 몆 바이트가 들어갈 것인가? 

Float형을 생각 할때 float은 4바이트 이다. 그래서 그대로 다 쓴다고 해서 12바이트를 COLOR 에 넣어주고

R/G/B/A 이니까 4바이트 곱하기 4개 이니까.  16바이트가 된다. 앞에 12바이트를 16바이트와 더해준다.

문제 1번은 28바이트부터 시작하면 된다.  (시작바이트 기준) . 

	D3D11_INPUT_ELEMENT_DESC layoutDesc[] =
	{
		"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
        "COLOR3", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0,( 문제1 ), D3D11_INPUT_PER_VERTEX_DATA, 0
	}; 
	UINT elementCount = ARRAYSIZE(layoutDesc);

 

4) 그다음 정점 자료형의 벡터3에서 버텍스 자료형으로 바뀌었으니 sizeof에와 Location이라고 잡혀있는것들을 변경해준다.Vertex와  Vertices 로 변경 (Location 부분) //sizeof 부분 정점자료형 바꿧으니 Vertex로 수정

 

5) 이제 Add에다 컬러를 하나 받을 것이다.  Line.h 

6) 받을려고 하는 컬러를 Line::Add에 수정해준다.

DrawCount부분 ++를 뻇다 두번째 꺼에서만 증가 하면되고 첫번쨰 꺼는 자기 위치 그대로 들어가면 된다.

7) 이제 편집이 완료 되면 Shader라는 것을 편집 해야 한다. 

도구 -> 확장 및 업데이트 -> 온라인 -> HLSL Tools for Visual Studio 파일을 다운 해준다. 

3D에서 주로 사용함 (쉐이더는 ) 

폴더에 Effect.hlsl 파일이 생성이 되어있을 것이다.

그 파일을 해당 프로젝트 파일 메인에 올려 놓는다.

그러면 파일이 생기는데 아까 hlsl 다운 받은 것은 이 Effect.hlsl같은 파일의

코드에 컬러를 나타나게 해주는 프로그램 이다.  

 

Line.cpp

 

#include "stdafx.h"
#include "System/Device.h"
#include "Line.h"

Line::Line()
{

	D3D11_INPUT_ELEMENT_DESC layoutDesc[] =
	{
		 "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
	}; // 앞에 포지션이 플롯 3개 였는데 
	UINT elementCount = ARRAYSIZE(layoutDesc);

	Device->CreateInputLayout(layoutDesc, elementCount, VsBlob->GetBufferPointer(), VsBlob->GetBufferSize(), &InputLayout);


	D3D11_BUFFER_DESC desc = { 0 };
	desc.Usage = D3D11_USAGE_DYNAMIC;
	desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	desc.ByteWidth = sizeof(Vertex) * MAX_LINE_COUNT; //수정 vertex
	desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;

	D3D11_SUBRESOURCE_DATA data = { 0 };
	data.pSysMem = Vertices; //수정 Vertices

	Device->CreateBuffer(&desc, &data, &VertexBuffer);
}

void Line::Add(D3DXVECTOR2 start, D3DXVECTOR2 end, D3DXCOLOR color)
{
	D3DXVECTOR3 tempStart(0, 0, 0);
	tempStart.x = GetWidth(start.x);
	tempStart.y = GetHeight(start.y);

	D3DXVECTOR3 tempEnd(0, 0, 0);
	tempEnd.x = GetWidth(end.x);
	tempEnd.y = GetHeight(end.y);

	Vertices[DrawCount].Location = tempStart;
	Vertices[DrawCount++].Color = color;

	Vertices[DrawCount].Location = tempEnd;
	Vertices[DrawCount++].Color = color;
}

Line::~Line()
{
	VertexBuffer->Release();
	InputLayout->Release();
}


void Line::Render()
{
	D3D11_MAPPED_SUBRESOURCE subResource;
	DeviceContext->Map(VertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
	{
		memcpy(subResource.pData, Vertices, sizeof(Vertex) * MAX_LINE_COUNT);//수정 Vertices
	}
	DeviceContext->Unmap(VertexBuffer, 0);
	//sizeof 부분 정점자료형 바꿧으니 Vertex로 수정 

	UINT stride = sizeof(Vertex);
	UINT offset = 0;

	DeviceContext->IASetVertexBuffers(0, 1, &VertexBuffer, &stride, &offset);
	DeviceContext->IASetInputLayout(InputLayout);
	DeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);

	DeviceContext->Draw(DrawCount, 0);

	DrawCount = 0;
}

Effect.hlsl은 GPU쪽 문법이고.  Line.cpp는 CPU쪽 프로그램 이다. 둘다 문법이 좀 다르다는 것을 알 수 있다.

 

- 잠시 그래픽 역사에 대해서 알아보자 

우리가 예를들어 유튜브 같은데에 1950년대 부터 그래픽의 성장을

보여주는 영상들이 있다.

그래픽의 발전이 거의 2000년대 초 중반 이다. 갑작 스럽게 발전하게 된 시기

 

참고 영상) 

 

1990년대 중후반 부터 2D에서 3D로 바뀌기 시작함 

2000년대 들어서면서 부터 쉐이더라는 개념이 등장하였음 

쉐이더를 프로그래밍 하기 시작한 

쉐이더를 본격적으로 활용한 시기가 2005~06년도 쯤 

 

쉐이더를 사용하면 왜 그래픽이 좋아질까? 

예를들어 100 x 100 size의 이미지가 있다고 쳐보자 

안에 픽셀을 읽어서 색을 바꿀려고 한다.

C에서 만약 처리 한다면

ex) 

for (y : 0 -> 99) 0~99까지 돌리고

for (x : 0 -> 99) 돌린다고 하자

그동안에 이곳에서 픽셀에 대한 어떠한 처리가 일어날 것이다.

그러면 10000번이 돌게 될것이다. 계속 돌면서 

 

그런데 쉐이더는 그렇지 않다. 위 내용은 CPU내용이다.

쉐이더는 PS(pixel shader) 함수를 하나 정해두면 

CPU는 순차적으로 가야하는 이유가 코어수가 적다 코어 크기는 큰데

코어 갯수는 적다 그러나 GPU는 GTX 1080기준 코어 갯수가 3000 몆개가 있다.

GPU는 코어가 작은대신 엄청나게 많다. 

GPU는 픽셀이 10000개 일때 코어 3000개가 각각 픽셀을 물고 3000개의 함수를 호출한다.

3000개가 동시에 각 픽셀별로 호출한다. 3000개 3000개 3000개 1000개 형식으로 4번 돌게 된다.

처리가 빠르니까 별별 그래픽 기술을 다 시도 할 수 있게 된것 이다. 

 

옛날에는 화면 효과가 별로 없었다. (흔들림, 뭉개짐 등등) 

언제부턴가 화면에 효과등이 엄청나게 생겨남 (후처리) 

그런것들이 GPU처리가 가능하기에 생겨남

(옛날 필름 촬영할때 와 관련이 있는데 (영화 방식이나 드라마 쪽)

필터 후처리로 조금 어둡게 처리 하는 방식의 발전이 

게임에서 넘어오면서 이러한 효과들이 생겨나기 시작했다. )

 

 

우리가 IA를 불러들이고

Draw를 한다. 그다음 -> VS(3D공간) -> RS(2D로 바꾸면? 두점을 주면 가운데를 채워주기 시작함(픽셀로 바뀜)) -> PS(얘한테 픽셀들이 들어온다 한코어가 각 픽셀을 물고 함수로 들어온다. ) 

(점................(RS)................점) = > PS 호출 색상은 (PS)에 들어간다. 색상은 PS에서 해야 하는데

VertexShader가 먼저 나온다. 우리가 아직 처리를 할 것이 아니기에 이번 시간은 Vertex에서 Pass만 시켜줄 것이다.

 

// POSITION0을 시멘틱이라고 부름 쉐이더에서 알려준걸 어떻게 받을지 쉐이더에서 결정하는 것

 

 

 

Effect.hlsl 

struct VertexInput
{
    float4 Position : POSITION0; //여기는 입력구조체 (만든 POSITION,0 Layout과 일치해야함 똑같이 쓰여져야함)  
	float4 Color : COLOR0; 
}; 

struct PixelInput
{
    float4 Position : SV_POSITION;//POSITION만 예외 
    float4 Color : COLOR0; //Vertexshader에서 그냥 PASS만 시킬거라 똑같이 넣어준다. 
};

PixelInput VS(VertexInput input)
{
    PixelInput output;
    output.Position = input.Position;
    output.Color = input.Color; // 받은 값을 그대로 보내줄 것이다. 

    return output; //이곳에서 다 처리하고 RS로 넘기고 
}

float4 PS(PixelInput input) : SV_TARGET
{
    return input.Color; //위에서 받은 것을 input으로 받아준다. 
    //RS에서 처리후 여기에서 처리 
}

 

 

그러면 컬러도 하나 넣었었는데 컬러도 하나 있어야 한다. 

그런데 쉐이더에서는 Float2 3 4 이다 포지션만 벡터3 3개 인데 float4로 effect에서 받았다.

그러나 POSITION만 예외 라는 점 

 

8) effect.hlsl vs에서 Line.cpp에서 받는 값들을 입력해준다. (POSITION COLOR) 

VS에서 넘기는 처리(PASS) output input 과정에 대해 설정해 준다 PS쪽으로 입력을 완료 했다면 저장 후 

추가적으로 비주얼 스튜디오 에서는 자동으로 컴파일 하는게 있는데 쉐이더는 따로 컴파일 한 코드가 있어서

Effect.hlsl -> 우클릭 -> 속성 -> 빌드에서 제외 (예) 로 표시 -> 비주얼 스튜디오에서는 이 파일을 빌드 하지 않는것 

 

9) main.cpp로 가자 Render값을 만들어 준다 . 의도 한 대로 빨간색 선이 나오는 것을 볼 수 있다. 

 

 

 

main.cpp

#include "stdafx.h"
#include "System/Device.h"
#include "Utilities/Math.h"
#include "Text.h"
#include "Line.h"


Line* line = NULL;

void InitScene()
{
	line = new Line();

}

void DestroyScene()
{
	delete line;
	line = NULL;
}

void Update()
{

}

void Render()
{
	line->Add(D3DXVECTOR2(100, 200),D3DXVECTOR2(300, 200),D3DXCOLOR(1, 0, 0, 1));
    line->Render();
}

====================================================================

 

2) Shader 1편 -> 다음시간 있음 

 

RS 가 하는 역할 중에 보간이라는 걸 수행 한다고 한다. 선형 보간을 실행한다. 

 

예를 들어 

(1 - t) * A + B * t = 

라는 식이 있다 0 ~ 1범위를 갖는다 치자

 

t = 0 이면  B는 사라지고 A만 남고 

1을 넣으면 A는 사라지고 B만 남는다

 

t = 0.5 면 반 씩 더해지고

t = 0.25 면 A가 강하게 나오고 B가 약하게 나온다

 

A = (1 , 0 , 0) 

B = (0 , 0 , 1) 이라고 할때  

t=  0 빨간색 

1을 넣으면 파란색

0.5 면 두개가 섞인 색 (0.5 , 0, 0.5) 로 나오게 될 것이다.

 

ex) 2개 의 정점이 생긴다고 할때  

A = 빨간색 

B = 파란색 일때 이 안에

픽셀을 채울때 RS가 선형보간법을 이용해서 빨간색에서 갈수록 파란색으로 바뀐다.

 

A>........................> B 형식으로 

 

자 그럼 한 번 사용해보자 

 

1) Line.cpp 에서 void Add하나를 더 만들어 준다. 

= 이름 갖게 써도 상관 없다 뒤에 파라미터의 계수나 자료형으로 판단 하니까.

2) 함수를 정의 하고 Line.cpp에 만들어 준후 

 

Line.h

#pragma once

#define MAX_LINE_COUNT 1000

class Line
{
public:
	Line();
	~Line();

	void Add(D3DXVECTOR2 start, D3DXVECTOR2 end, D3DXCOLOR color); //컬러를 받자
    void Add(D3DXVECTOR2 start, D3DXVECTOR2 end, D3DXCOLOR startColor, D3DXCOLOR endColor);
	void Render();

private:
	float GetWidth(float position) { return position / (float)Width * 2.0f - 1.0f; }
	float GetHeight(float position) { return -(position / (float)Height * 2.0f - 1.0f);};

private:
	struct Vertex //구조체로 묶음 
	{
		D3DXVECTOR3 Location;
		D3DXCOLOR Color;

		Vertex()
		{
			D3DXVECTOR3 Location;
			D3DXCOLOR Color;

		};
	};
	private:
	
		UINT DrawCount = 0;

		Vertex Vertices[MAX_LINE_COUNT]; //배열로 지정 

		ID3D11Buffer* VertexBuffer;
		ID3D11InputLayout* InputLayout;
	};

 

 

3) 기존에 Line::Add에 있던 것을 자르고 정의된 함수부분에 넣어 주고 자료형 명을 바꿔준다. 

프로그래밍 할때 많이 쓰는 기법 

같은 함수를 call하는데 start, end컬러를  최종적으로 처리하는 색을 같게 준다. 

이것이 들어오면 밑에 것을 호출하면서 색을 같을 것을 넣게 된다. 

void Line::Add(D3DXVECTOR2 start, D3DXVECTOR2 end, D3DXCOLOR color)
{
	Add(start, end, color, color);
}

4) main.cpp로 가자 

Line.cpp 

#include "stdafx.h"
#include "System/Device.h"
#include "Line.h"

Line::Line()
{

	D3D11_INPUT_ELEMENT_DESC layoutDesc[] =
	{
		 "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
	}; // 앞에 포지션이 플롯 3개 였는데 
	UINT elementCount = ARRAYSIZE(layoutDesc);

	Device->CreateInputLayout(layoutDesc, elementCount, VsBlob->GetBufferPointer(), VsBlob->GetBufferSize(), &InputLayout);


	D3D11_BUFFER_DESC desc = { 0 };
	desc.Usage = D3D11_USAGE_DYNAMIC;
	desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	desc.ByteWidth = sizeof(Vertex) * MAX_LINE_COUNT; //수정 vertex
	desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;

	D3D11_SUBRESOURCE_DATA data = { 0 };
	data.pSysMem = Vertices; //수정 Vertices

	Device->CreateBuffer(&desc, &data, &VertexBuffer);
}

void Line::Add(D3DXVECTOR2 start, D3DXVECTOR2 end, D3DXCOLOR color)
{
	Add(start, end, color, color);
}

void Line::Add(D3DXVECTOR2 start, D3DXVECTOR2 end, D3DXCOLOR startColor, D3DXCOLOR endColor)
{
	D3DXVECTOR3 tempStart(0, 0, 0);
	tempStart.x = GetWidth(start.x);
	tempStart.y = GetHeight(start.y);

	D3DXVECTOR3 tempEnd(0, 0, 0);
	tempEnd.x = GetWidth(end.x);
	tempEnd.y = GetHeight(end.y);

	Vertices[DrawCount].Location = tempStart;
	Vertices[DrawCount++].Color = startColor;

	Vertices[DrawCount].Location = tempEnd;
	Vertices[DrawCount++].Color = endColor;
}

Line::~Line()
{
	VertexBuffer->Release();
	InputLayout->Release();
}


void Line::Render()
{
	D3D11_MAPPED_SUBRESOURCE subResource;
	DeviceContext->Map(VertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
	{
		memcpy(subResource.pData, Vertices, sizeof(Vertex) * MAX_LINE_COUNT);//수정 Vertices
	}
	DeviceContext->Unmap(VertexBuffer, 0);
	//sizeof 부분 정점자료형 바꿧으니 Vertex로 수정 

	UINT stride = sizeof(Vertex);
	UINT offset = 0;

	DeviceContext->IASetVertexBuffers(0, 1, &VertexBuffer, &stride, &offset);
	DeviceContext->IASetInputLayout(InputLayout);
	DeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);

	DeviceContext->Draw(DrawCount, 0);

	DrawCount = 0;
}

 

5) main.cpp에서 아래 렌더 부분 하나더 복사하고 붙여준다음 startColor와 endColor설정을 해준다. 

실행하게 되면  

 

 

위에는 전에 렌더된 선이고 

아래는 새로 만든 것이다.

잘 보면 빨간색에서 파란색으로 점차 변경 되는 것이 보인다. 

 

 

main.cpp 

#include "stdafx.h"
#include "System/Device.h"
#include "Utilities/Math.h"
#include "Text.h"
#include "Line.h"


Line* line = NULL;

void InitScene()
{
	line = new Line();

}

void DestroyScene()
{
	delete line;
	line = NULL;
}

void Update()
{

}

void Render()
{
	line->Add(D3DXVECTOR2(100, 200), D3DXVECTOR2(300, 200), D3DXCOLOR(1, 0, 0, 1));
	line->Add(D3DXVECTOR2(100, 400), D3DXVECTOR2(300, 400), D3DXCOLOR(1, 0, 0, 1), D3DXCOLOR(0, 0, 1, 1));

	line->Render();
}

 

 

 

6) 앞으로도 이렇게 Line class를 활용 할 것인데. Line.h에서 기본 색상으로 쓸 아이를 하나 만들어준다. 

그렇게 하고 Line.cpp 에서 

Line.h - 아래 형식처럼 위에 바꿔주자 

#pragma once
#define MAX_LINE_COUNT 1000

class Line
{
public:
	Line();
	~Line();
    
	void Add(D3DXVECTOR2 start, D3DXVECTOR2 end); //변경 부분 
	void Add(D3DXVECTOR2 start, D3DXVECTOR2 end, D3DXCOLOR color); 
    void Add(D3DXVECTOR2 start, D3DXVECTOR2 end, D3DXCOLOR startColor, D3DXCOLOR endColor);
	void Render();
.
.

 

8) void Line::Add부분 정의 위쪽에  만들어 준다

9) main.cpp부분 도 추가 해준다. 

 

Line.cpp 

.
void Line::Add(D3DXVECTOR2 start, D3DXVECTOR2 end)
{
	Add(start, end, D3DXCOLOR(0, 0, 0, 1));
} //얘가 아래거 콜 

void Line::Add(D3DXVECTOR2 start, D3DXVECTOR2 end, D3DXCOLOR color)
{
	Add(start, end, color, color);
} //이애가 밑에꺼 콜해서 검은색 넣어버림 

void Line::Add(D3DXVECTOR2 start, D3DXVECTOR2 end, D3DXCOLOR startColor, D3DXCOLOR endColor)
{
	D3DXVECTOR3 tempStart(0, 0, 0);
	tempStart.x = GetWidth(start.x);
	tempStart.y = GetHeight(start.y);

	D3DXVECTOR3 tempEnd(0, 0, 0);
	tempEnd.x = GetWidth(end.x);
	tempEnd.y = GetHeight(end.y);

	Vertices[DrawCount].Location = tempStart;
	Vertices[DrawCount++].Color = startColor;

	Vertices[DrawCount].Location = tempEnd;
	Vertices[DrawCount++].Color = endColor;
}
...

 

main.cpp

void Render()
{
	line->Add(D3DXVECTOR2(100, 200), D3DXVECTOR2(300, 200), D3DXCOLOR(1, 0, 0, 1));
	line->Add(D3DXVECTOR2(100, 400), D3DXVECTOR2(300, 400), D3DXCOLOR(1, 0, 0, 1), D3DXCOLOR(0, 0, 1, 1));
	line->Add(D3DXVECTOR2(100, 600), D3DXVECTOR2(300, 600)); //아래에 넣어줌 

	line->Render();
}

 

완료 되면 출력 하게 되면 아래에 선 하나가 더 추가 됨을 볼 수 있다.

 

 

검은색 선 하나가 추가 된 것을 볼 수 있다. 

 

앞으로 우리는 쉐이더를 계속 다룰 것이다. 

상황에 따라서

쉐이더를 관리 할 수 있는 클래스를 만들겠다.

 

갑분팁 : 

어셈블리어라는 언어로 쉐이더 프로그래밍을 했는데

시간이 지나서 너무 빡세서 MS, OpenGL, Nvidia 가

모여서 언어 만든게 쉐이더 언어인데

각각 이름만 좀 다르게 부른다

Nvidia = CG (Comput Grahpic) 

MS = hlsl (high level shader language)

openGL = GLSL (open /GL Shader Language)

 

 

System -> 우클릭 -> 추가 -> 헤더파일 -> 파일명 (Shader.h) -> 추가 -> 파일명(Shader.cpp)

변수 이름 지을때 표기 방법 

지역변수 : Camel표기법 ex) drawCount (앞에 소문자 뒤에 대문자) 카멜표기법(낙타모양) 

멤버변수 /멤버함수 : InputLayout (앞에 대문자 뒤 단어 대문자 ) 파스칼 표기법

옛날방식 : 스네이크 케이스(헝가리언 표기법) a_i_DrawCount

그외 케밥케이스 라는 것도 있다 사이를 언더바 말고 '  - ' 표기법 

지금은 마우스 갖다 대면 무슨 자료형인지 나오는데 옛날에는 안나와서 저 표기법을 사용했던 것

 

10) Device,cpp 에서 보면  쉐이더를 사용하기 위해 필요한 것들 이다. 

이제 작성을 위해서 이것들을 자르고 shader.h에 옮겨준다 . 

ID3D11VertexShader* VertexShader;
ID3D11PixelShader* PixelShader;
ID3D10Blob* VsBlob;
ID3D10Blob* PsBlob;

11) 그리고 shader.h에서 생성자를 하나 만들어주자 string(문자열다룸) 

wstring = 스트링string은 영문권 1바이트권 아스키코드를 다루고/ w은 wide string이라고 부르는데

한글은 2바이트 인데 한글을 다룰 수 있도록 해주는 string 

 

12) 생성자에 Shader::Shader(wstring, file, 둘중 하나만 default파라미터vs, default파라미터ps ,

 

vs, ps는 vertexshader/pixel shader (이름으로 준것) 

 

초기화 방법 )

Shader::Shader(wstring file, string vs, string ps)
	: InputLayout(NULL) //3번째 초기화 방법 (주로 많이 사용) 이니셜 라이저
{
	InputLayout = NULL; // 1번째 초기화 방법 
}
	
/*shader.h 에서 */
private:
	ID3D11InputLayout* InputLayout = NULL; //2번째 초기화 방법

 

 

"D3DX11Comp 를 치게 되면 뒤에 자동완성 기능 중에 

File.a  = 안씨 코드 string 체어형 1바이트 https://studyfield.tistory.com/291

file.w = 와일드 체어 wstring 

아무것도 안되어 있는거 설정에 따라 다름

 

함수쓸때 파라미터 뜨는거 보면서 쓰면됨 LPCW = Long Pointer Const

이런식으로 선언 되어있는 것 (const wchar* p= null;)

 

HRESULT hr; 로 자료형 으로 만들어줌 (typedf long형) 1 이면 성공 0이면 실패 0이하로도 씀 

그런데 true. false / bool형으로 써도 되는건데 long형으로 쓴 이유가

실패했으면 왜 실패 했는지 에 대해서 알 수 있는 

 

hr = D3DX11CompileFromFile(wstring 부분 (file불러올것 string, 뭔지모르면 NULL, LP뭔지 모름NULL, 컴파일할 함수이름 배열로 vs.c_str(), version정보 "vs_5_0", 플래그 모름0, 플래그2도 모름  0, 멀티쓰레드 사용하는 부분NULL, shader에서 있는 것 단항포인터 니까 2차포인터로 만들려면 주소로 불러들임 &VsBlob, 에러메세지 돌려주는거 뭔지 모름 NULL, Hresult결과 리턴을 받을때 주소를 가져와서 리턴을 받는걸로 해서 NULL); 
assert(SUCCEEDED(hr)); //매크로 인데  assert(게임 빌드할때 공개하는데 그때는 그게 빠진다. 프로그래머 내부적으로 사용하기 위함 게임하다 꺼질때 메세지 띄어 주는 역할 (실제 게임 에서 나오는 것은 (사용자에게) 내부적으로는 무슨 문제가 있는지 어느줄 에서 에러가 났는지 띄어주고 꺼진다. ) 만약 실패를 했는데 그냥 꺼지면 어디서 실패했는지 모르니까. assert를 사용한다. 이줄에서 

 

#define SUCCEEDED(hr) (((HRESULT)(hr)) >=0) 이다 

단지 hr이 0보다 크거나 같으면 0이상이면 성공이라고 간주하는것 

 

쉐이더가 처음 등장한것은 directx8 였을때 그때는 version1 

문법도 그래픽 카드도 전부 다른 상태

DX9 버전도 바뀌면서  2.0 ~3.0 

10 4.0 

11 5.0 

12 6.0 "

 

blob (문자열 자료형)

 vs.c_str()이렇게 있는 것을 D3DX11CompileFromFile이 함수로호출 하면   "vs_5_0",  이 버전으로 

 vs.c_str()함수 이름에 있는 내용을 컴파일을 해준다

GPU가 이해할 수 있는 언어로 번역을 해준다 

그 결과를 가지고 우리가 쉐이더를 만들 것이다.

 

hr = Device->CreateVertexShader(VsBlob->GetBufferPointer(), VsBlob->GetBufferSize()문자열 길이, 뭔지모름 NULL, 이차포인터로 달라고함 &VertexShader);
assert(SUCCEEDED(hr));

 

바이트 코드라는 의미가 컴파일이 완료된 데이터 

우리가 이해할 수 있는 언어에서 컴퓨터가 이해할 수 있는 언어 바꿔놓은 그 결과가 

중간언어/ 바이트 코드 라고 불린다.

그 결과를 vsblob이 가지고 있다. 

 

13) 그다음 소멸자 shader.h에서 

항상 생성부터 하면 소멸코드 부터 작성하자 

빠지면 메모리 누수남 

~Shader();

 

shader.cpp 

Shader::~Shader()
{
	if (VertexShader != NULL) //주소가 있는지 확인 
    {
    	VertexShader->Release(); // 주소가 있었다면  release함수 호출 그렇게 하고 지웠으면 
        vertexShader = NULL; // NULL을 넣어둔다 
    }
} // 안전하게 제거 하는 방법.

 

이 걸 사용 할 수 있지만 매크로를 이용하자 stdafx.h 로 가서 매크로를 만들어주자 

 

 

stdafx.h

#define SAFE_RELEASE(p) { if(p != NULL){ p->Release(); p = NULL; } } // 이문자 쪽으로 
//stdafx.h 마지막 줄 추가

 

shader.cpp

Shader::~Shader()
{
	SAFE_RELEASE(VsBlob);
	SAFE_RELEASE(PsBlob);

	SAFE_RELEASE(VertexShader);
	SAFE_RELEASE(PixelShader);

	SAFE_RELEASE(InputLayout);
} //SAFE_RELEASE 이걸 위에 제거 처럼 매크로로 사용하여 더 간편하게 만들 수 있다

 

 

 

 

shader.cpp 

#include "stdafx.h"
#include "Shader.h"

Shader::Shader(wstring file, string vs, string ps)
	: InputLayout(NULL)
{
	HRESULT hr;
	
	hr = D3DX11CompileFromFile(file.c_str(), NULL, NULL, vs.c_str(), "vs_5_0", 0, 0, NULL, &VsBlob, NULL, NULL);
	assert(SUCCEEDED(hr)); //

	hr = D3DX11CompileFromFile(file.c_str(), NULL, NULL, ps.c_str(), "ps_5_0", 0, 0, NULL, &PsBlob, NULL, NULL);
	assert(SUCCEEDED(hr));

	/*cpu에서 일단 설정해주는것*/
	hr = Device->CreateVertexShader(VsBlob->GetBufferPointer(), VsBlob->GetBufferSize(), NULL, &VertexShader);
	assert(SUCCEEDED(hr));

	hr = Device->CreatePixelShader(PsBlob->GetBufferPointer(), PsBlob->GetBufferSize(), NULL, &PixelShader);
	assert(SUCCEEDED(hr));
}

Shader::~Shader()
{
	SAFE_RELEASE(VsBlob);
	SAFE_RELEASE(PsBlob);

	SAFE_RELEASE(VertexShader);
	SAFE_RELEASE(PixelShader);

	SAFE_RELEASE(InputLayout);
}

void Shader::CreateInputLayout(D3D11_INPUT_ELEMENT_DESC * desc, UINT count)
{
	HRESULT hr = Device->CreateInputLayout(desc, count, VsBlob->GetBufferPointer(), VsBlob->GetBufferSize(), &InputLayout);
	assert(SUCCEEDED(hr));
    // Line.cpp에서 받아온 Device->Create... 부분을 입력하고 desc
}

 

shader.h / void CreateinputLayout 을 정의 해주자 해주고

 

Line.cpp를 잘보면 Device->CreateInputLayout ....라고 되어 있는데 이걸 정의한 shader.cpp에 넣어준다. 

 

HRESULT hr = Device->CreateInputLayout이애도 Hresult로 불러준다. (desc받아온거, count받아온거 , VsBlob->GetBufferPointer(), VsBlob->GetBufferSize(), &InputLayout);
assert(SUCCEEDED(hr));

 

shader.h 

#pragma once

class Shader
{
public:
	Shader(wstring file, string vs = "VS", string ps = "PS");
	~Shader();

	void CreateInputLayout(D3D11_INPUT_ELEMENT_DESC* desc, UINT count); //Line.cpp에서 Layout Desc[] 불러 들일거임 
    //배열 이니까 배열의 이름을 넘기면 배열의 시작 주소 니까. 포인터로 받는다. (주소 <-> 포인터)
    // UINT count = arraysize 받을려고 
    //정의 하시오 
   

private:
	ID3D11InputLayout* InputLayout;

	ID3D11VertexShader* VertexShader;
	ID3D11PixelShader* PixelShader;
	ID3D10Blob* VsBlob;
	ID3D10Blob* PsBlob;
};

 

 

내가 어떤 함수를 정의 한다고 생각해보자 

예제 2) 

void Add(int a, int b, int c)
{
}
Add(10, 20, 30); // 이러면 자동으로 채워지는데 
------------------------------------------------------
내가 만약 C는 기본값으로 받고 싶다 하면 
void Add(int a, int b, int c =30)
{
}
Add(10, 20); // 이런식으로 넣으면 자동으로 C는 30이 나오고
default 파라미터 : 아무값을 안주면 자동으로 값을 주는 
=-----------------------------------------------------------
나는 필요해서 30이 아니라 다른 값을 쓰고 싶다면 
void Add(int a, int b, int c =30)
{
}
Add(10, 20, 40); // C=30은 무시되고 c에 40이 으로 대체 된다.
그런데 default파라미터의 특징은 
무조건 맨 뒤에서 부터 시작해야 한다. 
-----------------------------------------------------------
void Add(int a, int b = 20 , int c =30)
{
}
Add(10, 20, 40); //이렇게 넣어도 되는 데
-=--------------------------------------------------------
ex) 
void Add(int a, int b = 20 , int c)
{
}
Add(10, 20, 40); // 만약 이렇게 되면 중간에 넣으면 b가 20 인지 c에 20인지 
b는 기본 default로 쓸지 컴퓨터 입장에서는 모른다. 그래서 뒤에서 부터 쓴다. 

선언부에다 쓰던가 정의부분에다 쓰던가 둘중에 한 군데에 써야한다.
☆일반적으로 선언부에 쓴다.

 

 

 

다음 시간에는 쉐이더 편하게 다루기 위해서 클래스를 완성시키도록 하겠다. 

 

 

다음시간) 

 

[C++] DirectX 쉐이더 와 삼각형과 사각형의 이용 Shader Class 및 World /Rectangle/Triangle

ImGui 활용한 DirectX 11 3D를 이용한 2D를 만드는 내용입니다. 본 내용은 똑같이 사용할 수 없음을 알립니다. (참고및 공부자료로 만들어진 내용임을 밝힙니다.) 전 과정에 대해 이해를 해야 다음 이

ppatabox.tistory.com

 

728x90
728x90
LIST
profile

평생 공부하는 빠타박스 블로그 : Learning is Happiness

@공부하는 PPATABOX

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!