DirectX Texture Tool 이용 CubeMap 제작

 

 

DirectX에서 제공하는 Texture Tool을 이용하면 SkyBox를 만들기 위한 .dds(Direct Draw Surface)포맷의 파일을 쉽게 만들 수 있다. 

 

 

 

◎ 큐브맵이란? 

큐브맵은 환경에 대한 반사를 나타내는 여섯 개의 사각형 텍스쳐 컬렉션을 말한다. 여섯 개의 사각형은 오브젝트를 둘러싸는 가상 큐브면을 형성하며 각각의 면은 월드 축의 방향을 따른 뷰를 나타낸다. (위,아래, 좌,우, 앞, 뒤)

 

출처 ; Unity Document > 그래픽스 > 렌더링 컴포넌트 > 큐브맵 

 

 

 

 

◎ Direct Texture Tool은 어디에 있는가!? 

 

C드라이브의 Program Files(x86)에 들어가보면 Microsoft DirectX SDK 폴더가 있고 

그 안에 Utilities\bin\x86(혹은 x64)를 열어보면 DxTex.exe 파일이 있다.

 

 

 

만약 이 폴더의 존재를 찾아볼 수 없다면? 깔아야 한다. 

 

 

https://www.microsoft.com/en-us/download/details.aspx?id=6812

 

DirectX SDK - (June 2010)

Download the complete DirectX SDK, which contains the DirectX Runtime and all DirectX software required to create DirectX compliant applications.

www.microsoft.com

이곳에 들어가서 DownLoad를 눌러서 설치하면 된다. 

 

 

 

 

◎ 큐브맵 만들기 

 

 

이제 큐브맵을 만들 수 있다!

 

 

파일에서 New Texture를 누르면 이제 생성할 수 있는데 가로, 세로, 그리고 밉맵 레벨을 설정해 주고 확인을 누른다. 

 

그러면 View->CubeMapFace에서 +x, -x, +y, -y, +z, -z 이렇게 6개의 축을 선택할 수 있다.

각각의 축을 선택해서 이제 하나씩 채워줄 것이다.

 

 

CubeMapFace를 지금 +X 축으로 설정해 놨으니 Open Onto This Cubemap Face를 눌러 해당 축에 맞는 이미지를 찾아서 넣어준다.

여섯 면을 다 채워줬으면 .dds 포맷으로 Save를 해준다. 그러면 완성이다. 

 

 

 

 

 

 

 

참고 자료;

 

https://docs.unity3d.com/kr/2018.4/Manual/class-Cubemap.html

 

큐브맵 - Unity 매뉴얼

큐브맵(Cubemap) 은 환경에 대한 반사를 나타내는 여섯 개의 사각형 텍스처 컬렉션입니다. 여섯 개의 사각형은 오브젝트를 둘러싸는 가상 큐브면을 형성합니다. 각각의 면은 월드 축의 방향을 따��

docs.unity3d.com

 

 

 

XNA Math 라이브러리와 XMVECTOR

Direct3D 11의 D3DX 라이브러리에는 Direct3D 9와 10의 D3DX와는 다르게 개별적으로 개발된

XNA Math 라는 벡터 수학 라이브러리가 제공된다. 

 

 

 

 

 

 

SIMD의 명령들은 128비트 너비의 SIMD(Single instruction multiple data) 레지스터들을 이용해서 한 명령에서 32비트 float나 int 네 개를 한 번에 처리할 수 있다. 이는 벡터 계산에 아주 유용하다.

SIMD가 아닌 경우에는 32-비트의 실수를 4번 더해야 하지만 벡터의 덧셈 시 SIMD를 이용하면 두 개의 4요소 벡터(Vector4) 를 더할 경우 한 번의 덧셈 명령으로 처리가 가능하다는 것이다. 

 

SIMD?

더보기

