프로그래밍 공부

전체 글 700

카테고리 설명
프로그래밍 공부하는 블로그
  • 이미지 프로세스를 처리 해주는데, 카메라를 작업해주는데 UV처리를 통해, 원하는 Rect를 표시해줄 수 있다. void RenderingTargetDemo::Init() { rtt = new RenderTexture(); Vector3 size = Vector3(100, 100, 1); Vector3 trPos = Vector3(WinMaxWidth - (WinMaxWidth / 4), WinMaxHeight - (WinMaxHeight / 4), 0); Vector3 trSiz = Vector3(WinMaxWidth / 2, WinMaxHeight / 2, 0); float rot = 0; r1 = new Rect(Vector3(200, 200, 0), size, rot); r2 = new Rect(V..

  • DirectX의 Shader을 적용하여, 화면을 지정된 규칙하에 바꾸어주는 작업이다. TextureBlur기법으로, 하나의 픽셀을 기준으로 3X3의 주변픽셀을 함께 뭉개서 이미지를 흐릿하게 해주는 기법이다. 이 작업을 n번 반복하면, 반복한 횟수만큼 더 흐릿하게 상이 나타난다. 위와 같이, 이미지 픽셀을 1- 20 번 반복하였을 때의 픽셀 블러 정도가 달라진다. float4 PS(PixelInput input) : SV_Target { float4 color = _sourceTex.Sample(_samp, (float2) input.uv); // 주변 픽셀들 float2 arr[8] = { float2(-1, +1), float2(+0, +1), float2(+1, +1), float2(-1, +0), ..

  • VertexBuffer에는 IA와 World 버퍼가 존재한다. 크게, IA는 World 행렬을 곱하게 되면, 월드상에 존재하는 위치 회전 크기값이 조정되어 나타나는, 고정좌표값이 이어붙어 나온다. World버퍼는 해당 좌표값 SRT에 곱해지게 되는 월드 좌표를 나타낸다. SRT S(Scale) 객체의 크기를 표현한다. R(Rotation) 객체의 회전값을 표현한다. T(Translation) 객체의 위치값을 표현한다. 위와 같은 방식으로 SRT를 나타내게 된다. 이때, 로케이션을 곱하고 나타내는건 4개의 축을 사용하게 된다. 우리가 사용하는 X,Y,Z을 축으로 나타내는 3차원 축 인데, 왜 4개의 축을 사용하여 계산하게 되는지 알아보자. 여기서 사용하는 임의의 W라는 축을 나타내어 사용하는 좌표계를 동차..

  • DirectX의 Renders부분에 대하여 설명한다. Renders는 그래픽 리소스와 관련된 여러 구성 요소를 포함한다. IA ( ImputAssembler ) 그래픽 파이프라인의 시작 부분에 위치한 단계이다. 그래픽 하드웨어에 그래픽 데이터를 전달하기 전에 데이터를 준비하고 정리하는 역할을 한다. IA는 그래픽 데이터의 형식을 정의하고, 버텍스 데이터를 읽어들여 삼각형으로 조립한다. 이렇게 조립된 프리미티브는 다음 그래픽 파이프라인 단계로 전달되어 처리된다. VertexBuffer VertexBuffer는 DirectX의 그래픽 어플리케이션에 사용되는 정점 데이터를 저장하는 버퍼이다. 정점 데이터는 3D모델의 점, 선, 면 등의 기하학적 정보를 포함한다. 각 정점은 위치, 법선 벡터, 텍스처 좌표 및 ..

  • 서론 DirectX11을 구성하기 위해 Framework 와 UnitTest로 두개의 프로젝트로 나누어 관리한다. Framework는 각 라이브러리를 가져와서 연동시키는 역활을 하고, UnitTest는 연동된 라이브러리를 활용하는 직접적인 알고리즘 부분을 맡게 된다. [ 위와같은 방법으로 사용하지 않고 자유롭게 구축하여도 무방하다. ] DirectX 라이브러리 연동하기 이와같이 두개의 프로젝트를 구성하여, Framework 의 프로젝트를 UnitTest에 연동시키기 위해, VS에서는 다음과 같은 설정을 진행한다. 위 항목에서 포함 디렉터리, 라이브러리 디렉터리 를 수정한다. 상속된 값, 에 해당하는 기록들도 같이 복사 붙여넣기 해준다. 위 경로는, DirectX경로의 Include 를 프로젝트 폴더에 복..

  • 3D 그래픽의 출력 결과를 생성하기 위해 여러 단계를 거처 처리하는 과정이다. CPU와 GPU의 협업으로 동작한다. IA(입력 어셈블러, Input Assembler) VS(정점 쉐이더, Vertex Shader) HS(헐 쉐이더, Hull Shader) TS(분할기, Tessellator) DS(도메인 쉐이더, Domain Shader) GS(지오메트리 쉐이더, Geometry Shader) SO(스트림 출력, Stream Output) RS(래스터 라이저, Resterizer) PS(픽셀 쉐이더, Pixel Shader) OM(출력 병합기, Output Merger) 순으로 동작한다. IA(입력 어셈블러, Input Assembler) 정점 버퍼와 인덱스 버퍼를 사용하여 기본 도형을 생성해준다. 이러..

작성일
2023. 7. 21. 18:01
작성자
WDmil
728x90

이미지 프로세스를 처리 해주는데, 카메라를 작업해주는데 UV처리를 통해, 원하는 Rect를 표시해줄 수 있다.

OBB, AABB.pptx
0.26MB

 

 

void RenderingTargetDemo::Init()
{
	rtt = new RenderTexture();

	Vector3 size = Vector3(100, 100, 1);
	Vector3 trPos = Vector3(WinMaxWidth - (WinMaxWidth / 4), WinMaxHeight - (WinMaxHeight / 4), 0);
	Vector3 trSiz = Vector3(WinMaxWidth / 2, WinMaxHeight / 2, 0);
	float rot = 0;

	r1 = new Rect(Vector3(200, 200, 0), size, rot);
	r2 = new Rect(Vector3(500, 400, 0), size, rot);
	r3 = new Rect(Vector3(700, 100, 0), size, rot);

	tr1 = new TextureRect(Vector3(100, 100, 0), Vector3(500, 500, 1), .0f, TexturePath + L"asdf.jpg");
	tr2 = new TextureRect(trPos, trSiz, rot);

	//tr2->SetShader(ShaderPath + L"VertexTexture.hlsl");
	tr2->SetShader(ShaderPath + L"VertexTextureOutLine.hlsl");
}

 

r1과 r2, r3로써, Rect를 표시하기위해 동적으로 생성해주고, SetShader을 통하여 쉐이더 처리또한 진행해줄 수 있다.

 

여기서, r1과 tr1은, TextureRect에 대하여 이미지를 덮어씌워주어 tr1이 더 바깥쪽으로 나타나게 표시해준 것 이다.

 

미니맵 처리부분은, tr2->SetShader(ShaderPath + L"VertexTextureOutLine.hlsl"); 에서 처리해준다.

 

float4 PS(PixelInput input) : SV_Target
{
    float4 color = _sourceTex.Sample(_samp, (float2) input.uv);
    float3 greyScale = 0;
    
    // Line
    {
        if(input.uv.x < .01f || input.uv.x > .99f || input.uv.y < .01f || input.uv.y > .99f)
            return float4(1, 1, 1, 1);
        
        if(input.uv.x < .51f && input.uv.x > .49f)
            return float4(1, 1, 1, 1);
        
        if(input.uv.y < .51f && input.uv.y > .49f)
            return float4(1, 1, 1, 1);
    }
    
    {
        if(input.uv.x < .5f && input.uv.y < .5f)
        {
            color = _sourceTex.Sample(_samp, float2(input.uv.x * 2.0f, input.uv.y * 2.0f));
            greyScale = dot(color.rgb, float3(.299f, .587f, .114f));
            
            color = float4(greyScale, 1);
        }
        else if (input.uv.x >= .5f && input.uv.y < .5f)
        {
            color = _sourceTex.Sample(_samp, float2((input.uv.x - .5f) * 2.f, input.uv.y * 2.f));
            float r, g, b;
            r = dot(color.rgb, float3(.393f, .769f, .189f));
            g = dot(color.rgb, float3(.349f, .686f, .168f));
            b = dot(color.rgb, float3(.272f, .534f, .131f));
            
            greyScale = float3(r, g, b);
            color = float4(greyScale, 1);
        }
        else if (input.uv.x < .5f && input.uv.y >= .5f)
        {
            color = _sourceTex.Sample(_samp, float2(input.uv.x * 2.0f, (input.uv.y - .5f) * 2.0f));
        }
        else if (input.uv.x >= .5f && input.uv.y >= .5f)
        {
            return float4(.425f, .754f, .134f, 1);
        }
    }
    
    return color;
}

/*

위 코드에서, 각 UV마다의 객체를 검사하여, Input된 UV를 확인하여, 해당되는 UV에 객체를 표시하여 dot를 정의해주고,

 

표시해줌 을 알 수 있다.

 

 

위 이미지처럼, 카메라의 화면을 복사하여, 해당되는 UV위치에 지정된 객체를 표시해준다.

 

필요한 부분의 uv의 객체를 Sample하여 가져온 후, 해당되는 Sample에 uv를 곱하여, 위치를 재조정해준 뒤.

 

지정된 r과 g와 b의 위치에 색을 다시 칠해준다고 이해하면 될 것 이다.

 

여기서, 화면이 움직이면 미니맵 또한 같이 움직이는것 을 볼 수 있는데,

 

이것을 수정하여 화면이 움직여도 미니맵이 움직이지 않게 하려면.

 

미니맵의 UV를 그때그때 갱신해주어야 한다.

 

그리고 미니맵을 표시하기위한 서브카메라를 따로 설정하여 바라보게 해야할 것 이다.

 

즉, 메인카메라와 미니맵용 카메라 2개를 사용해서 표시해주어야 한다.


AABB

 

축이 정렬된 바운딩 박스 ( Axis-Aligned Bounding Box)를 이용하여, 두 객체가 충돌하는지를 파악하는 간단한 알고리즘이다.

 

객체의 경계를 모두 포함하는 최소크기의 정렬된 사각형 충돌체로 구성되며. 각 축이 절대축과 평행한다.

 

AABB의 검사방식

 

  1. 각 객체의 AABB를 생성한다.
    이때 AABB는 해당 객체의 충돌 콜리전의 바운딩 박스를 구성하는 XY좌표로. 좌상단, 우상단, 좌하단, 우하단 으로 이루어져 있다.
  2. 두 객체의 AABB가 겹치는지를 확인한다.
    AABB의 겹침 여부는 각 축의 범위를 비교하여 판단한다. X축과 Y축의 범위가 겹치는지를 서로 비교하여 판단하게 된다.
  3. 모든 축에서 겹침을 확인하면, 두 객체는 충돌한다고 간주한다. 그렇지 않았다면 두 객체는 충돌하지 않았다고 판단한다.

 

장점

  • 간단하고 빠른 충돌검출이 가능하다.
    AABB 충돌방식은 매우 간단한 수학계산을 통해 충돌을 검출하게 된다.

단점

  • 회전된 객체 처리가 불가능하다.
    계산식 상 축이 정렬된 객체 기준으로 작성되어 있기 때문에, 축이 회전되어있다 라고 가정한다면 회전체에 대한 접근이 불가능하다.
  • 사각형 에 대한 객체충돌 검사만 가능하다.
    수식이 직선과 직선상의 좌표계산이기 때문에, 회전체, 다각체 에 대한 충돌검사가 불가능하다.

AABB의 충돌처리방식

 

충돌처리 시 false가 리턴되는것을 직관적으로 이해할 수 있다.

ALeft 는 Au_y 가 Bd_y 보다 큼 으로 false,

ADown 는 Af_x 가 Br_x 보다 큼 으로 false

 

그럼으로 false가 리턴되어 충돌됨을 알 수 있다.


OBB

 

Oriented Bounding Box로, 회전이 가능한 사각형 또는 직육면체를 사용하여. 두 객체가 충돌하는지 를 검출하는 방식이다.

 

각 객체는 로컬 좌표게에 따라 정렬된 사각형 또는 직육면체 충돌체로 표현되며, 이를 기반으로 충돌 검출과 충돌 처리를 수행한다.

 

OBB의 검사방식

  • 두 객체가 OBB를 생성한다.
    OBB는 로컬 좌표계에 기반하여 회전, 크기, 위치 등의 정보를 포함한다.

 

  • 두 객체의 OBB가 겹치는지 확인한다. 이를 위해 Separating Axis Teorem(분리 축 정리) 을 사용하여 OBB의 로컬 축들을 기준으로 프로젝션을 수행하고, 프로젝션 범위를 비교한다.

객체의 중심점을 확인

 

 

객체간의 거리를 확인.

 

  • 모든 축에서 겹치는 것을 확인 시 두 객체가 충돌했다고 간주한다.

 

장점

  • 회전이 가능한 객체를 검출 가능하다.
    회전각을 고려하여 충돌을 검출할 수 있다.

  • 다양한 형태의 충돌체 검출이 가능하다.
    사각형 뿐 아니라 다양한 형태의 충돌체를 표현할 수 있으며, 3D공간에서도 직육면체로 사용할 수 있어. 더 정교한 충돌 검출이 가능하다.

 

단점

  • 계산이 복잡하다.
    OBB 충돌 검출은 AABB에 비해 계산이 더 복잡하고 오버헤드가 클 수 있기 떄문에, 많은 오브젝트들이 충돌검출을 필요로 할 때 성능저하가 일어날 수 있다.

  • 구현이 복잡하다.
    OBB 충돌 검출은 로컬 좌표계 변환, 프로젝션, 분리 축 정리 등을 사용하여 복잡한 계산을 해야하기 때문에 구현이 상대적으로 어렵다.

 

728x90
작성일
2023. 7. 20. 23:03
작성자
WDmil
728x90

DirectX의 Shader을 적용하여, 화면을 지정된 규칙하에 바꾸어주는 작업이다.

 

TextureBlur기법으로, 하나의 픽셀을 기준으로 3X3의 주변픽셀을 함께 뭉개서 이미지를 흐릿하게 해주는 기법이다.

 

이 작업을 n번 반복하면, 반복한 횟수만큼 더 흐릿하게 상이 나타난다.

 

위와 같이, 이미지 픽셀을 1- 20 번 반복하였을 때의 픽셀 블러 정도가 달라진다.

float4 PS(PixelInput input) : SV_Target
{
    float4 color = _sourceTex.Sample(_samp, (float2) input.uv);
    
    // 주변 픽셀들
    float2 arr[8] =
    {
        float2(-1, +1), float2(+0, +1), float2(+1, +1),
        float2(-1, +0), /* 기준 정점 */  float2(+1, +0),
        float2(-1, -1), float2(+0, -1), float2(+1, -1)
    };
    
    // 블러 카운트 만큼 반복
    for (int blur = 1; blur < _blurCount; blur++)
    {
        // 주변 픽셀들에 대해 반복
        for (int i = 0; i < 8; i++)
        {
            // 입력 텍스처에서 샘플링할 주변 픽셀들의 상대적인 위치를 계산
            float x = arr[i].x * (float) blur / _imageSize.x;
            float y = arr[i].y * (float) blur / _imageSize.y;
            
            // 새로운 uv 좌표 계산
            float2 uv = input.uv + float2(x, y);
            
            // 입력 텍스처에 색상을 추가로 샘플링하여 누적
            color += _sourceTex.Sample(_samp, uv);
        }
    }
    
    // 블러 반복 횟수
    int blurInterations = _blurCount - 1;
    // 오프셋 개수
    int offsetCount = 8;
    // 전체 샘플링 개수
    int totalSamples = blurInterations * offsetCount + 1;
    
    return color /= totalSamples;
}

위와 같은 방법으로 화면의 uv를 다르게 나타내어 줄 수 있다.

728x90
작성일
2023. 7. 19. 01:40
작성자
WDmil
728x90

VertexBuffer에는 IA와 World 버퍼가 존재한다.

 

크게, IA는 World 행렬을 곱하게 되면, 월드상에 존재하는 위치 회전 크기값이 조정되어 나타나는, 고정좌표값이 이어붙어 나온다.

 

World버퍼는 해당 좌표값 SRT에 곱해지게 되는 월드 좌표를 나타낸다.

 

SRT

 

  1. S(Scale)
    1. 객체의 크기를 표현한다.
  2. R(Rotation)
    1. 객체의 회전값을 표현한다.
  3. T(Translation)
    1. 객체의 위치값을 표현한다.

위와 같은 방식으로 SRT를 나타내게 된다.

순서는 다르지만 위와같은 방식으로 나타난다.

 

이때, 로케이션을 곱하고 나타내는건 4개의 축을 사용하게 된다.

 

우리가 사용하는 X,Y,Z을 축으로 나타내는 3차원 축 인데, 왜 4개의 축을 사용하여 계산하게 되는지 알아보자.

 

여기서 사용하는 임의의  W라는 축을 나타내어 사용하는 좌표계를 동차 좌표계 라고 한다.


동차 좌표계

 

XYZ 3개의 축만으로는 덧셈 을 활용한 이동연산이 가능하지만, 이동연산 이외에 회전 스케일 등 다른 연산을 같은 방법으로 진행할 수 없다.

 

그러나, W라는 임의의 축을 하나 추가한것으로 다른연산을 동일한 곱셈 연산으로 처리할 수 있게된다.

 

https://matrixcalc.org/ko/

 

행렬 계산기

이 계산기의 도움으로 행렬 행렬식, 계수, 행렬의 거듭 제곱, 행렬의 합과 곱셈을 구하고 역행렬을 계산할 수 있습니다. 행렬 요소를 입력하고 버튼을 클릭하십시오.

matrixcalc.org

위 링크에서 행렬 계산을 진행해보자.

 

X Y Z 축이 각각 1, 2, 3 이고 이 좌표를 2, 2, 2 만큼 이동시키고 싶다고 할 때, 행렬 곱을 행하면 다음과 같이 나타난다.

위와같이 행렬곱으로 위치좌표의 덧셈이 나타남을 확인할 수 있다.

 

여기서 사용되는 W는 뷰 공간에서의 심도 테스트에 이용된다.

 


심도 테스트

 

동차 좌표계에서 나타난 W값을 얼마나 깊은 곳에 있는지 계산하기 위해 사용하는것 을 이야기 한다.

 

간단하게 각 항에 W값을 곱해주는 방식으로 사용한다. W값이 1에 가까울 수록 무한원점임으로 원점에 가깝고 0에 가까울수록 원점에서 먼것을 나타낸다.

 


직교 투영법

일반적으로 2D의 경우, 깊이값이 존재하지 않기 때문에 원근감을 표현하지 않는다.

 

그래서 일반적인 3D표현방식에 비해 더 단순한 행렬곱을 사용하게 된다.

 

z값을 제한한 방법으로 뷰를 투영하게 된다.

 

728x90
작성일
2023. 7. 15. 21:28
작성자
WDmil
728x90

DirectX의 Renders부분에 대하여 설명한다.

 

Renders는 그래픽 리소스와 관련된 여러 구성 요소를 포함한다.


IA ( ImputAssembler )

그래픽 파이프라인의 시작 부분에 위치한 단계이다.

그래픽 하드웨어에 그래픽 데이터를 전달하기 전에 데이터를 준비하고 정리하는 역할을 한다.

 

IA는 그래픽 데이터의 형식을 정의하고, 버텍스 데이터를 읽어들여 삼각형으로 조립한다.

 

이렇게 조립된 프리미티브는 다음 그래픽 파이프라인 단계로 전달되어 처리된다.


VertexBuffer

VertexBuffer는 DirectX의 그래픽 어플리케이션에 사용되는 정점 데이터를 저장하는 버퍼이다.

 

정점 데이터는 3D모델의 점, 선, 면 등의 기하학적 정보를 포함한다.

 

각 정점은 위치, 법선 벡터, 텍스처 좌표 및 추가적인 사용자 지정 데이터와 같은 속성을 가질 수 있다.

 

VertexBuffer는 정점데이터를 저장하고, 그래픽 파이프라인의 다음단계로 전달하게 된다.

 

#pragma once

class VertexBuffer
{
	public:
	~VertexBuffer();

	template<typename T>
	void Create(const vector<T>& vertices,
				const D3D11_USAGE& usage = D3D11_USAGE_DEFAULT);

				uint GetStride()	{ return stride;	}
				uint GetOffset()	{ return offset;	}
				uint GetCount()		{ return count;		}

				void SetIA();
private:
	ID3D11Buffer* buffer = nullptr;
	uint stride = 0;
	// 정점 한개의 크기
	uint offset = 0;
	// 앞부터 몃번째 떨어져 있는걸로 시작해라.
	// 필요한 정보만 다시 호출할때 그만큼 띄어놓아라.
	uint count = 0;
};

template <typename T>
inline void VertexBuffer::Create(const vector<T>& vertices, const D3D11_USAGE& usage)
{
	stride = sizeof(T);
	count = vertices.size();

	D3D11_BUFFER_DESC desc;
	// 버퍼는 내용저장이기 때문에, 보통 DESC만 만들어서 할당해서 사용한다.
	ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC)); // 메모리 초기화

	// desc 설정
	{
		desc.Usage = usage;
		desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
		desc.ByteWidth = stride * count;
		
		// Usage에 따라 cpu에 접근 여부
		switch (usage)
		{
		// GPU 에서만 접근 가능한 버퍼
			case D3D11_USAGE_DEFAULT:
			// GPU 에서만 접근 가능하고 수정할 수 없는 버퍼
			case D3D11_USAGE_IMMUTABLE:
				break;
			// CPU에서 접근 가능하고 동적으로 수정 가능한 버퍼
			case D3D11_USAGE_DYNAMIC:

			// CPU에서 수정 가능함을 설정
				desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
				break;

			// CPU에서 접근 가능, GPU에서 사용할 수 있는 형태로 변환 가능한 버퍼
			case D3D11_USAGE_STAGING:
				desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
				break;
		}
		// 권한 할당.
	}

	// 생성 단계
	{
		D3D11_SUBRESOURCE_DATA subData;							// 정점 데이터를 담을 구조체
		ZeroMemory(&subData, sizeof(D3D11_SUBRESOURCE_DATA));	// 구조체 초기화

		subData.pSysMem = vertices.data();						// 정점 데이터를 할당한 메모리에 복사

		HRESULT hr = DEVICE->CreateBuffer(&desc, &subData, &buffer); // 정점 버퍼 생성
		CHECK(hr); // 실패시 펑
	}
}

