프로그래밍 공부
작성일
2023. 10. 6. 16:13
작성자
WDmil
728x90

DXD색깔 출력하기

색을 출력하기 위해서는, 먼저 버퍼를 생성해서 color를 넣어주어야 한다.

버퍼에 넣기전에 먼저 Vertex에 생성해놓은 pos부분에 color도 받을 수 있도록 바꾸어준다.

위 코드에서 전에 만들어두었던 Vertex부분에 XMFLOAT4형태의 color를 만들어서 기입해준다.

이렇게 하면 struct Vertex형태의 데이터에는 pos와 color값을 두개 가지고 있게된다.


그후, INPUT_ELEMENT_DESC에서 POSITION 이외에도 COLOR값을 받는다는 표시를 해주어야 한다.

DESC에서 데이터를 보낼 때, COLOR이 있다는 사실을 알려주고, 데이터형식과 앞부분 에 어떤 데이터가 추가로 존재하는지, 그리고 몃바이트가 사용되었는지 등을 전부 작성하여 표시해준다.


DESC에서 표시가 끝났으면, 이미 전에 만들었던 BUFFER가 알아서 현재 CPU의 REM에 존재하는 데이터를 GPU의 VREM에 기입 해줄것이다.


그후, VREM에서 데이터를 가져오는 hlsl에서 Color값을 읽어오기 위해 PixelInput과 VertexInput을 재구성해준다.

 

위와같이. VertexInput에서 Color값을 읽어와 PixelInput에서 활용할 수 있게 작업하기 때문에,

Buffer에서는 VertexInput에 전달하게 설정되어있다.

 

그리고 Vertex데이터를 기입해줄 때. 컬러값을 넣어준다면,

3차원좌표의 앞자리수가 아닌 뒷자리 3개는 RGB값이다.

대충 도형이 컬러풀해진다.


DX3D에서 삼각형 출력하기

D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST  1 - 2 -3 으로 삼각형을 그린다.

시계방향으로 돌아야 화면을 바라보게 폴리곤이 그려진다.

 

DX에서 사각형을 출력하기 위해서는 삼각형을 출력할 수 있어야 한다. 모든 버텍스는 삼각형 형태로 이어져 있다.

한 면을 만드는 가장 최소한의 버텍스 숫자는 3개이고. 3개의 삼각형을 전부 이어붙여서 모든 면을 만들 수 있기 때문에,

모든 버텍스 면을 삼각형으로 이어주어 면을 만들 수 있다.

삼각형으로 이어놓은 면을 두개 붙이게 되면 그것이 사각형이 된다.

indices에서 Front주석부분에서 0 -> 1 -> 2 순서로 삼각형이 그어진다고 생각하면 된다.

여기에서 그어지는 순서를 추가하면 삼각형 한개가 더 생성된다.

이 순서대로 선을 긋게되면 다음과 같은 순서가 나타날것이다.

0->1->2 삼각형 한개 2->1->3 삼각형 한개

로 두개의 삼각형이 만들어지고, 이 삼각형 두개를 합치면 사각형 한개가 나타난다.


2D좌표를 3D좌표로 변환하기

2D를 3D로 변환하기 위해서는, 먼저 XYZ위치좌표를 이해해야 한다.

XYZ 좌표도

왼쪽 손가락을 엄지부터 중지까지 펼친다음, 중지를 안쪽으로 구부리면 더 쉽게 이해가 가능하다.

왼손좌표계

아마 대부분의 다이렉트X의 좌표계는 왼손 좌표계를 사용한다.

 

이러한 왼손 좌표계를 기준으로 XYZ축을 설계하여 사각형을 그려주면 된다.

xyz 축을 그려준 버텍스

NDC좌표계를 기준으로 사각형을 그리면 된다. Z축은 안쪽이 - 바깥쪽이 +라고 이해하면 된다.

NDC좌표

행렬 카메라연산을 기입하지 않으면, Z축이 0이 아닐경우 이미지가 화면에 표시되지 않는다.


행렬연산으로 카메라 제작하기

우리가 이미지를 바라보는 화면은 2D이다. 그러나 우리가 제작해야할 물체는 3D입방체 이다.

3D입방체를 2D화면으로 대입시키려면 Z축으로 들어가있는 깊이부분이 2D화면으로 끌어당겨져 와야한다.

카메라 좌표계를 기준으로, vertex위치를 수정해준다.

 

위와같이 Z축으로인해 화면차이가 날 경우, 두 원의 사이즈가 같을경우 라도. z축 위치에 따라 2D에서 볼 때 사이즈가 달라질것이다. 그러한 위치좌표를 보정해주는게 WVP 를 보정해준다고 하는데.

각각의 역할을 다음과 같다.

World행렬 객체의 위치와 방향을 3D월드 공간에 배치하는데 사용.
모델좌표를 월드좌표로 변환한다.
View 행렬 카메라 또는 뷰어의 위치와 방향을 정의한다.
월드 좌표를 뷰좌표로 변환한다.
Projection 행렬 3D월드를 2D화면에 투영하는 방법을 정의한다.
뷰 좌표를 투영좌표로 변환한다.

이 과정을 살펴보면,

 