병렬 프로세서의 한 종류로, 하나의 명령어로 여러 개의 값을 동시에 계산하는 방식, 컴퓨터를 일컫는다.

SSE (Streaming SIMD Extensions)는 이런 SIMD 구조의 명령을 프로세서에 도입한 것으로 128bit짜리 SIMD 전용 레지스터가 추가된 것이다. 

 

 

 

 

 

◎ 사용

코드에서 이 라이브러리를 사용하려면 헤더파일 xnamath.h를 추가하기만 하면 된다.

#include <xnamath.h>

모든 코드가 헤더 파일 안에 inline으로 구현되어 있으므로 라이브러리 파일을 따로 링크할 필요가 없다. 

물론 <d3dx10.h>를 포함시키고 <d3dx10.lib>를 링크해서 XNA Math 라이브러리 대신에 D3DX10 Math 함수들을 사용하는 것도 여전히 가능하다. 

 

 

 

 

 

◎ 벡터 형식들

XNA Math에서 핵심 벡터 형식은 SIMD 하드웨어 레지스터들에 대응되는 XMVECTOR이다.

XMVECTOR는 하드웨어 레지스터에 대응하는 32-비트의 실수 벡터로 32-비트 실수 또는 정수 요소들의 벡터를 표현하기 위한 '자료형'이다. (구조체가 아니다.) 

추가로 덧붙이자면 뒤에 나오는 XMMATRIX는 구조체이다.

 

XMVECTOR는 128비트짜리 형식으로 하나의 SIMD 명령으로 처리되는 네 개의 32비트 부동소수점 값들로 이루어져있다.

SSE2를 사용할 수 있는 경우에서 XMVECTOR는

typedef __m128 XMVECTOR;

위와 같이 정의되어 있다.

 

__m128?

더보기

특별한 SIMD 형식으로 계산을 수행할 때 이 형식의 벡터들은 반드시 SIMD의 장점을 갖고 연산을 할 수 있다. 

이 XMVECTOR는 사용할 때 16바이트 경계에 정렬되어야 한다.

 

왜냐하면 정렬이 되어있어야 SIMD 명령어를 이용해 데이터를 벡터에 패킹하여 한 번의 명령으로 동시에 처리할 수 있기 때문이다.

이 정렬은 지역 변수와 전역 변수에는 정렬이 자동으로 이루어지게 된다.

그러나  class의 멤버나 구조체의 멤버변수의 경우에는 이것 보다는 XMFLOAT를 사용하는 것이 더 바람직하다. 

 

 

 

왜?

더보기

(Microsoft Docs의 DirectXMath 中)

SIMD 처리는 데이터를 SIMD 레지스터에 load하고 결과를 추출하기 전에 완전히 처리할 때 가장 효율적이다.

SIMD processing is most efficient when data is loaded into the SIMD registers and fully processed before extracting the results. 

스칼라와 벡터 형식 간의 변환은 비효율적이므로 필요할 때만 수행하는 것이 좋다.

Conversion between scalar and vector forms is inefficient, so we recommend that you do it only when required. 

이러한 이유로 스칼라 값을 생성하는 DirectXMath 라이브러리의 함수는 스칼라 결과가 결과 벡터에 복제되는 벡터 형태로 리턴된다. 

For this reason, functions in the DirectXMath library that produce a scalar value are returned in a vector form where the scalar result is replicated across the resulting vector

 

그래서 스칼라 값이 필요한 경우에 이와 같은 내용을 수행하는 방법에 대한 몇 가지 선택사항으로 XMFLOAT를 이용해 벡터를 메모리 구조에 저장하고 다시 읽어오는 방식을 사용. 

 

 

 

typedef struct _XMFLOAT3 
{
	FLOAT x;
	FLOAT y;
	FLOAT z;
} XMFLOAT3;

예를 들면 XMFLOAT3(3차원)은 위와 같이 정의한 후 사용한다. 