VertexBuffer에서 Create는, VertexBuffer의 데이터를 직접 지정해주고 생성하는 역할을 한다.

 

VertexBuffer에 대한 각 항목인 ID3D11Buffer* , unsinged int 형인 stride , offset, count 를 초기화한다.

 

정점 한개의 크기는 sizeof(T)로, 정점 한개에 대한 사이즈를 받아온 형식으로 지정해주고

(대부분 float을 사용한다)

 

count 를, vertices의 size를 가져와 배열의 개수가 몃개인지 확인한다. (항목이 몃개인지?)

 

그 후 D3D11_BUFFER_DESC 형식을 ZeroMemory 로 초기화해준다.

더보기

D3D11_BUFFER_DESC

  • "ByteWidth": 생성할 버퍼의 크기를 바이트 단위로 지정한다.

  • "Usage": 버퍼의 사용 용도를 정의한다. 예를 들어, 버퍼를 정점 버퍼로 사용할 것인지, 상수 버퍼로 사용할 것인지를 지정한다.

  • "BindFlags": 생성된 버퍼를 어떤 용도로 바인딩할지를 지정한다.
    예를 들어, 정점 버퍼로 사용할 경우 D3D11_BIND_VERTEX_BUFFER를 지정한다.

  • "CPUAccessFlags": CPU에서 버퍼에 액세스할 수 있는지를 지정한다.
    예를 들어, 버퍼를 동적으로 업데이트해야 하는 경우 D3D11_CPU_ACCESS_WRITE를 지정한다.

  • "MiscFlags": 버퍼의 기타 특성을 정의한다. 대부분의 경우 0으로 설정된다.

  • "StructureByteStride": 구조적 버퍼를 사용하는 경우, 각 요소의 크기를 바이트 단위로 지정한다.
    구조적 버퍼를 사용하지 않을 경우 0으로 설정된다.

