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

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

 

목차 )

1) 사각형 월드에 집어넣기 구현원리

2) 랜덤으로 돌리는 사각형 

 

--------------------------------------------------------------------------------------------------------------

 

 

1)Rect.cpp 에서 Rect::Rect()부분에서 변경을 해준다. 

그러하면 끝에 사각형이 나오는걸 볼 수 있는데 

0~ 1까지 꽉채워놨는데 

월드를 쓰면 월드에 대한 상대의 크기로 결정 되어서 이렇게 화면에 꽉차지 않는다 .

 

그럼이제 월드를 넣어보자 

 

Rect::Rect()
{
	float minusX = +0;
	float plusX = +1;

	float minusY = +0;
	float plusY = +1; //변경부분
	

	vertices[0] = Vertex(D3DXVECTOR3(minusX, minusY, 0), D3DXCOLOR(0, 1, 0, 1));
	vertices[1] = Vertex(D3DXVECTOR3(minusX, plusY, 0), D3DXCOLOR(1, 0, 0, 1));
	vertices[2] = Vertex(D3DXVECTOR3(plusX, minusY, 0), D3DXCOLOR(0, 0, 1, 1));

	vertices[3] = Vertex(D3DXVECTOR3(plusX, minusY, 0), D3DXCOLOR(0, 0, 1, 1));
	vertices[4] = Vertex(D3DXVECTOR3(minusX, plusY, 0), D3DXCOLOR(1, 0, 0, 1));
	vertices[5] = Vertex(D3DXVECTOR3(plusX, plusY, 0), D3DXCOLOR(1, 0, 0, 1));
    .
    .
    .

 

일단 main.cpp에 해두고 분리를 하자 

 

우리가 어떤 위치가 하나 있다고 치자 

정점하나의 위치를 처리한다고 생각해보면 W V P(3D)공간이여서 VS에서 처리를 한다(정점이기 때문에)

View port라는 것이 있는데 (RS= 3D 에서 2D로 바꿔주는것 리니어 인터폴레이션 일어남) 

2D(PS) 형식의 순서로 처리 된다.

 

world, view, projection은 변환행렬이라고 부른다 

뭔가 공간을 변환하기 위한 행렬 (Tansform행렬) world만 

world는 아래 빨간색이 위치를 결정하고

 

이것을 넣기 위해서 4X4의 변환행렬을 만들것이다.

자료형을 다 만들면 답이 없기에 

D3DX = 9.0이하버전

11에서도 가끔 쓴다 수학클래스가 11로 다루면 복잡하다

9.0버전은 간단 

 

D3DXMATRIX = 4X4행렬을 지원해주는 자료형이다 (D3DX랑)

D3D11이 =11버전 

 

 

 

2) main.cpp에서 

D3DXMATRIX world; 를 상단에 만들어준다 .

 

매트릭스의 초기화는 기존의 방법이랑은 다르다

제로벡터 를 쓰면 저게 전부다 0인 행렬이 된다

대각선으로 1 1 1 xyz가 되어있는데

전부 0이 되니까 크기 부분이 아무것도 안나온다

1이면 1배 / 0이면 0배

그래서 매트릭스 초기화 할때는 제로는 안되고

벡터는 가능하다

 

D3DXMatrixIdentity(&world); // 매트릭스를 초기화 해주는 함수 

 

월드를 넣으려면 버퍼가 하나 필요하다 버퍼도 하나 만들어 주자 

ID3D11Buffer* constantBuffer;(버텍스 버퍼 처럼) 

main.cpp/ buffer.cpp를 비교하면서 넣을 것이다. 

또한 Buffer.cpp를 보고 main.cpp와 비교해 보자 

옆에 D3D11_BUFFER_DESC desc = { 0 }; 부분이 있다. 

정의할려고 설정해야 하니까 Buffer하려면 이게 필요했는데

이걸 복사 해오자  똑같은 버퍼인데 용도만 다를 뿐 이다.

 

한번 들어가면 안바꿀 것이다. 그러면 

이 world를 이용한 정점의 위치를 안건드릴 것이다.(한번만 쓰고 묶어버리는 것) 

 

Default는 CPU에서 쓰는거 불가 GPU에서 쓸수 있다

우리는 CPU에서 GPU로 보내는 것 

 

현재까지는 CPU<->RAM 사이간의 데이터를