XMVECTOR나 XMMATRIX는 operator(연산자)들이 오버로드 되어있지만 XMFLOAT를 이용해 사용하는 경우 추가로 생성자들이나 연산자 관련 함수를 추가해 준다. 

 

이 XMFLOAT를 이용한 형식은 계산할 때 SIMD의 장점을 갖고 연산할 수가 없으므로 SIMD를 이용하고 싶으면 이 형식의 인스턴스를 XMVECTOR 형식으로 변환해줘야 한다. 

 

이를 위해 XNA Math는 여러 함수를 제공한다.

또한 XNA Math는 XMVECTOR 인스턴스에 담긴 자료를 XMFLOAT* 형식들로 변환하는 저장 함수들도 제공한다.

 

 

 

간략정리

더보기

간략정리

1. 지역 변수와 전역 변수에서는 XMVECTOR를 이용

2. 클래스 자료 멤버에는 XMFLOAT2나 XMFLOAT3, XMFLOAT4를 사용

3. 계산 수행 전 함수들을 이용해 XMFLOAT*를 XMVECTOR로 변환

4. '계산'은 XMVECTOR 인스턴스들을 이용해서 수행

5. XMVECTOR를 XMFLOAT*로 변환하려면 저장 함수들을 이용

 

 

 

 

 

◎ 적재 및 저장 함수

- XMFLOAT*의 자료를 XMVECTOR로 적재(Load)하는 함수

XMVECTOR XMLoadFloat2 (Const XMFLOAT2 *pSource);

XMVECTOR XMLoadFloat3 (Const XMFLOAT3 *pSource);

XMVECTOR XMLoadFloat4 (Const XMFLOAT4 *pSource);

이외에도 Color나 UINT 배열을 XMVECTOR에 load하는 함수들도 존재한다.

 

 

- XMVECTOR의 자료를 XMFLOAT*로 저장(Store)하는 함수

FLOAT XMVectorGetX (FXMVECTOR V);
FLOAT XMVectorGetY (FXMVECTOR V);
FLOAT XMVectorGetZ (FXMVECTOR V);
FLOAT XMVectorGetW (FXMVECTOR V);

XMVECTOR XMVectorSetX (FXMVECTOR V, FLOAT x);
XMVECTOR XMVectorSetY (FXMVECTOR V, FLOAT y);
XMVECTOR XMVectorSetZ (FXMVECTOR V, FLOAT z);
XMVECTOR XMVectorSetW (FXMVECTOR V, FLOAT w);

 

 

 

 

 

◎ 매개변수 전달과 상수 벡터 

SIMD의 장점을 이용하려면 함수에 XMVECTOR 형식의 매개변수를 전달할 때 지켜야 할 규칙이 있다.

이 규칙들은 플랫폼바다 다른데 플랫폼 독립적 코드를 위해 XMVECOTR 형식의 매개변수에 대해 CXMVECTOR, FXMVECTOR 형식을 사용한다.

 

Windows의 경우

// 32비트 Windows
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;

//64비트 Windows
typedef const XMVECTOR& FXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;

 

이 둘의 차이는 XMVECTOR의 복사본을 직접 전달할 수 있는지, 참조를 전달해야 하는지이다.

구체적인 또 하나의 규칙은 한 함수의 처음 세 개의 XMVECTOR 매개변수는 반드시 FXMVECTOR형식이어야 한다. 그 외의 XMVECTOR 매개변수는 반드시 CXMVECOTR 형식이여야 한다. 

 

예를 들어 7개의 매개변수를 받는 함수가 있으면 위의 규칙에 따라 처음 세 개는 FXMVECTOR, 나머지 네 개는 CXMVECOTR 형식이어야 하며 XMVECTOR 매개변수들 사이에 다른 매개변수가 끼어있을 경우에도 처음 세 개의 XMVECTOR 매개변수는 반드시 FXMVECTOR 형식이고 나머지 XMVECTOR 매개변수는 CXMVECOTR 형식이어야 한다. 

 

 