Usage에 따라, 해당 버퍼가 GPU에서만 접근이 가능한지, 접근이 가능하나 상수인지, CPU에서 접근이 가능하고 동적수정이 가능한지 등의 값으로 설정해준다.

 

권한을 할당한다.

 

그후, D3D11_SUBRESOURCE_DATA 형 subData를 생성한 뒤, 구조체를 ZeroMemory로 초기화 한다.

 

더보기

D3D11_SUBRESOURCE_DATA

  • "pSysMem": 초기 데이터가 있는 메모리 블록의 포인터를 가리킨다.
    이 포인터는 초기화할 리소스의 데이터를 가리키는 포인터이다.

  • "SysMemPitch": 데이터가 저장된 메모리의 각 행(텍스처의 경우) 또는 요소(버퍼의 경우)의
    바이트 단위 크기를 나타낸다.

  • "SysMemSlicePitch": 데이터가 저장된 메모리의 각 슬라이스(텍스처 배열의 경우)의
    바이트 단위 크기를 나타낸다.

그러니까, D3D11_BUFFER_DESC 는, 데이터의 형식, 접근여부, 특성 등 정점버퍼의 특징을 담아낸다.

 

D3D11_SUBRESOURCE_DATA는, 버퍼의 데이터 블록의 사이즈, 메모리 슬라이스 사이즈 등 버퍼 자체의 데이터 사이즈를 확인한다.

 