World행렬에서는 객체의 위치와 방향을 3D월드 공간에 배치하는데 사용한다.

그럼으로 World 행렬에서 position값이 대입되지 않는다는 가정하에 World는 단위 행렬이 나타난다.

단위 행렬

View 행렬에서는 카메라의 위치와 카메라가 바라보는 방향 그리고 카메라의 업벡터를 연산하여 계산해준다.

 

즉, 카메라가 어떤위치에 있는지, 카메라가 어디를 바라보는지를 확인해서, 현재 뷰포트가 어떤식으로 나타나야 하는지를 연산하는것 이다.

 

업벡터는 카메라의 위쪽 을 나타내는것으로 행렬에 큰 영향을 끼치지는 않는다.

업벡터는 카메라가 회전할때. 회전의 기준축 을 담당한다.

 

projection 행렬에서는 현재 카메라의 FOV와 종횡비, 그리고 절도체를 잡아준다.

왼쪽에서부터, FOV, 종횡비, 절도체의 시작과 끝.

FPS게임을 할 때 대부분 살펴보았을 개념인데, 각각의 설명은 다음과 같다.

FovAngleY (시야각도) 필드의 각도를 라디안 단위로 설정한다. 카메라의 시야각도를 결정하며, 값이 클수록 카메라가 보는 범위가 넓어진다.
AspecRatio (종횡비) 뷰 공간의 가로 세로비율을 결정한다. 일반적으로 화면의 너비를 높이로 나눈값이다.
종횡비로 판단하는 이유는 뷰포트는 무한히 팽창하기 때문에
사이즈를 결정할 수 없기 때문이다.
NearZ와 FarZ(절도체 잡기) 투영 절단면을 설정한다. NearZ는 가까운면의 z좌표이고, FarZ는 먼 절단면의 z좌표이다. 두 값사이의 공간만이 최종적으로 화면에 렌더링 된다.

위 설명을 이미지로 나타내면 다음과 같다.

그리고, 절도체 이외의 범위에 대해서는 렌더링되지 않는다.


개념을 잡았으면 코드로 구현하면 된다.

우선, 전역변수 형태로 WVP로 작성하여 world, view, projection값을 대입하고 구조를 작성한뒤,

해당 struct를 활용하여 데이터를 전달한다.

 

위와같은 struct를 활용하여, wvp를 Buffer로 만들어서 VREM에 전달해야 GPU가 연산을 할 수 있다.

위와 같은 구조도로 Buffer를 제작한다.

상수버퍼는 다른 버퍼와 다르게, D3D11_SUBRESOURCE_DATE를 사용하지 않는다.

그 이유는, GPU에 의해 직접 액세스되며, CPU에서 해당 버퍼를 업데이트 하는 동안, GPU가 동시에 액세스하지 못하도록 하기 위해서 이다.

 

그래서, D3D111)SUBRESOURCE_DATA대신, UPDATESUBRESOURCE를 통해 실시간으로 데이터를 업데이트 시켜준다. 쉽개말해 특별관리 체제에 들어간다고 이해하면 편하다.

wvp를 초기화하고, 값을 대입해주어 뷰포트를 잡기 편하게 해준다.


wvp행렬을 VREM에 넘겨주기전에, 먼저 전치행렬로 바꾸어야 한다.

 

원래 행렬은 1과 2가 연산이 진행될때 1의 행에서 2의 열로 곱하는 방식으로 이루어지는데, 이것은 DIrect3D에서 이루어지는 방식이고,

 

이는 행우선(row_major)방식이라고 한다. 그러나, GPU, 그래픽스 API는 열 우선(column-major)방식을 사용하기 때문에, 행에서 열로 곱하는게 아닌, 열에서 행을 곱하는 계산방식을 따른다.

 

즉, api의 차이 때문에 발생하는 일이며. Direct3D에서 OpenGL로 넘어가는 과정에서의 연산차이 가 발생하기 때문에 한번 보정해주는것이다.

생성돤 WVP를 초기화해주고, Buffer을 통해 전달해준다.

그리고 Vertex에서 Pixel로 넘어가기 때문에, 모든곳에서 데이터를 활용하기 위해 Vertex에 데이터를 넘겨준다.


위에서 Buffer세팅이 끝났으면, 이제부터 HLSL을 처리해주어야 한다.

위처럼 입력하면 되는데, WVPBuffer방식의 cbuffer을 선언해주고, 받아온 데이터버퍼를 b0으로 해준다.

즉, b0레지스터에 받아와진 Buffer을, WVPBuffer방식으로 데이터순서를 처리하겠다 라는 의미임으로,

각 데이터의 순서가 맞다면, world, view, projection으로 분할하여 데이터를 저장하게 된다.

 

그리고, 버퍼에 받아와 데이터를 mul() 함수를 통해, 행렬곱을 하여 좌표를 처리하고, 해당값을 output의 pos에 각각 대입해준다.

 

행렬곱은 순서에 따라 좌표가 크게 틀어짐으로. 항상 w -> v -> p 순으로 곱샘을 하도록 유의해야한다.

 

위와같은 hlsl의 처리가 끝났다면, 결과는 다음과 같아진다.

728x90