또한 상수(const) XMVECTOR 인스턴스에는 반드시 XMVECTORF32 형식을 사용해야 한다.

초기화 구문을 사용하고자 할 때에는 항상 XMVECTORF32를 사용해야 한다.

XMVECTORF32는 16바이트 경계로 정렬된 구조체로, XMVECTOR로의 변환 연산자를 지원한다. 

 

 

 

 

 

◎ 기타 제공 함수

XNA Math 라이브러리는 XMVECTOR를 이용한 벡터 덧셈, 뺄셈, 스칼라 곱셈을 위해 중복적재된 연산자들을 제공한다.

또한 XNA Math 라이브러리는 벡터의 길이, 벡터 길이의 제곱, 두 벡터의 내적, 두 벡터의 외적, 벡터 정규화를 위한 편의용 함수들도 제공한다.

 

XMVECTOR XMVector3Length(FXMVECTOR V);
XMVECTOR XMVector3LengthSq(FXMVECTOR V);
XMVECTOR XMVector3Dot (FXMVECTOR V1, FXMVECTOR V2);
XMVECTOR XMVector3Cross (FXMVECTOR V1, FXMVECTOR V2);
XMVECTOR XMVector3Normalize (FXMVECTOR V);

 

 

 

 

 

 

 

 

 

참고 출처;


https://docs.microsoft.com/ko-kr/windows/win32/dxmath/pg-xnamath-getting-started?redirectedfrom=MSDN#type_usage_guidelines_

 

 

Getting started (DirectXMath) - Win32 apps

Getting started (DirectXMath) In this article --> The DirectXMath Library implements an optimal and portable interface for arithmetic and linear algebra operations on single-precision floating-point vectors (2D, 3D, and 4D) or matrices (3×3 and 4×4). The l

docs.microsoft.com


- https://ko.wikipedia.org/wiki/SIMD

 

SIMD - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 둘러보기로 가기 검색하러 가기

ko.wikipedia.org


- Direct11을 이용한 3D게임프로그래밍 (저; 프랭크 D. 루나, 역; 류광, 출판사; 한빛미디어)


 

 

 

렌더링 파이프라인(Rendering Pipeline)

 

GPU를 사용해 리소스를 2D 이미지로 렌더링 하는 과정이다.

파이프라인은 여러 개의 파이프라인 단계로 구성되어 있으며 프로그램 가능 단계와 고정 프로그램 단계로 구분된다. 

 

 

 

 

렌더링 파이프라인을 구성하는 단계들과 관련 GPU 메모리 자원들

 

 

고정 프로그램 단계?

Direct3D에서 모든 처리가 진행되며 응용 프로그램에서 변경할 수 없는 단계

- 입력 조립(IA) 단계, 테셀레이터 (TS) 단계, 스트림 출력(SO) 단계, 래스터라이저(RS) 단계, 출력 병합(OM) 단계

 

프로그램 가능 단계?

응용 프로그램에서 쉐이더 프로그램을 통해 제공해야 하는 단계

- 정점 쉐이더(VS) 단계, 헐 쉐이더(HS) 단계, 도메인 쉐이더(DS) 단계, 기하 쉐이더(GS) 단계, 픽셀 쉐이더(PS) 단계

 

 

위의 파이프라인에서 오른쪽은 자원 메모리 풀을 뜻한다. 자원 메모리 풀에서 파이프라인의 단계로 가는 화살표는  그 단계가 자원을 입력으로 사용할 수 있음을 뜻하고 파이프라인의 단계에서 자원으로 가는 화살표는 그 단계가 GPU 자원에 자료를 기록할 수 있음을 뜻한다. 

 

 

 

◎ 입력 조립기 (Input Assembler) 단계