그후

 

HRESULT hr = DEVICE->CreateBuffer(&desc, &subData, &buffer); 를 통하여

buffer에 desc와 subData의 값을 삽입해주고 HRESULT 로 실패와 성공여부를 확인한다.

CHCK(hr)을 통해 실패가 반환시 프로그램을 터트린다.

 


Resources

 

리소스는 그래픽 어플리케이션에 사용되는 그래픽 데이터를 나타낸다. 자원은 GPU 에서 처리되는 텍스처, 버퍼, 셰이더 상수 등을 포함할 수 있다.

 

 


VertexType

 

버텍스 자체의 정보를 저장하기 위한 구조체이다.

 

버텍스는 3D또는2D모델의 정점에 대한 정보를 포함하며, 위치, 색상, 텍스처 좌표 등의 속성을 저장하는 역할을 한다.

 

이 구조체는 그래픽 어플리케이션의 정점 데이터를 정의하고 사용하는데 사용된다.

 

// 버텍스 정보를 저장하기 위한 구조체

#pragma once

// 색상 정보
struct VertexColor
{
	VertexColor()
		: position(0, 0, 0), color(0, 0, 0) {}

	VertexColor(Vector3 position, Vector3 color)
		: position(position), color(color) {}

	Vector3 position;
	Vector3 color;

	// 정점데이터 구조를 서술
	static D3D11_INPUT_ELEMENT_DESC descs[];
	static const uint count = 2; // 원소 개수
};

// 텍스처
struct VertexTexture
{
	VertexTexture()
		: position(0, 0, 0), uv(0, 0) {}
	VertexTexture(Vector3 position, Vector2 uv)
		: position(0, 0, 0), uv(uv) {}

	Vector3 position;
	Vector2 uv;

	// 정점데이터 구조를 서술
	static D3D11_INPUT_ELEMENT_DESC descs[];
	static const uint count = 2; // 원소 개수
};

/*
	D3D11_INPUT_ELEMENT_DESC

	SemanticName		 : 정점 데이터의 의미를 나타내는 문구
	SemanticIndex		 : 위 이름이 중복되는 경우 구분하기 위한 인덱스 값
	Format				 : 데이터 형식을 나타냄
	InputSlot			 : 입력 슬롯의 인덱스
	AlignedByteOffset	 : 정점 데이터의 바이트 단위 오프셋 (0 = 자동계산)
	InputSlotClass		 : 사용되는 데이터 형식을 지정
	InstanceDataStepRate : 인스턴스마다 데이터를 읽어들이는데 사용할 스텝 레이트 값
*/