GPU<->VRAM 으로만 일방적으로 보내는 걸 사용하고 있었다

그런데 Default를 쓰면 불가능 하다고 했는데

(GPU에서 CPU로는 가능 하지만 CPU에서 GPU로는 불가능하다 원래는)

그런데 예외 사항이 있다 (UpdateSubResource사용할 수 있다

 

크기는 알수 없는데 아까 만들어둔 world를 구조체 안에 넣어보자

그리고 View와 Projection도 구조체 안에 넣어두자 

ID3D11Buffer* constantBuffer;
struct ConstantBufferDesc
{
	D3DXMATRIX World;
	D3DXMATRIX View;
	D3DXMATRIX Projection;//3D에서의 개념을 다루는 것 
};

 

이제 3개다 초기화를 해주어야 하니까

ConstantBufferDesc bufferDesc; 변수하나 만들고 

ID3D11Buffer* constantBuffer;
struct ConstantBufferDesc
{
	D3DXMATRIX World;
	D3DXMATRIX View;
	D3DXMATRIX Projection;//3D에서의 개념을 다루는 것 
};

Rect* rect = NULL;
void InitScene()
{
	ConstantBufferDesc bufferDesc; //변수선언 
	D3DXMatrixIdentity(&bufferDesc.World);
	D3DXMatrixIdentity(&bufferDesc.View);
	D3DXMatrixIdentity(&bufferDesc.Projection); //초기화

 

이렇게 하고 나서 이것의Default의  ByteWidth는 이것이 들어가고 

버퍼의 데이터가 될 것이다.

 

그다음 bine.flags는 버텍스 말고 컨스탄트 버퍼(상수버퍼) 

	D3D11_BUFFER_DESC desc = { 0 };
	desc.Usage = D3D11_USAGE_DEFAULT;
	desc.ByteWidth = sizeof(ConstantBufferDesc);// 이것이 들어가고 버퍼의 데이터가 될 것이다.
	desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; //상수버퍼 사용

 

그다음 Device이용해서 CreateBuffer해준다. 

D3D11_BUFFER_DESC desc = { 0 };
	desc.Usage = D3D11_USAGE_DEFAULT;
	desc.ByteWidth = sizeof(ConstantBufferDesc);
	desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;

	HRESULT hr = Device->CreateBuffer(&desc, NULL, &constantBuffer); // (desc들어가고 , 서브리소스 데이터(NULL), 우리가 만들버퍼)
	assert(SUCCEEDED(hr));

 

  • AT : 카메라가 바라보는 지점
  • EYE : 카메라의 위치
  • UP : 카메라의 상향 벡터
//예시
D3DXMATRIX* D3DXMatrixLookAtLH(
    _Inout_  D3DXMATRIX *pOut,  // 카메라 변환 행렬
    _In_     const D3DXVECTOR3 *pEye,   // 카메라 위치
    _In_     const D3DXVECTOR3 *pAt,    // 카메라가 바라보는 지점
    _In_     const D3DXVECTOR3 *pUp     // 카메라의 상향 벡터
);

 

이제 월드 셋팅에 들어갈 것이다. 

View먼저 하자 

View는 눈위치가 필요하다 눈위치에서 어느 방향을 바라보는 것

그릴려고 하는 원점을 0이라고 해보자 

Z이 들어갈수록 플러스 Z는 0에 있는 것이다.

그래서 눈위치를 살짝 뒤로 뺀 것

 

lookAt 바라볼 초점 (위치) 바로 앞에 있는 걸 쳐다 볼 것 

계산 할때 필요한 것이 있는데 눈이 같은 0 이였다고 치지만

눈 바로앞에서 볼 수 있는데 아래를 쳐다 볼 수 도 있다

그래서 머리의 수직각도 가 중요 바로 정면의 90도를 바라볼거 라서 고개 회전이 없는(위) 

 

방향을 쓸때는 단위벡터를 흔히 사용한다

 

 

[DirectX9]월드 변환(World Transform), 뷰 변환(Viewing Transform), 투영 변환(Projection Transform)

기계식 키보드, 프로그래밍, 컴퓨터 관련 정보, IT 제품 관련 블로그입니다.

mooneegee.blogspot.com

 

D3DXMatrixLookAtLH = View를 자동으로 계산해주는 함수 위 eye , lookAt, up 을 가지고 계산함

	D3DXVECTOR3 eye(0, 0, -1); //카메라 위치
	D3DXVECTOR3 lookAt(0, 0, 0); // 카메라가 바라보는 지점
	D3DXVECTOR3 up(0, 1, 0); // 카메라의 상향벡터

	D3DXMatrixLookAtLH(&bufferDesc.View, &eye, &lookAt, &up);

 


중요)

행렬을 다룰때 2가지가 있다 

일단 2D에서 행우선을 다룰 것인데 열우선으로 바꿀 것이다.

크기는 X, Y, Z 동일 한데 

위치는 열단위에서 

 

행우선이 계산하기 편함 

언리얼도 행우선

 

열우선(원래는 시스템 적으로 열우선이 더 빠르고 OpenGL은 열우선 사용

DX는 빠져나와서 독자적인 함수를 사용 (원본 기술을 뒤집어 둔다) 

 

프로그래머가 계산 할때는 행우선이 편함 

시스템 입장에서는 열우선이 빠르다

 

그래서 내부적으로 보통 행우선을 쓰면

열우선으로 바꾸는 옵션을 넣던가 

 

아니면 바꿔서 데이터를 입력해준다.(넣어준다) 

 

예시로 왜 열우선이 빠른지 보면 ( SISD, SIMD, MISD, MIMD ) 

우리가 그래픽 카드에서 쓰는 형태가 SIMD 방식이다. (cpu도 SIMD방식이 있긴한데 거의 SISD) 

I(Instruction): 명령 

D(Data) 

CPU / (SISD) : 하나의 명령어로 하나의 데이터를 처리하겠다는 의미 

GPU / (SIMD) : 하나의 명령어로 여러개의 데이터를 처리하겠다.

 

MISD : 여러개의 명령어로 하나의 데이터를 처리하겠다.(이론상으로만 존재)

데이터 하나 나올것인데 왜 명령어 여러개가 들어가나?

 

MIMD : 여러개의 명령어로 여러개의 데이터를 다루겠다.(양자컴퓨터 쯤 가야.. 실현?)

SIMD 데이터를 처리할때 모든 하드웨어는 데이터를 오른쪽에서 부터 읽어드린다

행우선이면 완성이 될까? 

X방향 Y방향 성립이 될 수 있긴한데. 

하드웨어는 오른쪽 부터 읽는다고 했다. 

 

      Z축방향 위치  
X 1 0 0 0
Y 0 1 0 0
Z 0 0 1 0
  0 0 0 1
  X Y Z    

 

오른쪽 열부터 읽었을 텐데 X Y Z순서인데 성립 할 수가 없다.

우린 프로그래머 기준으로 넣었으니까. 

열우선은 그대로 오른쪽에서 부터 열로 넣게 되면 성립을 하게된다. 

행렬이 뒤집어져 있으니까. 

그래서 열로만 읽었을때 위치를 다은칸에서 z축을

SIMD를 보았을때 열우선으로 쓰는게 빠르다 .

오른쪽에서 부터 

 

DX9은 행우선이였는데

DX10 열우선으로 바뀜

 

그럼에도 행우선을 쓰면 더 익숙하게 받아들일 수 있고

책 저자들이 거의다 행우선으로 쓰고 있음

 

추가 설명은 맨아래 참조


 

행우선을 열우선으로 바꿔주겠다는 (뒤집는 작업 (Transpose) ) 

D3DXMatrixTranspose(&bufferDesc.View, &bufferDesc.View);

 

DX에서는 포인터 인데 리턴해주는 값은 앞에 out이라고 붙여 둔다(나오는 값이라고) 

그다음 프로젝션 

우리가 화면에 그려진 영역(3D에서) 

맥락정도만 이해해자

 

프로젝션 기법 2가지 

예를들어 우리가 어떤 물체가 있다고 치자 

보면 물체에 원근감이 느껴진다 . 

3D에서 쓰는 perspective(관점) 

원근투영법 perspective 방식

 

 

 

2D게임은 멀어지고 작아지면 어색하다.

거리에 따른 크기 차이 변화가 없는 Orthographic Projection (직교투영) 

거리에 따른 크기차이 변화가 없는 방식을 사용할 것이다. 

원근감이 없는 

 

Ortho(직교투영 약자로 쓰임) 

offCenter( 우리가 기준점 중심을 잡을 것 ) 

D3DXMatrixOrthoOffCenterLH(&bufferDesc.Projection, 0, (float)Width, 0, (float)Height, -1, +1);
D3DXMatrixTranspose(&bufferDesc.Projection, &bufferDesc.Projection);

왼쪽 하단을 0으로 회전높이 Height 

깊이 /

 

전치로 프로젝션 해준다. 

-part2-

이것을 GPU쪽으로 밀어줘야 한다. 

 

ConstantBuffer는 밀어주는 방식이 좀 다르다. 

 

main.cpp

IA는 시작할때 넣는 데이터가 되는데

Constantbuffer는 쉐이더에 넣는 거기에 IA가 안붙는다. 

 

지금은 GPU에 바로 넣는것 

 

DeviceContext->VSSetConstantBuffers(0, 1, &constantBuffer);

 

정점처리 쉐이더를 작성하자 

 

우리가 뭔가 집어넣고 이동하고 회전하는 것을 

공간변환 이라고 말한다 .

 

 

우리가 어떤 (0, 0, 0) 의 어떠한 위치가 있다고 생각해보자 

 

벡터는 위치를 표기하거나 방향을 표기 한다. 

이 위치를 어느 공간에 변환 시키면 변환된 위치가 나온다

 

벡터는 행렬 

4X4행렬을 tansform이라 얘기 했는데

다른 말로 공간이라고도 말한다.

 

벡텨와 행렬곱 

행렬곱을 하면 공간변환이 된 결과가 나온다. 

 

행렬변환을 쉐이더에서 하는것 행렬곱을 수행하는 명령어 

mul(벡터(위치벡터) , 행렬) 이 나옴 

 

effect.hlsl에서 보면 

input.position (위치)

정점 하나당 이 쉐이더 한번을 col해야함 

정점이 6개 이니까 6개가 col됨 

 

각 위치 마다 mul 

 

Effect.hlsl

struct VertexInput
{
    float4 Position : POSITION0;
	float4 Color : COLOR0;
};

struct PixelInput
{
    float4 Position : SV_POSITION;
	float4 Color : COLOR0;
};

cbuffer VS_Wvp : register(b0) //constantbuffer를 다뤄줘야하는데 
{ //cbuffer는 구조체 모양인데 이 안에가 전역으로 취급됨 월드라고 전역이라고 취급된다. 
    matrix World; //
    matrix View;
    matrix Projection;
}

PixelInput VS(VertexInput input)
{
    PixelInput output;
    output.Position = mul(input.Position, World); //월드 해주기 (전역변수) 
    output.Position = mul(output.Position, View); // 월드 변환된 결과 (output.position에서 월드에서 뷰로 변환
    output.Position = mul(output.Position, Projection); //뷰로 변환된 결과를 프로젝션 해주는 것 
	output.Color = input.Color;

    return output;
}

float4 PS(PixelInput input) : SV_TARGET
{
    return input.Color;
}

 

main.cpp에서 

 

초기데이터 설정하는 것을 넣어주자.(수정부분) 

void InitScene() 부분 

D3D11_SUBRESOURCE_DATA subResource = { 0 };
subResource.pSysMem = &bufferDesc;

 

만약 실행하면 하단 크기에서 보이게 된다 .

 

그리고 원래는 가운데를 0으로 맞춘다.

 

이제 이것을 이동시킬려고 한다.

정점을 다 옮기면 연산량이 많기때문에

월드에 넣어주는 것인데.

 

 

그래서 월드의 값을 바꿔줘야하는데.

문제는 CPU에서 GPU로 보내는게 불가능한데 예외사항이 하나 있다. 

UpdateSubresource를 사용하는 방법이 있다. 

 

DeviceContext->UpdateSubresource(constantBuffer, 0, NULL, &bufferDesc, 0, 0);

CPU에서 GPU로 보내는 과정 

 

 

main.cpp

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

ID3D11Buffer* constantBuffer;
struct ConstantBufferDesc
{
	D3DXMATRIX World;
	D3DXMATRIX View;
	D3DXMATRIX Projection;
} bufferDesc;

float x = 0;
float y = 0;
D3DXMATRIX world[10];

Rect* rect = NULL;
void InitScene()
{
	D3DXMatrixIdentity(&bufferDesc.World);
	D3DXMatrixIdentity(&bufferDesc.View);
	D3DXMatrixIdentity(&bufferDesc.Projection);


	D3D11_BUFFER_DESC desc = { 0 };
	desc.Usage = D3D11_USAGE_DEFAULT;
	desc.ByteWidth = sizeof(ConstantBufferDesc);
	desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;

	bufferDesc.World._41 = 300; //비율
	bufferDesc.World._42 = 300;
	D3DXMatrixTranspose(&bufferDesc.World, &bufferDesc.World);

	D3DXVECTOR3 eye(0, 0, -1);
	D3DXVECTOR3 lookAt(0, 0, 0);
	D3DXVECTOR3 up(0, 1, 0);

	D3DXMatrixLookAtLH(&bufferDesc.View, &eye, &lookAt, &up);
	D3DXMatrixTranspose(&bufferDesc.View, &bufferDesc.View);

	D3DXMatrixOrthoOffCenterLH(&bufferDesc.Projection, 0, (float)Width, 0, (float)Height, -1, +1);
	D3DXMatrixTranspose(&bufferDesc.Projection, &bufferDesc.Projection);


	D3D11_SUBRESOURCE_DATA subResource = { 0 };
	subResource.pSysMem = &bufferDesc;

	HRESULT hr = Device->CreateBuffer(&desc, &subResource, &constantBuffer);
	assert(SUCCEEDED(hr));


	rect = new Rect();
}

void DestroyScene()
{
	SAFE_DELETE(rect);
}

void Update()
{

}

void Render()
{	
	DeviceContext->UpdateSubresource(constantBuffer, 0, NULL, &bufferDesc, 0, 0); //CPU에서 GPU로 보내줄 수 있는 과정(예외사항처리)
	rect->Render();
}

 

	bufferDesc.World._41 = 300;
	bufferDesc.World._42 = 300;

대략잡아 비율이 나오는 걸 볼 수 있다.&amp;amp;amp;amp;nbsp;

화면 비율을 재볼 수 있다. 

 

Photopea | Online Photo Editor

✕ Photopea: advanced photo editor Free online photo editor supporting PSD, XCF, Sketch, XD and CDR formats. (Adobe Photoshop, GIMP, Sketch App, Adobe XD and CorelDRAW). Create a new image or open existing files from your computer. Save your work as PSD (

www.photopea.com

위치가 맞는지 의아 할때 이런식으로 확인하면 된다. 

포토피아가 아니더라도. 캡쳐 뜨고서 그림판을 통해 해도 괜찮다. 

선택하여서 사각형의 중점으로 부터 화면 끝부분을 확인해 보면 된다. 

 

 

 

다음으로 main.cpp에서 

float x = 0;
float y = 0;
D3DXMATRIX world[10];

Rect* rect = NULL;
void InitScene()
{
	D3DXMatrixIdentity(&bufferDesc.World);
	D3DXMatrixIdentity(&bufferDesc.View);
	D3DXMatrixIdentity(&bufferDesc.Projection);


	D3D11_BUFFER_DESC desc = { 0 };
	desc.Usage = D3D11_USAGE_DEFAULT;
	desc.ByteWidth = sizeof(ConstantBufferDesc);
	desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;

	bufferDesc.World._41 = 300;
	bufferDesc.World._42 = 300;
	D3DXMatrixTranspose(&bufferDesc.World, &bufferDesc.World);

	D3DXVECTOR3 eye(0, 0, -1);
	D3DXVECTOR3 lookAt(0, 0, 0);
	D3DXVECTOR3 up(0, 1, 0);

	D3DXMatrixLookAtLH(&bufferDesc.View, &eye, &lookAt, &up);
	D3DXMatrixTranspose(&bufferDesc.View, &bufferDesc.View);

	D3DXMatrixOrthoOffCenterLH(&bufferDesc.Projection, 0, (float)Width, 0, (float)Height, -1, +1);
	D3DXMatrixTranspose(&bufferDesc.Projection, &bufferDesc.Projection);


	D3D11_SUBRESOURCE_DATA subResource = { 0 };
	subResource.pSysMem = &bufferDesc;

	HRESULT hr = Device->CreateBuffer(&desc, &subResource, &constantBuffer);
	assert(SUCCEEDED(hr));


	rect = new Rect();
}

void DestroyScene()
{
	SAFE_DELETE(rect);
}

void Update()
{
        
	D3DXMatrixTranslation(&bufferDesc.World, 100, 100, 0); //100 100 만큼 움직여줌 이걸 이용해서 키보드로 움직이는 것도 가능하다 
	D3DXMatrixTranspose(&bufferDesc.World, &bufferDesc.World); //움직였으니까 
}

void Render()
{
	DeviceContext->UpdateSubresource(constantBuffer, 0, NULL, &bufferDesc, 0, 0);
	rect->Render();
}

 

 

D3DXMatrixTranslation(&bufferDesc.World, 100, 100, 0); 이걸 이용해서 키보드로 움직이는 것도 가능하다. 

 

 

void Update()
{
	if (Key->Press('D'))
		x += 1;
	else if (Key->Press('A'))
		x -= 1;

	if (Key->Press('W'))
		y += 1;
	else if (Key->Press('S'))
		y -= 1;
        
	D3DXMatrixTranslation(&bufferDesc.World, x, y, 0); 
	D3DXMatrixTranspose(&bufferDesc.World, &bufferDesc.World);
}

 

현실에서는 불가능 하다

물체하나를 월드하나에 담지만

같은 물체를 여러개 담을 수 있는게 게임이다.

 

월드 위치가 바뀌면서 찍히는 걸 볼 수 있다. 

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

ID3D11Buffer* constantBuffer;
struct ConstantBufferDesc
{
	D3DXMATRIX World;
	D3DXMATRIX View;
	D3DXMATRIX Projection;
} bufferDesc;

float x = 0;
float y = 0;
D3DXMATRIX world[10]; //제한 

Rect* rect = NULL;
void InitScene()
{
	D3DXMatrixIdentity(&bufferDesc.World);
	D3DXMatrixIdentity(&bufferDesc.View);
	D3DXMatrixIdentity(&bufferDesc.Projection);


	D3D11_BUFFER_DESC desc = { 0 };
	desc.Usage = D3D11_USAGE_DEFAULT;
	desc.ByteWidth = sizeof(ConstantBufferDesc);
	desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;

	bufferDesc.World._41 = 300;
	bufferDesc.World._42 = 300;
	D3DXMatrixTranspose(&bufferDesc.World, &bufferDesc.World);

	D3DXVECTOR3 eye(0, 0, -1);
	D3DXVECTOR3 lookAt(0, 0, 0);
	D3DXVECTOR3 up(0, 1, 0);

	D3DXMatrixLookAtLH(&bufferDesc.View, &eye, &lookAt, &up);
	D3DXMatrixTranspose(&bufferDesc.View, &bufferDesc.View);

	D3DXMatrixOrthoOffCenterLH(&bufferDesc.Projection, 0, (float)Width, 0, (float)Height, -1, +1);
	D3DXMatrixTranspose(&bufferDesc.Projection, &bufferDesc.Projection);


	D3D11_SUBRESOURCE_DATA subResource = { 0 };
	subResource.pSysMem = &bufferDesc;

	HRESULT hr = Device->CreateBuffer(&desc, &subResource, &constantBuffer);
	assert(SUCCEEDED(hr));


	rect = new Rect();


	for (int i = 0; i < 10; i++)
	{
		x = Math::RandomFloat(0, (float)Width);
		y = Math::RandomFloat(0, (float)Height);

		D3DXMatrixTranslation(&world[i], x, y, 0);
		D3DXMatrixTranspose(&world[i], &world[i]);
	}
}

void DestroyScene()
{
	SAFE_DELETE(rect);
}

void Update()
{
	//if (Key->Press('D'))
	//	x += 1;
	//else if (Key->Press('A'))
	//	x -= 1;

	//if (Key->Press('W'))
	//	y += 1;
	//else if (Key->Press('S'))
	//	y -= 1;

	//D3DXMatrixTranslation(&bufferDesc.World, x, y, 0);
	//D3DXMatrixTranspose(&bufferDesc.World, &bufferDesc.World);
}

void Render()
{
	DeviceContext->VSSetConstantBuffers(0, 1, &constantBuffer);

	
	for (int i = 0; i < 10; i++)
	{
		bufferDesc.World = world[i];
		DeviceContext->UpdateSubresource(constantBuffer, 0, NULL, &bufferDesc, 0, 0);
		rect->Render();
	}	
}

 

그러면 실행할때 마다 바뀌는 것을 볼 수 있다. 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

행 우선(Row-Major)


row 단위로 저장 하겠다는 뜻

하나의 row를 완전히 저장하고 다음 row를 저장할 것 

 

a11 이 저장된 메모리 다음 칸에는 a12가 저장될 것이다. 

a13이 저장된 메모리 다음 row의 첫번째 값인 a21이 저장될 것이다.

 

따라서 메모리에는 다음과 같이 1차원으로 처져서 저장 된다.

 

[ a11, a12, a13, a21, a22, a23, a31, a32, a33 ]

 

우리가 주어진 행렬을 화면에 출력하는 프로그램을 짠다고 생각해보자 

상식적으로 윗줄부터 오른쪽으로 끝까지 쓰고 개행한 뒤 다음줄을 써내려가는 방식이 되어야 할텐데,

그렇다면 대부분의 프로그래밍 언어들도 콘솔창 위에서 아래로 내려가기 때문에 행우선을 선택하는 편이 자연스럽다.

 

 

열 우선(Column-Major)


 

row와 같은 맥락 col단위로 저장하겠다는 의미

하나의 온전한 col을 저장한 뒤 다음 col을 저장하겠다는 것

 

a11,을 저장한 메모리 다음 칸에는 a21이 올 것이다. 

이와 마찬가지로, a32를 저장한 메모리 다음 칸에는 

다음 column의 첫번째 원소인 a13이 저장될 것이다.

 

따라서, 메모리에는 다음과 같이 1차원으로 퍼져서 저장된다.

 

[ a11, a21 a31, a12, a22, a32, a13, a23, a33 ]

 

포트란, 매트랩, R, 줄리아(과학 관련분야 프로그래밍언어) 

계산 쪽의 언어들이 열우선을 채택한 것을 볼 수 있는데 

행렬이라는 것의 기원이 연립방정식의 축약임을 생각해 보면 당연한 것이다. 

 

세상에 행렬을 가로 방향으로 읽는 수학자는 없다. 

행을 따라 위에서 아래로, 열우선으로 읽는게 정상이다. 

 


행우선과 열우선을 벤치마크 하였을때 (줄리아 언어기준) 행/렬 순서만 바꾸고 행을 먼저 읽었을때 약 36초 

열을 먼저 읽었을때 20초가 걸려 거의 2배 수준의 성능 차이가 있음을 알 수 있다.

 

데이터 레이아웃은 다른 프로그래밍 언어로 작성된 프로그램간에 배열을 올바르게 전달하는 데 중요하다

최신 CPU는 비 순차적 데이터보다 순차 데이터를 더 효율적으로 처리하기 때문에 어레이 를 순회할때 성능에도 중요하다

 

어찌되었든 행 중심 환경에서 열 중심 순서를 사용하거나 , 그 반대의 경우, 한가지 해결방법은 

인덱스에 비 전통적인 역할을 할당하는 것(열에는 첫번째 인덱스를 사용, 행에는 두번째 인덱스를 사용) 

또는 1차원 배열의 위치를 명시 적으로 계산하여 언어 구문을 우회하는 것

(물론 관습에서 벗어나면 취약성이 증가할 뿐만 아니라 기존언어 기능 및 기타 코드와의 필요한 상호 작용 정도에 따라 비용이 증가 할 수 있다)

 

다차원 배열을 지원하는 프로그래밍 언어 또는 표준 라이브러리는

일반적으로 이허나 배열에 대한 기본 행 중심 또는 열 중심 저장 순서를 갖는다

 

행 우선 순서는 다음에서 사용됩니다. /C ++/목표 -C (C 스타일 배열의 경우), PL / I,[3] 파스칼,[4] Speakeasy,[인용 필요SAS,[5] 과 Rasdaman.[6]

열 주요 순서는 다음에서 사용됩니다. 포트란MATLAB,[7] GNU 옥타브S-Plus,[8] 아르 자형,[9] 줄리아,[10] 과 Scilab.[11]

 

 

 

 

다음시간)

 

[C++]DirectX 벡터와 배열과 범위 Array | Scale

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

ppatabox.tistory.com


각주)

 

 

 

728x90
728x90
LIST
profile

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

@공부하는 PPATABOX

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