ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [49] - Texture - 1
    Graphics 2021. 8. 17. 17:47

     육면체는 총 8개의 Vertices가 있고 Vertex Shader - Tessellation - Geometry Shader 등을 거쳐서 Fragment/Pixel Shader에 이르면 최종적인 외형을 결정하게 됩니다. 최종적 외형[最終的外形]이라는 것은 Colour, Illumination, Texture 등등을 이릅니다. 오늘은 Image Texturing에 대한 공부를 할 것입니다. 

    Rasterization에서 Fragment를 생성했으니 이들은 다음 Shader로 넘어갑니다. 그 전에 Fragment Shader와 Pixel Shader의 차이점이 있는지 확인해 봅니다. 크게 다른 점은 없고 OpenGL과 D3D의 단어 선택적 차이와 Graphics Pipepline을 구성하는 약간의 구조적인 차이만 존재하는 것 같습니다. 엄밀하게 말하면 Rasterization을 거친 Fragment들은 아직 Depth, Alpha, Stencil 등의 Process를 거치지 않았기 때문에 Pixel(Picture Element)이라고 말할 수 있는 단계는 아니므로 Fragment라고 부르는 것이 더 맞다는 설명도 있었습니다.

    여하튼, 이 Fragment/Pixel Shader에서는 Rasterization Stage에서 건너온 fragment에 'Colour'값(혹은 특성[attributes])을 줍니다. 그리고 색을 부여하는 대표적인 예시로 Texture와 lighting이 있는데 오늘은 Texture에 대해서 공부하도록 합니다. Texture는 2차원 배열의 색의 값[Colour value]입니다. 그리고 각 배열에는 Texel이라는 이름이 붙습니다. 그리고 이 texel은 texture의 주소가 존재합니다. 좀더 직관적으로 설명된 글을 보면 Texel이란 Texture내에 존재하는 pixel과 같다고 합니다. 즉, pixel이 image의 가장 작은 단위인 것처럼 texel은 texture의 가장 작은 단위라는 것입니다.

    Texture Coordinates

    예를 들어서 다음과 같은 그림이 있다고 가정하겠습니다.

    Image Texturing은 Rasterization에 의해 생성된 Fragment의 정보가 필요합니다. 좌측 예시의 경우 각 Vertex에 둘러싸인 Fragment는 총 6개로 해당 Fragment의 texture coordinates(이하 TC)라는 것을 사용해야 합니다.

    Texture coordinates 상에선 (1, 6) = (0, 1) / (1, 2) = (0, 0) / (5, 2) = (1, 0)이 됩니다. 이때 가장 좌측 하단의 fragment의 TC 상의 좌표는 (0.125, 0.125)입니다. 어느 한 점을 (0, 0)으로 잡고 상대적인 좌표를 만드는 것입니다.

    그러면 4x4크기의 실제 texture가 있다고 했을 때, ( 0.125 * 4, 0.125 * 4 )에 해당하는 Texture element(혹은 texel)를 갖다 붙입니다.

     당연한 말이긴 한데 texture space는 texture coordinates 상에 존재하며 (0, 0)을 기준으로 크기가 양의 방향으로 1만큼인 공간에 대해 상대적인 위치에 존재하게 됩니다. 이런 공간을 도입한 이유는 texel이 texuter의 정보를 object space에 mapping할 때 일관성을 유지하기 위함입니다. 즉, 공통된 주소 체계가 있어야 texuter의 크기와 상관 없이 texuter를 mesh에 바를 수 있다는 뜻입니다. 참고로 Cartesian Coordinates가 XY-Coordinates를 사용하는 것처럼 D3D는 0.0부터 1.0까지 표현되는 UV-Coordinates를 사용합니다.

     texture가 삼차원 공간 상의 Primitive에 발리게 되면 해당 Texel의 주소는 Object Space의 좌표에 할당이 되어야 합니다. 그리고 나서 Screen space든 어디든 Translate되어야 합니다. 바로 위의 예제의 texture는 4 by 4였으나 6 by 6도 존재할 수 있습니다. (https://docs.microsoft.com/en-us/windows/win32/direct3d9/texture-coordinates) 그러나 MSDN의 문서를 읽어보면 D3D는 효율성을 위해서 texture coordinates상의 texel의 좌표를 직접 Screen space 상의 좌표에 붙인다고 되어 있습니다. 이를 inverse mapping이라고 합니다.

     texture coordinates 덕분에 서로 다른 두 개의 Texture가 존재한다고 해도 같은 Mesh에 다른 Texture를 붙일 수 있습니다. 하지만 이런 경우에는 예상된 Mesh의 형태와 지나치게 다를 경우, Texture가 찌그러지거나 늘어지는 부작용을 경험할 수 있습니다. 추가적으로 Texture coordinates의 Range가 반드시 [0,1]일 필요는 없는데 대신에 GPU에서 0과 1을 넘어서는 값에 대해서 설정을 해주어야 합니다.

    Suface Parameterization

    어떤 Mesh에 texture coordinates를 잘 설정해야 원하는 형태로 어떤 사물이나 효과를 만족스럽게 얻을 수 있습니다. 예를 들어서 어떤 원통형 Mesh 표면에 texture를 바른다고 가정해봅시다. 이때, 원통의 Mesh를 평면에 활짝 펴는 행위 자체를 Parameterization이라고 합니다. 극단적으로 복잡한 사람의 얼굴이나 여타 Mesh도 예외는 없습니다. Texture를 바르기 위해 Mesh의 전개도를 얻어야 하며 이 과정을 Parameterization이라고 합니다. (https://www.researchgate.net/figure/Mapping-functions-of-surface-parameterization_fig2_257336512)

    그런데 이런 복잡한 Mesh를 한 번에 전개하기 힘들 수 있습니다. 따라서 Mesh를 부분 분해할 수 있습니다. 가령, 사람의 경우엔 얼굴, 머리, 몸통, 사지 등등으로 세심하게 나눌 수 있습니다. 이렇게 부분으로 나눈 조각들에는 Patch라는 특수한 이름이 있습니다. Patch위에 아트 담당자가 그림을 입히면 이 Patch는 Chart라는 이름이 붙으며 이렇게 하나의 mesh를 만들기 위한 Chart들을 모아놓은 타일이 존재하는데 여기엔 Atlas라는 이름이 있습니다.

    Texture Filtering

    Mesh가 80x60짜리 장방형이고 (30, 40.5)에 texture를 입힌다고 상상해봅시다. 이 Texel을 참조하여 Mesh에 입힐 texture로 가서 (30.0 * u, 40.5 * v )를 하여 입힐 texture를 찾으면 30.0은 상관이 없는데 0.5가 존재하는 40.5에서 문제가 발생합니다. 여기엔 정확히 가리키는 texture가 없기 때문입니다. 따라서 이 경우에는 주변 texture의 정보를 참조하는데 이 참조하는 과정을 가리켜 Texture Filtering이라고 합니다. 이 기법이 필요한 상황이 크게 두 가지가 있습니다. 하나는 Magnification이고 다른 하나는 Minification입니다.

     Magnification은 채워야 할 pixel이 texture보다 클 경우를 이르는 말입니다. 가령, 40,000개의 픽셀을 2,500개의 texel로 구성된 texture를 사용하여 채우는 경우를 상정해 봅니다. 반대로 Minification은 pixel보다 texel이 훨씬 많을 경우를 가리킵니다. 각각을 해결하는 다양한 기법이 존재하는데 Magnification부터 살표봅니다.

    1. Nearest Point Sampling : Magnification

    가장 가까운 texel의 정보를 참조합니다. 예를 들어서 4x4, 총 16개의 pixel을 채우도록 명령이 떨어졌는데 mapping해준 texture에 오직 2x2개의 texel만 존재한다고 해봅시다.

    figure 1a

    채워야 하는 pixel은 작은 동그라미로 나타냈습니다. texture는 장방형 네 개로 나타냈습니다. 즉, 작은 장방형 하나가 texel을 뜻하는 것입니다. 이제 좌측 픽셀은 오른쪽 texture로 맵핑이 된 정보를 가져올 것입니다. 그런데 Texel 하나가 pixel 네 개를 덮고 있는 것을 볼 수 있습니다. 즉, pixel과 texel이 매칭이 되지 않습니다. 가령, texture 쪽에 빨갛게 표시한 pixel의 경우, 가장 가까운 texel이 자신이 속한 바로 그 texel입니다. 따라서, 해당 pixel을 비롯한 주변 pixel들이 모두 같은 texel로 표현이 되는 것입니다. 이것이 바로 Nearest Point Sampling입니다. 이런 식으로 sampling을 해버리면 우리가 흔히 보는 도트 이미지처럼 보이는 효과를 얻을 수 있습니다.

    2. *Bilinear Interpolation* : Magnification

    Graphics Hardware에서 채택하는 보편적 해결 방법이며 상당히 최적화 된 방법입니다. Nearest Point Sampling에서 한 발 더 나아간 형태로 주변 Texel들을 모두 참조하여 Pixel을 만듭니다. Block처럼 보이는 현상을 완화하지만 완전히 해결할 수는 없습니다. 구글링을 해보면 이 외에도 다양한 해결책이 존재합니다. 그 중 인상 깊었던 것은 Bicubic interpolation인데 이 녀석은 너무 과해서 종종 의미가 알 수 없는 그림을 결과 값으로 내주기도 한다는 점이 재밌습니다.

    여기까지는 pixel이 texel보다 많아서 생기는 문제들과 해결책들이었습니다. 이번에는 반대로 texel이 pixel보다 많아서 생기는 문제를 살펴볼 것입니다. 직관적으로 어떤 문제가 생길 것인지 이미 감이 옵니다.

    figure 1b

    위의 그림처럼 pixel에 비해서 texel이 너무 많으면 어떤 texel을 고르냐에 따라서 완전히 모습이 바뀌게 됩니다. 우리는 명백히 원하는 mesh의 외형이 존재합니다. 불확실성을 줄이기 위해서 고안된 다양한 대책이 존재합니다.

    1. Mipmap : Minification

     Texel이 Pixel보다 클 가능성이 언제든 있기 때문에 애초에 Texel을 줄여 놓으면 된다는 발상에서 시작합니다. 원본을 level 0으로 두고 반 자른 것을 level 1 그것을 자른 것을 level 2... ... level k까지 마치 피라미드의 형태로 데이터를 만들어 둡니다. 여기서 '자른다'라는 표현은 texture를 물리적으로 자르는 것이 아니라 적당히 interpolation한다는 뜻입니다. 만약에 어떤 texture가 2^k, 2^k의 크기를 갖고 있다면 계속 반 씩 자르기 때문에 총 k+1 층의 피라미드를 만들고 이 피라미드를 Mipmap이라고 합니다. 이때 mipmap의 level은 level of detail으로 표현하고 λ[lambda]로 표현합니다. 이러면 pixel의 크기에 따라 level을 골라서 mapping하면 됩니다. pixel의 크기를 2의 승수로 표현하고 밑이 2인 로그를 취하면 mipmap의 레벨이 나오기 때문에 어렵지 않습니다. 이렇게 pixel의 크기와 texture가 2로 정확하게 나누어 떨어지면 각 pixel과 texel이 1:1 대응이 되어 이상적인 결과를 얻을 수 있습니다.

     

    물론, 2의 승수로 모두 표현할 수 있지는 않습니다. 8x8의 texture가 존재하고 3x3 pixel들에 맵핑을 하려면 2x2보다는 크고 4x4보다는 작은 애매한 수가 나옵니다. 정확히는 1.58...  의 수가 나옵니다. 여기엔 레벨이 없습니다. 따라서 크게 두 가지 방법 중 하나를 채택해서 Mapping을 진행해야 합니다.

    먼저 대충 버림이나 올림을 해서 texture level을 결정하고 pixel에 대응하는 texel을 갖고 오거나 해야 합니다. 당연히 이 방법은 다시 도트 이미지처럼 만들 가능성이 존재합니다. 다른 방법은 linear interpolation이라는 방법인데 양쪽 level의 texture를 모두 참조하여 interpolate하는 방법입니다.

     

     

    'Graphics' 카테고리의 다른 글

    [51] - imgui  (0) 2021.08.28
    [50] - Texture - 2  (0) 2021.08.26
    [48] - Rasterization  (0) 2021.08.13
    [47] - Bindable/Drawable System - 3  (0) 2021.08.12
    [46] - std::optional  (0) 2021.08.12
Designed by Tistory.