고정 함수 단계이다. 응용 프로그램에서 제공받은 정점 버퍼의 정점 데이터(프리미티브 데이터 : 점, 선, 삼각형)를 다른 파이프라인 단계에서 사용할 프리미티브(선 리스트, 삼각형 리스트, 삼각형 스트립, 인접성을 가지는 프리미티브 등)로 조립한다. 

즉, 메모리에서 기하 자료(정점 데이터와 Index(색인))를 읽어 기하학적 기본도형(삼각형, 선분 등)을 조립한다. 

 

그럼 정점이란 무엇일까?

더보기

Direct3D에서의 정점은 공간적 위치, 즉 위치 값 이외의 정보를 담고 있으며 이를 통해 좀 더 복잡한 렌더링 효과를 구현할 수 있다. 예를 들면 조명 구현을 위해 정점에 법선 벡터를 추가하거나 텍스처를 적용하기 위해 텍스처 좌표를 추가하는 식으로 사용할 렌더링 효과에 따라 특정 정보를 추가할 수 있는 유연성을 갖고 있다. 

 

 

 

◎ 정점 쉐이더 (Vertext Shader) 단계

이 단계에서는 입력 조립 단계에서 출력되는 Primitive의 각 정점에 대한 연산을 수행한다. 

이 정점 쉐이더는 항상 모든 정점들에 대해 한 번씩 실행된다. 또한 하나의 정점에 대해 한 번만 호출되며 하나의 출력 정점을 생성될 뿐 아니라 파이프라인 단계에서 항상 수행이 되어야 하는 단계이다. 따라서 정점에 대한 변환이 필요하지 않아도 정점 쉐이더를 생성해 연결해야 한다. 

 

이 정점 셰이더 함수의 구체적인 내용은 프로그래머가 구현해서 GPU에 전달하게 된다. 그 함수는 각 정점에 대해 GPU에서 실행되기 때문에 속도가 빠르다. 

변환(Transformation), 스키닝(Skinning), 조명(Vertex Lighting) 등 수많은 특수 효과를 정점 쉐이더에서 수행할 수 있다. 정점 쉐이더에서 입력 정점 자료는 텍스쳐라든가 변환 행렬, 장면 광원 정보 등 GPU 메모리에 담긴 다른 자료에도 접근할 수 있다. 

 

더보기

이 단계에서 일어나는 작업 중 변환이 어느 물체의 로컬 좌표를 월드 좌표로, 월드 좌표를 뷰 스페이스 좌표로 바꿔주고 투영 변환등이 일어나는 변환 작업이다.

 

 

 

 

◎ 테셀레이션 단계

테셀레이션이란 한 메시의 삼각형들을 더 잘게 쪼개서 새로운 삼각형들을 만드는 과정을 말한다.

 

테셀레이션의 장점은

  1.  LOD 구현이 가능하다.
    더보기
    LOD란 Level-of-detail를 말한다.
    카메라에 가까운 삼각형들은 테셀레이션을 적용해 더욱 세밀한 구현을 적용하고 멀리 있는 삼각형들은 테셀레이션을 적용하지 않는 방식의 세부 수준 메커니즘을 구현해 눈에 띄는 부분에 대해서만 삼각형을 더 투여할 수 있게 된다. 
  2.  Low-poly 메시, 적은 수의 삼각형들로 이루어진 메시를 담아두고 즉석에서 삼각형들을 추가해 메모리를 적용할 수 있다.
  3.  애니메이션, 물리 처리 같은 연산들을 단순한 Low-Poly 메시에 대해 수행하고, 테셀레이션 된 High-Poly 메시는 렌더링에만 사용해 계산량을 줄일 수 있다. 

 

 

 

◎ 기하 셰이더 (Geometry Shader) 단계

이 단계는 정점 셰이더의 처리를 거친 정점 데이터를 입력받는다. 그리고 입력받은 정점에 정보를 추가하거나 삭제해 입력 기본도형을기본 도형을 다른 여러 기본 도형들로 확장할 수도, 특정 조건에 따라서는 입력된 기본 도형을 출력하지 않고 버릴 수도 있다. 

