※ 아래의 내용들은 DirectX 11을 이용한 3D 게임 프로그래밍 입문 책의 내용을 바탕으로 작성된 것입니다.
8장 텍스처 적용
- 텍스처 매핑(8.1절 351p)
- 메시의 삼각형 면에 이미지 자료를 입히는 기법
=> 장면의 세부도와 사실감을 크게 높일 수 있다.
- 2차원 텍스처는 자료 원소들의 행렬(2차원 배열)이다.
- 2차원 텍스처의 한 가지 용도는 2차원 이미지 자료를 저장하는 것으로 그런 경우 텍스처의 각 원소는 한 픽셀의 색상을 담는다.
- 텍스처는 이미지 자료 저장만을 얘기하는 것이 아니라 훨씬 범용적이다.
- 텍스처가 단순한 자료 배열인 것만은 아니다.
=> 텍스처에 밉맵 수준들이 존재할 수 있으며, GPU는 필터링, 다중표본화 등의 특별한 연산을 텍스처에 적용할 수 있다.
=> 텍스처에 아무 자료나 담을 수 있는 것은 아니다.
==> 텍스처에는 특정 형식(DXGI_FORMAT이라는 열거형으로 지정)을 따르는 자료만 담을 수 있다.
- 렌더링 파이프라인에는 텍스처를 묶을 수 있는 단계들이 여럿 있다.
ex) 텍스처를 렌더 대상으로 묶는 것(D3D가 텍스처에 렌더링하는 경우)과 셰이더 자원으로 묶는 것(셰이더 안에서 텍스처를 추출하는 경우)
- 텍스처 자원이 파이프라인 단계에 직접 묶이는 것이 아니라 텍스처가 연관된 자원 뷰를 파이프라인 단계에 묶는다.
=> 어떤 용도이든 D3D에서 텍스처를 사용하려면 텍스처의 초기화 시점에서 그 텍스처의 자원 뷰(resource view)를 생성해야 한다.
=> 이런 추가 절차는 기본적으로 효율성을 위한 것이다.
==> SDK 문서에는 "이렇게 하면 실행시점 모듈(런타임)과 구동기(드라이버)가 유효성 점검과 매핑을 뷰 생성시점에 수행할 수 있기 때문에 결속 시점에서의 형식 점검이 최소화된다." 라고 나와있다.
=> 따라서 텍스처를 렌더 대상과 셰이더 자원으로 사용하는 예제를 위해서는 두 개의 뷰를 생성할 필요가 있다. (렌더 대상 뷰, 셰이더 자원 뷰)
- 자원 뷰들은 본질적으로 두 가지 일을 한다.
1. D3D에게 자원의 사용 방식(즉, 파이프라인의 어떤 단계에 묶을 것인지)을 알려주는 것
2. 생성 시점에서 무형식을 지정한 자원 형식의 구체적인 형식을 결정하는 것
=> 무형식 자원의 경우 텍스처 원소를 한 파이프라인 단계에서는 부동소수점 값으로 사용하고 다른 단계에서는 정수로 사용하는 것이 가능함을 뜻한다.
==> 이는 본질적으로 자료의 재해석 캐스팅(C++의 reinterpret_cast 같은)에 해당한다.
- 무형식 자원은 꼭 필요한 경우에만 사용해야 한다.
=> 형식이 완전하게 지정된 자원은 생성 시 지정된 형식으로만 사용할 수 있으며, 그러면 런타임은 자원에 접근을 최적화할 수 있다.
- 어떤 자원을 위한 뷰를 생성하려면, 애초에 자원을 그 뷰에 맞는 결속 플래그로 생성해야 한다.
- 텍스처 좌표(8.2절 353p)
- D3D는 u축이 이미지의 가로, v축이 이미지의 세로 방향인 텍스처 좌표계를 사용한다.
- 0 ≤ u, v ≤ 1 인 텍스처 좌표(u, v)로 식별되는 텍스처의 한 요소를 텍셀(texel; texture element)이라고 부른다.
=> 보통의 좌표계와 달리 v축은 위에서 아래로 향해 있다.
=> 또한, 텍스처 좌표는 [0, 1] 구간으로 정규화된 좌표 성분들을 사용한다.
==> 텍스처 이미지의 크기에 독립적인 좌표계를 위해
=> [0, 1] 구간 바깥의 값을 사용하는 방법도 있으나 나중에 설명함.
- 텍스처 매핑을 위해서는 각각의 3차원 삼각형마다 그 삼각형에 입힐 텍스처 이미지상의 삼각형을 지정해야 한다.
=> 각 3차원 삼각형마다 하나씩의 2차원 텍스처 삼각형이 연관된다.
- 여러 종류의 서로 무관한 이미지들을 하나의 커다란 텍스처 맵(텍스처 대지도(texture altas])에 모아두고 각 부분 이미지를 서로 다른 여러 물체에 적용하기도 한다.
=> 텍스처의 어떤 부분이 삼각형에 입혀질 것인지 결정하는 것이 바로 텍스처 좌표이다.
- 텍스처 생성 및 활성화(8.3절 356p)
- 일반적으로 텍스처 자료는 디스크에 저장된 이미지 파일에 읽어서 ID3D11Texture2D 객체에 적재한다.
- 텍스처 셰이더 자원 뷰를 생성하고 해당 뷰를 파이프라인에 묶는 과정을 간략히 하면 아래와 같다.
1. ID3DX11CreateTextureFromFile을 호출해서 디스크에 저장된 이미지 파일로부터 ID3D11Texture2D 객체 생성
2. ID3D11Device::CreateShaderResourceView를 호출해서 그 텍스처에 대한 셰이더 자원 뷰 생성
=> 위 두 단계를 한번에 수행해주는 함수 D3DX11CreateShaderResourceViewFromFile()
- 텍스처 대지도를 사용하면 한 번의 그리기 호출로 좀 더 많은 기하구조를 그릴 수 있으므로 성능이 향상된다.
=> 그리기 호출에는 추가부담이 존재하므로, 이런 기법을 이용해서 호출 횟수를 줄이는 것이 바람직하다.
- 텍스처 자원은 픽셀 셰이더 이외의 셰이더(정점, 기하 등)에서도 사용할 수 있다.
=> 일단 지금은 픽셀 셰이더에서 사용하는 것만 생각한다.
- 필터(8.4절) - 확대(8.4.1절 359p)
- 통상적인 텍스처 매핑에서 텍셀, 즉 텍스처 맵의 요소들은 하나의 연속된 이미지로부터 추출하는 이산적인 색상 표본이라 할 수 있다.
- 텍셀을 면적을 가진 하나의 직사각형이라고 생각하는 것은 바람직하지 않다.
=> 실제 텍셀 점과 정확히 일치하지 않는 텍스처 좌표(u, v)를 사용한다면?
각 픽셀에는 정점 텍스처 좌표를 삼각형을 따라 보간해서 결정된 고유한 텍스처 좌표가 부여되는데, 텍셀 점과 정확히 일치하지 않는 텍스처 좌표가 존재할 수 있다. (ex: 화면 해상도는 1024 x 1024, 벽의 텍스처 이미지는 256x256일 때, 해당 벽이 화면을 가득 채우게 되는 경우)
그런 픽셀들의 색을 결정하는 한 가지 방법은 픽셀 부근에 있는 텍셀들의 색들을 보간하는 것이다.
=> 그래픽 하드웨어에서 지원하는 두 가지 종류의 보간 방법
1. 상수 보간
2. 선형 보간
- 2차원 텍스처에서는 겹선형 보간(bilinear interpolation)이라는 선형 보간 기법을 사용한다.
=> 겹선형 보간에서는 네 텍셀 사이의 한 지점을 가리키는 텍스처 좌표가 주어졌을 때 u 방향으로 1차원 선형 보간을 수행하고 v 방향으로 1차원 선형 보간을 수행해 최종 결과를 얻는다.
- 가상 카메라 장면을 자유로이 돌아다닐 수 있는 "대화식 3차원 프로그램"에서는 확대 문제가 필연적으로 발생한다.
=> 어떤 게임에서는 과도한 확대를 피하기 위해 가상 카메라가 표면에 일정 거리 이하로 다가가지 못하게 하는 우회책을 사용한다.
=> 확대 문제를 완화하는 데에는 더 높은 해상도의 텍스처를 사용하는 것이 도움이 된다.
- 텍스처 적용의 맥락에서, 텍셀들 사이의 텍스처 좌표에 대한 텍스처 값을 상수 보간으로 구하는 것을 점 필터링(point filetering)이라 부른다.
- 같은 경우에, 선형 보간으로 구하는 것을 선형 필터링(linear filetering)이라고 부르기도 한다.
=> D3D가 사용하는 용어도 점 필터링, 선형 필터링이다.
- 필터(8.4절) - 축소(8.4.2절 361p)
- 축소(minification)는 확대의 반대로 너무 많은 텍셀들이 너무 작은 픽셀들에 사상되는 것을 말한다.
=> 이 경우에도 상수 보간 필터링이나 선형 보간 필터링이 적용된다.
- 축소의 경우 선형 혹은 상수 보간 필터링 이외의 처리가 가능하다.
=> 텍셀 크기의 맵을 일종의 평균 하향표본화(downsampling)을 통해 더 작은 맵으로 줄일 수 있다.
=> 이 점을 이용해서 축소를 효율적으로(대신 메모리를 조금 더 사용한다) 근사하는 기법이 바로 밉매핑(mipmapping)이다.
- 밉매핑에서는 텍스처 초기화 시점(또는 생성 시점)에 주어진 이미지를 하향표본화해서 텍스처의 더 작은 버전들을 만든다.
=> 그런 버전들을 밉맵 수준(mipmap level)들이라 부르며, 그러한 밉맵 수준들이 하나의 밉맵 사슬(mipmap chain)을 형성한다.
- 즉, 평균을 이용한 하향표본화로 밉맵 수준들을 생성하는 작업은 렌더링 이전에 미리 수행되는 것이다.
=> 이후 렌더링 도중에 텍스처를 적용할 때 그래픽 하드웨어는 응용 프로그램이 제공한 밉맵 설정에 기초해서 다음 두 방식 중 하나를 적용한다.
1. 화면에 투영된 기하구조의 해상도에 가장 잘 부합하는 하나의 밉맵 수준을 선택해서 텍스처로 사용한다.(필요시 상수 보간 or 선형 보간 적용) 이처럼 가장 가까운 밉맵 수준을 사용하는 방식을 밉맵의 점 필터링이라 부른다.(텍스처 적용 시 상수 보간을 통해 가장 가까운 텍셀 값을 선택하는 점 필터링과 비슷한 방식이기 때문)
2. 화면에 투영된 기하구조의 해상도에 가장 잘 부합하는 이웃한 두 밉맵 수준(하나는 화면 기하구조 해상도보다 큰 것, 다른 하나는 더 작은 것)을 선택한다. 두 밉맵 수준에 대해 상수 필터링이나 선형 필터링 적용해서 두 개의 표본(텍스처 색상)을 뽑는다. 마지막으로 두 표본을 보간해서 최종 색상 결정.
이처럼 가장 가까운 두 밉맵 수준을 선형 보간하는 방식을 밉맵의 선형 필터링이라 부른다.(텍스처 적용 시 가장 가까운 두 픽셀 값을 보간하는 선형 필터링과 비슷한 방식이기 때문)
=> 위처럼 밉맵 사슬에서 가장 적합한 밉맵 수준을 선택하면 축소의 필요성이 크게 줄어든다.
- 필터(8.4절) - 축소(8.4.2절 361p) - 밉맵 생성(8.4.2.1절 363p)
- D3DX11 함수들은 원본 자원 파일에 밉맵 사슬이 없으면 자동으로 밉맵 사슬을 생성해준다.
- 또한, 밉맵 적용이 활성화되어 있으면 하드웨어가 자동으로 적절한 밉맵 수준을 선택해서 적용한다.
- 필터(8.4절) - 비등방 필터링(8.4.3절 364p)
- 다각형의 법선 벡터와 카메라의 시선 벡터 사이의 각도가 클 때(ex: 다각형이 시야 창과 수직에 가까울 때) 발생하는 왜곡 현상이 완화된다.
- 비등방 필터링은 비용이 더 크긴 하지만, 왜곡에 의한 결함을 제거함으로써 품질이 크게 향상된다면 시도해 볼 만 하다.
- 텍스처 표본 추출(8.5절 364p)
- 효과 파일에서 Texture2D 객체는 하나의 2차원 텍스처를 대표한다.
=> 텍스처에 연관된 다른 객체로는 표본추출기(sampler)를 뜻하는 SamplerState 객체가 있다.
=> 표본추출기 객체는 무엇보다도 텍스처에 적용할 필터링에 대한 설정을 담는다.
- 다른 렌더 상태들처럼 표본추출기 상태도 초기화 시점에서 생성해 두는 것이 바람직하다
- 텍스처와 재질(8.6절 366p)
- 텍스처를 재질/조명 시스템과 통합할 때에는, 텍스처 색상을 주변광과 분산광으로 변조(modulation)하되, 반영광으로는 변조하지 않도록 하는 것이 일반적이다
=> 이런 방식을 흔히 변조 후 가산[modulate with late add] 이라고 부른다.
- 텍스처 좌표 지정 모드(8.8절 374p)
- 텍스처와 상수 또는 선형 보간의 조합은 하나의 벡터 값 함수 T(u,v) = (r, g, b, a)를 정의한다.
=> 텍스처 좌표 (u, v)∈[0,1]^2 이 주어졌을 때, 텍스처 함수 T는 하나의 색상 (r, g, b, a)를 돌려준다.
=> 이 함수의 정의역 바깥의 좌표가 주어졌을 때의 처리 방식을 좌표 지정 모드(address mode) 이라고 부르며, D3D가 지원하는 좌표 지정 모드는 순환(wrap), 테두리 색(border color), 한정(clamp), 거울(mirror) 네 가지이다.
1. 순환 모드에서는 이미지가 정수 경계마다 반복(즉, 좌표 성분이 1을 넘기면 다시 0부터 증가하고, 반대로 0보다 작으면 1부터 감소하는 식으로 '순환'된다.)
2. 테두리 색 모드에서는 [0,1]^2 바깥의 텍스처 좌표 (u, v)가 입력되면 텍스처 함수는 프로그래머가 지정한 색을 돌려줌
3. 한정 모드에서는 텍스처 함수는 [0,1]^2 바깥의 좌표 (u, v)에 대해 색 T(u0, v0)를 돌려주는데 여기서 (u0, v0)는 [0,1]^2 범위 안에서 (u, v)에 가장 가까운 점이다.
4. 거울 모드에서는 이미지가 각 정수 경계마다 반사, 즉 반대 방향으로 반복된다.
- 좌표 지정 모드는 항상 적용되며(디폴트값은 순환 모드), 따라서 [0, 1] 구간 바깥의 텍스처 좌표는 항상 적절한 의미를 갖는다.
- 순환모드는 가장 흔히 사용되며, 텍스처를 일정한 표면에 반복해서 깔 수 있다.
=> '타일링(tiling)'이 가능하다.
==> 타일링은 추가적인 자료 없이 텍스처의 해상도를 높이는 효과를 낸다.
==> 타일링을 적용할 때 중요한 것은 텍스처에 이음매가 없도록(seamless) 하는 것이다.
- 좌표 지정 모드는 표본추출기 객체에서 지정한다.
=> u 성분과 v 성분에 대해 좌표 지정 모드를 따로 설정할 수도 있다.
- 텍스처 변환(8.9절 378p)
- 텍스처 좌표는 텍스처 평면의 2차원 점을 의미하므로 다른 점처럼 이동, 회전, 비례가 가능하다.
=> 텍스처 좌표 변환을 수행하는 방법은 점이나 벡터의 변환에서와 동일하다. 즉, 원하는 변환을 수행하는 행렬을 만들어서 텍스처 좌표 벡터에 곱하면 된다.
- 압축 텍스처 형식들(8.11절 382p)
- 게임의 가상 세계가 커져서 수천 장의 텍스처가 필요해지면 텍스처를 위한 GPU 메모리 요구량도 증가한다.
=> 텍스처를 빠르게 적용하기 위해서는 텍스처들을 모두 GPU 메모리에 보관해두어야 함을 기억할 것.
- 높은 메모리 요구량을 완화하기 위해 D3D는 일곱 가지 압축 텍스처 형식 BC1, BC2, BC3, BC4, BC5, BC6, BC7을 지원한다.
=> 압축된 텍스처는 렌더링 파이프라인의 셰이더 단계에 대한 입력으로만 사용할 수 있다.
=> 위의 블록 압축 알고리즘들은 4x4 픽셀 블록 단위로 작동하므로 텍스처의 가로, 세로 모두 4의 배수여야 한다.
- 압축 형식들의 장점은, 압축된 자료를 GPU 메모리에 담아 두고 필요할 때 GPU에서 즉석으로 압축을 풀 수 있다는 점이다.
- 압축되지 않은 이미지 자료를 담은 파일이 있다면, D3DX11CreateShaderResourceViewFromFile 함수 호출 시 pLoadInfo 매개변수를 적절히 설정함으로써 D3D가 즉석에서 자료를 압축하게 만들 수 있다.
- 압축되지 않은 자료를 담은 것이 BMP 파일 ↔ 이미 압축된 자료를 담은 DDS(Direct Draw Surface) 형식의 파일
=> DDS 형식의 파일을 사용할 수도 있다.
=> DirectX 텍스처 도구(DxTex.exe)로 만들 수 있음.
- DDS 파일이 앞에서 말한 형식들(BC1, ... , BC7) 중 하나로 압축된 이미지 자료를 담고 있는 경우 pLoadInfo 매개변수에 그냥 0을 지정하면 됨.
- DirectX 텍스처 도구로 밉맵 수준들을 생성해서 DDS 파일로 저장하는 것도 가능
=> 밉맵 수준들이 모두 미리 압축되어서 파일에 저장되므로 실행 시점에서 따로 계산할 필요가 없다.
=> 텍스처를 압축해서 DDS 파일에 저장하면 파일들이 디스크 공간을 덜 차지한다는 장점도 생긴다.
틀린 부분이나 이상한 부분이 있으면 댓글로 편하게 지적해주세요.
감사합니다!
'DirectX11 > 정보정리' 카테고리의 다른 글
[DirectX11] 스텐실 적용 (0) | 2023.01.07 |
---|---|
[DirectX11] 혼합 (0) | 2023.01.05 |
[DirectX11] 조명 (0) | 2022.11.23 |
[DirectX11] 효과 프레임워크 (0) | 2022.11.08 |
[DirectX11] 정점 버퍼와 색인 버퍼 (0) | 2022.11.07 |
댓글