D3D11_INPUT_ELEMENT_DESC VertexColor::descs[]
{
	{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
	{"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0}
};

D3D11_INPUT_ELEMENT_DESC VertexTexture::descs[]
{
	{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
	{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0}
};

VertexColor에 생성자로써 Color값과 Position값을 삽입하여 동작시킨다.

 

또한, static으로 전역선언하여, D3D11_INPUT_ELEMENT_DESC 형의 배열을 한개 만들어준다.

그리고, 사용하는 데이터의 종류가 position과 color 두가지 임으로, count는 2로 두개의 값을 가짐을 명시해준다.

 

VertexTexture도 같은 방식으로 uv와 position을 정의해준다.

 

더보기

D3D11_INPUT_ELEMENT_DESC

  • SemanticName: 정점 데이터의 의미를 나타내는 문자열이다.
    예를 들어, "POSITION", "NORMAL", "TEXCOORD" 등이 사용될 수 있다..
  • SemanticIndex: 위의 SemanticName이 중복되는 경우 구분하기 위한 인덱스 값이다.
  • Format: 데이터 형식을 나타낸다.
    예를 들어, 32비트 부동소수점 좌표, 8비트 정수 색상 등을 나타낼 수 있다.
  • InputSlot: 입력 슬롯의 인덱스를 나타낸다.
    여러 입력 슬롯이 있는 경우 해당 정점 데이터가 어떤 입력 슬롯에 할당되는지를 지정한다.
  • AlignedByteOffset: 정점 데이터의 바이트 단위 오프셋을 나타낸다.
    이 값을 0으로 설정하면 자동으로 계산된다.
  • InputSlotClass: 사용되는 데이터 형식을 지정한다.
    주로 D3D11_INPUT_PER_VERTEX_DATA 또는 D3D11_INPUT_PER_INSTANCE_DATA가 사용된다.
  • InstanceDataStepRate: 인스턴스마다 데이터를 읽어들이는 데 사용할 스텝 레이트 값을 나타낸다.

ShaderBuffer

 

GPU에서 사용하는 데이터를 CPU에서 생성하고 수정할 수 있도록 버퍼를 제공하는 역할을 한다.

 

// GPU 에서 사용하는 데이터를 CPU에서 생성하고 수정할 수 있도록 버퍼를 제공하는 역할

#pragma once
#include "Framework.h"

class ShaderBuffer
{
public:
	void SetVSBuffer(uint slot)
	{
		MapData();
		DC->VSSetConstantBuffers(slot, 1, &buffer); // 버텍스 슬롯에 한개의 버퍼를 이 버퍼로 세팅하겠다.
	}

	void SetPSBuffer(uint slot)
	{
		MapData();
		DC->PSSetConstantBuffers(slot, 1, &buffer); // 버텍스 슬롯에 한개의 버퍼를 이 버퍼로 세팅하겠다.
	}

protected:
	// GPU 쪽에서 사용하는 데이터를 CPU 쪽에서 생성하고 수정할 수 있도록 제공하는 버퍼
	ShaderBuffer(void* data, uint dataSize)
	{
		desc.Usage = D3D11_USAGE_DYNAMIC;
		desc.ByteWidth = dataSize;
		desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
		desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

		HRESULT hr = DEVICE->CreateBuffer(&desc, nullptr, &buffer);
		CHECK(hr);
	}

private:
	// 데이터를 열어주는 용도의 MapData이다.
	void MapData()
	{
		D3D11_MAPPED_SUBRESOURCE subResource;
		HRESULT hr = DC->Map
		(
			buffer,						// 매핑할 그래픽 리소스
			0,							// 시작 바이트 위치
			D3D11_MAP_WRITE_DISCARD,	// 매핑 방법 ( 완전히 새로 쓴다 )
			0, 							// 매핑을 원하는 하위 리소스
			&subResource				// 매핑된 메모리 주소를 전달
		);
		CHECK(hr);

		memcpy(subResource.pData, data, dataSize);
		DC->Unmap(buffer, 0);
	}

private:
	D3D11_BUFFER_DESC desc = { 0 };
	ID3D11Buffer* buffer = nullptr;

	void* data = nullptr;
	uint dataSize = 0;
};

ShaderBuffer에서 SetVSBuffer을 통해, 버텍스 슬롯에 한개의 버퍼를 지정된 버퍼로 세팅한다는 의미이다.

SetPSBuffer 또한 버텍스 슬롯에 한개의 버퍼를 지정된 버퍼로 세팅하겠다는 의미이다.

 

ShaderBuffer의 생성자로 data와 uint 형태의 dataSize를 받아온다.

 

그 후, desc를 지정해준뒤, hr로 buffer에 값을 밀어넣어준다.쉐이더 값 임으로, 버텍스값은 기입되지 않는다.

 

MapData로 hr에 값을 넣어서 buffer값을 넣어준뒤, memcpy로 지정된 값들을 전부 외부로 빼내어 도출시켜

값이 어떤것이 들어있는지 확인해줄 수 있다.

 

private에 기입하여. 함수를 상속받는 위치에서만 작동할 수 있게 정의해준다.

 

 

728x90
작성일
2023. 7. 13. 22:11
작성자
WDmil
728x90

서론

DirectX11을 구성하기 위해 Framework 와 UnitTest로 두개의 프로젝트로 나누어 관리한다.

 

Framework는 각 라이브러리를 가져와서 연동시키는 역활을 하고,

 

UnitTest는 연동된 라이브러리를 활용하는 직접적인 알고리즘 부분을 맡게 된다.

 

[ 위와같은 방법으로 사용하지 않고 자유롭게 구축하여도 무방하다. ]


DirectX 라이브러리 연동하기

이와같이 두개의 프로젝트를 구성하여, Framework 의 프로젝트를 UnitTest에 연동시키기 위해,  VS에서는 다음과 같은 설정을 진행한다.

 

Framework에서 마우스 오른쪽 클릭 -> 속성

위 항목에서 포함 디렉터리, 라이브러리 디렉터리 를 수정한다.

포함 디렉터리 -> 메크로 -> SolutionDir을 찾아 빈칸에 붙여넣기.

상속된 값, 에 해당하는 기록들도 같이 복사 붙여넣기 해준다.

 

위 경로는, DirectX경로의 Include 를 프로젝트 폴더에 복사 붙여넣기 한 경로이다.

만약, 절대경로로써 로컬디스크 C 에 있는 DirextX를 사용하고 싶다면, 위 경로를 찾아가서 설정해도 좋다.


디버그 폴더 관리하기

그리고, 프로젝트를 컴파일 했을 때 나오는 디버그 폴더를 관리하기 위해, 출력 디렉터리와 중간 디렉터리를 다음과 같이 수정해준다.

위 항목을 Framework와 UnitTest 둘다 사용한다.


DIrextX 의 Graphics에 대한 설명을 작성한다.

 

그래픽 작업을 다루는 클레스이며, 싱글톤 베이스 로 작업한다.

싱글톤 베이스는 겹쳐지는 것을 피하기 위해 한개만 사용할때 사용한다.

// 그래픽들의 값을 전부 초기화 해주는것.
// 인자값을 전부 초기화 해야한다.
class D3DEnumAdapterInfo;
class D3DEnumOutputInfo;

class Graphics : public SingletonBase<Graphics>
{
// 싱글톤 베이스 = 한개가 존재해야 하는것은 한개만 넣는것.
public:
	friend class SingletonBase<Graphics>;
	// private에 있는 것을 사용하기 위해 firend 선언해준다.
	ID3D11Device* GetDevice() { return device;}
	ID3D11DeviceContext* GetDC() { return deviceContext; }
	
	void Resize(const UINT& width, const UINT& height);
	// 창 사이즈 바꾸기
	void SetViewport(const UINT& width, const UINT& height);
	// Viewport = 우리가 보고있는 화면.

	void Begin();
	void End();
	// 생성자와 소멸자의 내용을 줄여서 만든다.
	void GUI();
	// 그래픽 유저 인터페이스.
	// 다른 부가정보를 띄워주기 위해 사용
private:
	void CreateSwapchain();
	// 우리가 화면을 그려줄떄 뒤쪽에 버퍼를 생성해준다.
	// 그리고 화면을 두개 띄워서 교차하면서 표시해준다.
	void CreateRenderTargetView();
	// 
	void DeleteSurface();

private:
	Graphics();
	~Graphics();

private:
	void EnumerateAdapters();
	bool EnumerateAdapterOutput(D3DEnumAdapterInfo* adapterInfo);


private:
	ID3D11Device* device = nullptr;
	ID3D11DeviceContext* deviceContext = nullptr;
	IDXGISwapChain* swapChain = nullptr;
	ID3D11RenderTargetView* rtv = nullptr;
	D3D11_VIEWPORT viewport;
	D3DXCOLOR clearColor = 0xff555566;

	UINT numerator = 0;
	UINT denominator = 1;

	UINT gpuMemorySize;
	wstring gpuName;

	vector<D3DEnumAdapterInfo*> adapterInfos;
	int selectedAdapterIndex = 0;

	bool bVsync = true;
};

class D3DEnumAdapterInfo
// 그래픽카드 
{
public:
	~D3DEnumAdapterInfo();

	UINT adapterOrdinal = 0;
	IDXGIAdapter1* adapter = nullptr;
	DXGI_ADAPTER_DESC1 adapterDesc = { 0 };

	D3DEnumOutputInfo* outputInfo = nullptr;
};

class D3DEnumOutputInfo
// 모니터
{
public:
	~D3DEnumOutputInfo();

	IDXGIOutput* output = nullptr;
	DXGI_OUTPUT_DESC outputDesc = { 0 };

	UINT numerator = 0;
	UINT denominator = 1;
};
#include "Framework.h"
#include "Graphics.h"

// 스왑체인을 새로 조정하고, 렌더 타겟 뷰와 뷰포트를 업데이트
void Graphics::Resize(const UINT& width, const UINT& height)
{
	// 기존에 생성된 RTV 제거
	DeleteSurface();

	// 버퍼 크기 변경
	{
		HRESULT hr = swapChain->ResizeBuffers
		(
			0,						// 백 버퍼의 수 (0은 기존과 동일하게)
			width,					// 백 버퍼의 너비
			height,					// 백 버퍼의 높이
			DXGI_FORMAT_UNKNOWN,	// 백 버퍼의 포맷 (기존과 동일하게 유지)
			0						// 백 버퍼의 속성 (기존과 동일하게 유지)
		);
		assert(SUCCEEDED(hr));		// 리사이즈 실패한 경우 프로그램 종료
	}
	CreateRenderTargetView();		// 새로운 백 버퍼에 대한 RTV 생성
	SetViewport(width, height);		// 뷰포트를 새로운 크기에 맞게 설정
}

// 뷰포트 설정
void Graphics::SetViewport(const UINT& width, const UINT& height)
{
	viewport.TopLeftX = 0.0f;
	viewport.TopLeftY = 0.0f;
	viewport.Width = (float)width;
	viewport.Height = (float)height;
	viewport.MinDepth = 0.0f;
	viewport.MaxDepth = 1.0f;
}

// 렌더링을 시작하기 전 필요한 초기화 작업을 수행
void Graphics::Begin()
{
	// RTV 설정
	deviceContext->OMSetRenderTargets(1, &rtv, nullptr);
	// 뷰포트 설정
	deviceContext->RSSetViewports(1, &viewport);
	// RTV를 지우고 clearColor로 색상을 채움
	deviceContext->ClearRenderTargetView(rtv, clearColor);
}

// 렌더링을 끝내고 화면에 결과를 출력
void Graphics::End()
{
	// 백 버퍼를 출력하고, 화면 갱신에 대해 대기할지 여부를 bVsync로 전달
	HRESULT hr = swapChain->Present(bVsync == true ? 1 : 0, 0);
	assert(SUCCEEDED(hr));
}

// Gui 구현
void Graphics::GUI()
{
	static bool bOpen = true;
	ImGui::SetNextWindowPos({ 0, 15 });
	ImGui::SetNextWindowSize(ImVec2(200, 30)); // 위젯 창 크기 설정
	ImGui::Begin
	(
		"Vstnc",
		&bOpen,
		ImGuiWindowFlags_NoBackground |
		ImGuiWindowFlags_NoTitleBar |
		ImGuiWindowFlags_NoResize |
		ImGuiWindowFlags_NoMove |
		ImGuiWindowFlags_NoScrollbar
	);
	{
		ImGui::Checkbox("##Vsync", &bVsync);
	}
	ImGui::End();
}

// 스왑 체인을 생성
void Graphics::CreateSwapchain()
{
	// 이전에 할당된 메모리 해제
	{
		SAFE_RELEASE(device);
		SAFE_RELEASE(deviceContext);
		SAFE_RELEASE(swapChain);
	}

	// 구조체 초기화
	DXGI_SWAP_CHAIN_DESC desc;
	ZeroMemory(&desc, sizeof(DXGI_SWAP_CHAIN_DESC));

	// 너비와 높이 설정
	desc.BufferDesc.Width = 0;
	desc.BufferDesc.Height = 0;

	// 수직 동기화를 사용할 경우 프레임 레이트 설정
	{
		if (bVsync)
		{
			desc.BufferDesc.RefreshRate.Numerator = adapterInfos[0]->outputInfo->numerator;
			desc.BufferDesc.RefreshRate.Denominator = adapterInfos[0]->outputInfo->denominator;
		}
		else
		{
			desc.BufferDesc.RefreshRate.Numerator = 0;
			desc.BufferDesc.RefreshRate.Denominator = 1;
		}
	}

	// 버퍼의 쓰임새에 대해서 정의
	{
		// 버퍼의 색상 형식 설정
		desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;

		// 스케일링과 스캔라인 순서
		desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
		desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;

		// 스왑 체인의 버퍼 개수, 용도, MSAA 품질 설정
		desc.BufferCount = 1;
		desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		desc.SampleDesc.Count = 1;
		desc.SampleDesc.Quality = 0;

		// 출력 창 핸들, 창 모드, 스왑 체인 효과 설정
		desc.OutputWindow = handle;
		desc.Windowed = true;
		desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
	}

	// 사용 가능한 D3D 기능 수준을 나타내는 D3D_FEATURE_LEVEL 배열 생성
	vector<D3D_FEATURE_LEVEL> featureLevel
	{
		D3D_FEATURE_LEVEL_11_1,
		D3D_FEATURE_LEVEL_11_0,
		D3D_FEATURE_LEVEL_10_1,
		D3D_FEATURE_LEVEL_10_0,
	};

	// 가장 VRAM이 큰 어댑터를 선택하여 selectedAdapterIndex에 할당
	UINT maxVRam = 0;
	for (UINT i = 0; i < adapterInfos.size(); i++)
	{
		if (adapterInfos[i]->adapterDesc.DedicatedVideoMemory > maxVRam)
		{
			selectedAdapterIndex = i;
			maxVRam = adapterInfos[i]->adapterDesc.DedicatedVideoMemory;
		}
	}

	// 디바이스와 스왑 체인 생성
	HRESULT hr = D3D11CreateDeviceAndSwapChain
	(
		adapterInfos[selectedAdapterIndex]->adapter,	// 최대 VRAM 용량을 가진 그래픽 장치 선택
		D3D_DRIVER_TYPE_UNKNOWN,						// 드라이버 타입 (자동)
		nullptr,										// 소프트웨어 렌더러 사용 안함
		0,												// 렌더링 시 필요한 플래그 설정
		featureLevel.data(),							// 사용할 Direct3D 기능 레벨
		featureLevel.size(),							// 사용할 Direct3D 기능 레벨의 개수
		D3D11_SDK_VERSION,								// DirectX SDK 버전
		&desc,											// 스왑 체인을 생성할 때 사용할 구조체
		&swapChain,										// 생성된 스왑 체인 객체 반환
		&device,										// 생성된 디바이스 객체 반환
		nullptr,										// 사용하지 않음
		&deviceContext									// 생성된 디바이스 컨텍스트 객체를 반환
	);
	assert(SUCCEEDED(hr));

	// 사이즈 재설정
	Resize(WinMaxWidth, WinMaxHeight);

	// cmd 출력
	{
		for (int i = 0; i < adapterInfos.size(); i++)
		{
			gpuName = adapterInfos[i]->adapterDesc.Description;
			wcout << "GPU Name : " << adapterInfos[i]->adapterDesc.Description << endl;
			cout << "VRAM : " << adapterInfos[i]->adapterDesc.DedicatedVideoMemory << endl;
			cout << endl;
		}

		wcout << "Selected GPU Name : "
			<< adapterInfos[selectedAdapterIndex]->
			adapterDesc.Description << endl;
	}

}

// 스왑체인에서 백 버퍼를 가져와 RTV 생성
void Graphics::CreateRenderTargetView()
{
	// 백버퍼 가져오기
	ID3D11Texture2D* backbuffer = nullptr;
	HRESULT hr = swapChain->GetBuffer
	(
		0,
		__uuidof(ID3D11Texture2D),
		(void**)&backbuffer
	);
	assert(SUCCEEDED(hr));

	// 백 버퍼로 RTV 생성
	hr = device->CreateRenderTargetView
	(
		backbuffer,
		nullptr,
		&rtv
	);
	assert(SUCCEEDED(hr));

	// 백 버퍼 해제
	SAFE_RELEASE(backbuffer);
}

// RTV 해제
void Graphics::DeleteSurface()
{
	SAFE_RELEASE(rtv);
}

// 어댑터를 검색하고 스왑체인 생성
Graphics::Graphics()
{
	EnumerateAdapters();
	CreateSwapchain();
}

// 생성한 자원을 해제
Graphics::~Graphics()
{
	SAFE_RELEASE(rtv);
	SAFE_RELEASE(swapChain);
	SAFE_RELEASE(deviceContext);
	SAFE_RELEASE(device);
}

// 그래픽 어댑터를 찾아 정보를 저장
void Graphics::EnumerateAdapters()
{
	// DXGI 객체를 생성하는 함수를 구현한 인터페이스
	IDXGIFactory1* factory;
	// 팩토리 생성
	if (FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&factory)))
		// 실패시 종료
		return;

	UINT index = 0;
	while (true)
	{
		IDXGIAdapter1* adapter = nullptr;
		// 어댑터를 나열
		HRESULT hr = factory->EnumAdapters1(index, &adapter);

		// 더 이상 어댑터가 없으면 종료
		if (hr == DXGI_ERROR_NOT_FOUND)
			break;
		// 나열에 실패하면 프로그램 종료
		assert(SUCCEEDED(hr));

		D3DEnumAdapterInfo* adapterInfo = new D3DEnumAdapterInfo();
		ZeroMemory(adapterInfo, sizeof(D3DEnumAdapterInfo));
		// 어댑터의 인덱스 저장
		adapterInfo->adapterOrdinal = index;
		// 어댑터의 정보 저장
		adapter->GetDesc1(&adapterInfo->adapterDesc);
		// 어댑터 정보 저장
		adapterInfo->adapter = adapter;

		// 어댑터의 출력 장치 나열
		EnumerateAdapterOutput(adapterInfo);
		// 어댑터 정보 저장
		adapterInfos.push_back(adapterInfo);

		// 다음 어댑터로 이동
		index++;
	}
	// 팩토리 해제
	SAFE_RELEASE(factory);
}

// 어댑터에서 지원하는 출력 모드를 가져오는 역할, 출력 빈도를 저장
bool Graphics::EnumerateAdapterOutput(D3DEnumAdapterInfo* adapterInfo)
{
	IDXGIOutput* output = nullptr;
	// 어댑터의 출력 장치 나열
	HRESULT hr = adapterInfo->adapter->EnumOutputs(0, &output);

	// 출력 장치가 없으면 함수 종료
	if (DXGI_ERROR_NOT_FOUND == hr)
		return false;
	// 나열에 실패하면 프로그램 종료
	assert(SUCCEEDED(hr));

	D3DEnumOutputInfo* outputInfo = new D3DEnumOutputInfo();
	ZeroMemory(outputInfo, sizeof(D3DEnumOutputInfo));


	output->GetDesc(&outputInfo->outputDesc);	// 출력 장치의 정보 저장
	outputInfo->output = output;				// 출력 장치 객체 저장

	UINT numModes = 0;
	DXGI_MODE_DESC* displayModes = nullptr;
	DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM;

	// 출력 장치의 디스플레이 모드 개수 확인
	hr = output->GetDisplayModeList(format, DXGI_ENUM_MODES_INTERLACED, &numModes, nullptr);
	assert(SUCCEEDED(hr));


	displayModes = new DXGI_MODE_DESC[numModes];
	// 출력 장치의 디스플레이 모드 정보 저장
	hr = output->GetDisplayModeList(format, DXGI_ENUM_MODES_INTERLACED, &numModes, displayModes);
	assert(SUCCEEDED(hr));

	for (UINT i = 0; i < numModes; i++)
	{
		bool bCheck = true;
		bCheck &= displayModes[i].Width == WinMaxWidth;		// 디스플레이 모드의 너비가 최대 너비와 같은지 확인
		bCheck &= displayModes[i].Height == WinMaxHeight;	// 디스플레이 모드의 높이가 최대 높이와 같은지 확인

		if (bCheck == true)
		{
			// 디스플레이 모드의 리프레시 비율 저장
			outputInfo->numerator = displayModes[i].RefreshRate.Numerator;
			outputInfo->denominator = displayModes[i].RefreshRate.Denominator;
		}
	}

	// 출력 장치 정보 저장
	adapterInfo->outputInfo = outputInfo;
	SAFE_DELETE_ARRAY(displayModes);
	return true;
}

D3DEnumAdapterInfo::~D3DEnumAdapterInfo()
{
	SAFE_RELEASE(adapter);
	SAFE_DELETE(outputInfo);
}

D3DEnumOutputInfo::~D3DEnumOutputInfo()
{
	SAFE_RELEASE(output);
}

함수

Graphics::GetDevice()

  • 현재 DIrectX장치를 반환하는 함수이다.

Graphics::GetDC()

Graphics::Resize( ... )

  • 현재 출력되는 창의 크기를 변경하는 함수이다. 전달된 너비와 높이에 따라 렌더타겟을 재생성하고 크기를 조정한다.

Graphics::SetViewport( ... )

  • viewport의 크기를 설정해주는 함수로, 화면에 그려질 영역을 지정해주는 역활을 한다.

Graphics::Begin()

  • 렌더링의 루프를 시작하는 함수로, 시작전 값을 초기값으로 초기화해주는 작업을 한다.

Graphics::End()

  • 렌더링 루프의 종료를 나타내는 함수로, 렌더링 이후 정리작업을 수행한다.

Graphics::GUI()

  • 그래픽 사용자 인터페이스를 처리하는 함수이다. 다른부가정보를 표시한다.

Graphics::CreateSwapchain()

  • Swap Chain을 생성하는 함수로, 화면에 그릴후, 그리기전의 버퍼를 생성하고 두개의 화면을 교차하며 표시한다.

Graphics::CreateRenderTargetView()

  • Render TargetView를 생성하는 함수. SwapChain의 뷰포트 를 지정해준다.

Graphics::DeleteSurface()

  • Surface를 삭제하는 함수. 생성된 SwapChain과 Render Target View와 관련된 자원을 정리한다.

Graphics::EnumerateAdapters()

  • 사용가능한 그래픽 어댑터를 열거하는 함수이다. 시스템 설치 그래픽카드를 확인하고 어뎁터 정보를 수집한다.

Graphics::EnumerateAdapterOutput( ... )

  • 그래픽 어댑터의 출력(모니터)를 열거하는 함수로 모니터의 정보를 수집한다.

나머지는 소멸자이다.


Grapic Pipeline에 대해 설명한다.

 

728x90
작성일
2023. 7. 13. 22:11
작성자
WDmil
728x90

3D 그래픽의 출력 결과를 생성하기 위해 여러 단계를 거처 처리하는 과정이다.

CPU와 GPU의 협업으로 동작한다.

 

  1. IA(입력 어셈블러, Input Assembler)
  2. VS(정점 쉐이더, Vertex Shader)
  3. HS(헐 쉐이더, Hull Shader)
  4. TS(분할기, Tessellator)
  5. DS(도메인 쉐이더, Domain Shader)
  6. GS(지오메트리 쉐이더, Geometry Shader)
  7. SO(스트림 출력, Stream Output)
  8. RS(래스터 라이저, Resterizer)
  9. PS(픽셀 쉐이더, Pixel Shader)
  10. OM(출력 병합기, Output Merger)

순으로 동작한다.


 

IA(입력 어셈블러, Input Assembler)

 

정점 버퍼와 인덱스 버퍼를 사용하여 기본 도형을 생성해준다.

 

이러한 도형은 기본 그래픽객체의 기본 구성 요소이며, 정점 데이터의 입력 형식을 지정한다.

 

IA에서는, 정점 버퍼에서 각 도형의 선분 끝에 점을 찍어주고, 인덱스 버퍼에서는 그 점간의 선분을 이어준다.


VS(정점 쉐이더, Vertex Shader)

 

IA에서 받아온 도형의 정점 위치를 변환하여, 원하는 공간 위치에 배치한다.

 

즉, 원하는 도형을 위치에 비틀어서 설치한다. 만들어진 도형의 기울기, 각도 등을 정해주는 부분이라고 생각하면 된다.


HS(헐 쉐이더, Hull Shader)

 

공간분할 단계로, 모델의 표면을 분할하는 작업을 수행한다. 즉, 각 도형을 가능한 디테일하게 삼각형으로 잘라준다.

 


TS(분할기, Tessellator)

 

테셀레이션 단계를 수행한다.

 

받아온 입력데이터를 더 많은 점으로 나누어 더 자세한 세밀한 모델을 생성해준다.

 

HS에서 TS로 더 세분화시켜서 분할작업을 수행한다고 이해하면 좋다.

 


DS(도메인 쉐이더, Domain Shader)

 

TS에서 수행된 분할작업에 다른 알고리즘을 넣어 세분화된 지점의 꼭지점 위치를 다시 재구성하여

 

더 자세한 모델을 구성한다.

 

특정지점에서의 추가계산을 수행한다. 노말벡터를 계산하여 조명계산에 활용할 수 있다.

 


GS(지오메트리 쉐이더, Geometry Shader)

 

테셀레이션에서 생성된 정점 데이터를 받아서 처리한다.

 

더 많은 선을 추가하거나 필요없는 선을 판단하여 지워준다

 


SO(스트림 출력, Stream Output)

 

정점 데이터를 캡처하고 저장하는 단계이다.

 

정점 데이터를 저장할 필요가 없다면, 스트림 출력은 생략된다.

 

백업이라고 생각하면 될듯?


RS(래스터라이저, Resterizer)

 

3D공간에서 정의된 3D 모델을 2D 화면으로 변환한느 과정이다.

 

각 모델을 2D화면의 픽셀로 변환하고, 픽셀에 대한 정보를 계싼하여 렌더 타겟뷰에 출력하게 된다.

 

쉽게 생각하여, 설계도에 사용하는 모눈종이에 삼각형을 그었다면, 선분이 지나가는 모눈종이의 사각형 칸은

 

대부분은 삼각형 안에 들어있겠지만, 외각부분의 칸은 선분에 걸쳐있을것 이다.

 

이때, 걸쳐있는 선분의 사각형 칸의 일정 % 이상이 모델의 내부로 들어와있다면 표시하고 아니면 표시하지 않는것을 계산한다.

 


PS(픽셀 쉐이더, Pixel Shader)

 

픽셀 쉐이더는 화면에 출력되는 각 픽셀에 대한 정보를 계산한다.( 색상, 깊이 등)

 

모델이 화면에 차지하는 픽셀의 개수만큼 픽셀 쉐이더가 실행되어 각 모델의 픽셀에 대한 색상을 계산하여 출력하게 된다.

 


OM(출력 병합기, Output Merger)

 

위의 모든 항목이 직렬이 아닌 병렬적으로 도출됨으로, 도출된 모든 결과를 OM에서 모아서 합산한 뒤

 

버퍼에 출력결과를 생성하게 된다.

728x90

'컴퓨터 용어 정리' 카테고리의 다른 글

업 케스팅(Up casting)  (0) 2023.10.10
멀티셈플링 Multisampling(표본화)  (0) 2023.10.05
Device Context  (0) 2023.07.13
Delta_Time  (0) 2023.06.21
Window API  (0) 2023.06.14