기하 셰이더의 흔한 용도는 하나의 점이나 선분을 하나의 사각형으로 확장하는 것이다. 

 

 

 

◎ 래스터라이저(Rasterizer) 단계

이 단계는 투영된 3차원 삼각형으로부터 픽셀 색상들을 계산해 내는 것이다. 

Rasterization을 하는 동안 각 프리미티브를 구성하는 정점은 픽셀로 변환되고 프리미티브의 내부에 해당하는 점들은 보간을 통해 픽셀로 변환된다.

 

과정

1. 원근 투영 나누기(z 나누기)

2. 카메라 절두체를 벗어나는 점(Pixel)들을 클리핑(Clipping)

3. Primitive를 2차원 Viewport로 매핑

4. Primitive의 모든 픽셀들에 대해 픽셀 쉐이더를 호출

 

 

 

 

◎ 픽셀 셰이더 (Pixel Shader) 단계

각 픽셀의 데이터(기본적으로 색상)를 생성한다. 프로그래머가 작성해서 GPU에서 실행하는 프로그램으로 각각의 필셀 단편(pixel fragment)마다 실행된다. 

상수 변수, 텍스처 데이터, 또는 픽셀 출력 데이터 등을 결합해 출력 색상을 결정한다.

이 단계에서 픽셀 조명 계산 또는 픽셀에 대한 후처리를 할 수 있다. 

 

하나의 프리미티브를 구성하는 각 픽셀에 대해 픽셀 쉐이더를 한 번씩 호출한다. 

다중 샘플링을 사용한다면 깊이/스텐실 테스트는 각 서브픽셀에 대해 한 번씩만 수행되며 다중 샘플링을 사용해도 이 픽셀 쉐이더는 하나의 픽셀에 대해 한 번만 호출된다.

 

 

 

 

◎ 출력 병합기 (Output Merge) 단계

픽셀 셰이더가 생성한 픽셀 단편들은 이 단계로 입력된다. 최종적으로 픽셀의 색상을 생성해 렌더 타깃으로 출력하는 단계이다. 이 단계에서 일부 픽셀 단편들이 깊이 판정이나 스텐실 판정에 의해 버려지게 되며 버려지지 않은 픽셀 단편은 후면 버퍼에 기록된다.

흔히 말하는 블렌딩도 이 단계에서 일어난다.

더보기

블렌딩은 새 픽셀이 후면 버퍼의 기존 픽셀을 완전히 덮어 쓰는 것이 아니라 두 픽셀을 일정한 공식에 따라 혼합한 결과를 기록하는 것을 말한다. 

렌더 타겟의 픽셀 색상과 출력(픽셀 쉐이더) 색상을 결합한다. 

 

- 깊이-스텐실 검사(Depth-Stencil Testing)

픽셀이 그려져야 하는지를 결정하기 위해 깊이 값과 스텐실 값 데이터를 사용한다.

하나의 깊이/스텐실 버퍼만 활성화 되며 깊이-스텐실 버퍼에 스텐실 요소가 없으면 스텐실 검사는 항상 성공한다.

또한 깊이-스텐실 버퍼가 파이프라인에 연결되지 않으면 스텐실 검사는 항상 성공한다. 

 

깊이 검사?

더보기

z = min(Viewport.MaxDepth, max(Viewport.MinDepth, z))

출력 픽셀의 깊이 값을 깊이 버퍼의 같은 위치의 깊이 값과 비교한다. 

비교의 결과에 따라 출력 픽셀을 렌더 타깃에 출력하거나 출력하지 않는다.

 

 

 

 

 

 

 

 

참고 출처

Direct11을 이용한 3D게임프로그래밍 (저; 프랭크 D. 루나, 역; 류광, 출판사; 한빛미디어)

+ Recent posts