ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [50] - Texture - 2
    Graphics 2021. 8. 26. 23:17

     Texture에 대한 약간의 공부를 진행했습니다. Texture, texel, pixel 등 이들이 어떻게 관리되고 어떤 식으로 Mapping이 되는지 개략적인 이해는 했습니다. D3D에서는 이 Texture을 어떤 식으로 관리할 수 있을지 배워봅니다.

    Pixel은 모호하게 표현하면 하나의 이미지와 같습니다. 따라서 우리는 가장 먼저 이미지를 우리의 Engine에 불러올 수 있도록 할 라이브러리가 필요합니다. 여기에는 많은 Tool이 존재합니다. DirectX Toolkit에도 이미지를 불러올 수 있는 기능이 존재하지만 이것을 사용하게 되면 Texture에 대한 많은 부분이 Black Box인 상태로 남기 때문에 공부를 하는 목적에 부합하지 않습니다. 따라서 이는 협상의 여지가 없이 GDI Plus라는 것을 통해 수동으로 불러오도록 합니다.

    ((1) C++ 3D DirectX Tutorial [Texture Mapping] - YouTube)

    Texture, Sampler : Bindable

    이 둘은 Bindable입니다. 어떤 Mesh를 생성할 때 옵션으로 사용할 수 있다는 것입니다. 반면에 이들을 덮어 씌울 Sheet는 Drawable에 속하게 될 것입니다.

    figure 1a
    figfure 1b

    Texture class를 분석해보도록 합니다. Texture class라는 말이 거창할 뿐이지 결국엔 Bindable의 속성을 이어받을 수밖에 없습니다.

    figure 2a

    member variable인 ID3D11ShaderResourceView가 COM object로 Wrapping 되어 있는 것을 확인할 수 있습니다. 이는 Rendering 기간 동안에 Shader가 접근할 수 있는 Subresource를 명시하는 일종의 Interface입니다. 즉, Texture를 위해서 구성한 Description을 받아 D3D에 정보를 넘겨주는 매개 역할을 다한다고 볼 수 있습니다.

    figure 2b

    이렇게 Graphics에 Bind하기 위해서 parameter를 받고 Texture를 바를 어떤 표면을 요구하게 됩니다. 해당 역할은 Surface에 대한 Reference를 받는 Parameter가 수행합니다.

    figure 2c

    How to Create a Texture - Win32 apps | Microsoft Docs Texture를 만들기 위한 Description을 명시해줍니다. Description은 다른 Description과 대체로 비슷한 정보를 갖습니다. Texture에서 확실하게 명시해야 할 것은 Subresource data입니다. pSysMem은 Initialisation data의 포인터를 넘겨주라고 되어 있습니다. 여기에는 Surface의 버퍼의 포인터 정보를 넘겨줍니다. 더 중요한 것은 SysMemPitch인데 다음은 MSDN 공식 문서의 일부입니다.

    figure 2d
    figure 2e

    Figure 2c와 Figure 2e는 동일하게 Subresources을 구성하고 있으며 initiailisation data를 명시하지만  pSysMemPitch는 오직 Texture 만이 명시합니다. 그 이유는 Pitch가 쉽게 말해서 첫 Pixel과 다음 pixel (일반화를 하여서 n번째 pixel과 인접한 n+1번째 pixel간의 간격도 됩니다. )간의 간격을 명시하는 정보이기 때문입니다. 이 코드에선 Surface가 Padding과 같은 정보를 포함하지 않기 때문에 폭의 값과 색을 곱해주는 것으로 매듭 지을 수 있습니다.

    figure 2f

    Figure 2c까지가 Texture의 생성이었습니다. 그렇기 때문에 이 코드만 가지고는 실질적으로 Texture을 입힐 수 없습니다.

    figure 3a

    그렇게 때문에 위처럼 View에 대한 정보도 함께 파이프 라인에 넘겨주어야 합니다. 저번에 Mipmap에 대한 공부를 했습니다. 당장은 Mipmap의 요소를 요구하지 않기 때문에 MostDetailedMip을 0으로 설정하도록 합니다. 

    figure 3b

    남은 것은 Bind하는 것인데 어렵지 않습니다. 단순히 PixelShader에 셋을 해주면 끝입니다. Texture을 렌더링 하기 위해선 여기서 한 발 더 나아가서 Sampler라는 것이 필요합니다. 이것은 파이프 라인에게 어떤 식으로 Texture을 분석할 것인지 가이드 라인을 제공한다고 보면 됩니다. 

    figure 4a

    보면 Texture와 관련이 있음에도 Texture에 대한 Parameter는 볼 수 없습니다. 직접 파이프 라인에 묶습니다.

    Sampler

    figure 4b

    Sample 또는 샘플, 샘플러 상태는 texture를 공부하며 함께 약간 다뤘습니다. D3D11_SAMPLER_DESC은 Sampling을 어떻게 할 것인지 결정하는 파트와 관련이 깊다고 보면 됩니다. 당장 Filter를 보아도 Texture sampling을 수행할 때 옵션을 걸어주는 파트라는 것을 알 수 있습니다. 특히 AddressU, V, M은 자세히 들여다 보아야 할 필요가 있기 때문에 따로 공부하기로 합니다. 그러나 이전 Texture에서 공부한 내용이긴 합니다. Texture 보다 큰 Pixel에 어떤 식으로 바를 것인지 결정하는 내용이기 때문입니다. 

    이렇게 구성한 Texture와 Sampler는 결국 Bind를 호출하여 파이프 라인에 정보를 넘겨주도록 합니다. 그런데 아래의 두 Bind 함수를 보면 첫 번째 Argument가 0으로 일치한다는 것을 알 수 있습니다. 이 Start Slot은 Shader나 레지스터 측에서 직접적으로 접근하는 번호와 같기 때문에 둘은 같아야만 합니다. 

    figure 4c
    figure 4d

     다음은 Texture를 위한 Shader의 전문입니다. 

    figure 5a

    기존의 Vertex Shader와 문법적으로나 구조적으로나 크게 다른 점은 눈에 띄지 않습니다. Texture Coordinates를 Input으로 받으며 이 좌표를 직접 Output으로 삼습니다. 이 Output은 그대로 Texture의 Pixel Shader로 넘어가고 다음과 같은 구조를 갖습니다.

    figure 5b

    Texture의 Pixel Shader는 input으로 Texture Vertex Shader의 Output을 받습니다. 이 값을 통해서 Texture의 좌표를 반환하는 것입니다. 추가적으로 가장 위의 Textrue2D tex;은 기본 상태로 Slot 0u번을 가리키고 있는데 수동으로 값을 부여할 수도 있습니다.

    figure 5c

    그리고 SamplerState 역시 기본으로 Slot 0u을 가리키고 있습니다. 역시 수동으로 부여할 수 있지만 여기서는 그러지 않도록 합니다. 이제 적당한 Drawable만 있으면 Texture를 올릴 수 있을 것입니다. 이차원 텍스쳐이기 때문에 평면에 그린다면 아주 적합할 것입니다. 그래서 준비된 다음의 Sheep.cpp을 분석해보도록 합니다. 기본적으 이 Mesh는 Plane Mesh을 이용하는 편이 좋습니다.

    figure 6a
    figure 6b

    가장 먼저 온갖 랜덤 요소들을 초기화 시켜줍니다. 핵심은 이 다음입니다. Object space 상의 평면의 좌표를 결정해 주도록 합니다. 

    figure 6c

    외부에서 이미지를 불러오고 이를 Texture로 만들어서 Bind합니다. 그리고 Vertex를 넘겨주고 이 텍스쳐를 사용하는 모든 Mesh들은 같은 Sampler를 쓰도록 하니까 같이 묶어줍니다.

    figure 6d

    이후로는 그저 다른 Drawable과 다른 것이 크게 없습니다. 단지 Texture를 위한 Description이라든지 Shader의 구성에 주의만 해주면 됩니다. 

    figure 6e

    이제 실제로 이것들을 화면에 출력하게 해야 합니다. 전에 Factory 함수에서 랜덤으로 Mesh들을 출력하도록 세팅을 했기 때문에 거기에 약간 손만 보면 바로 직접 불러온 Texture를 입은 Mesh을 볼 수 있을 것입니다.

    figure 6f
    figure 7a

    잘 안 보일 수도 있는데 시뻘건 글씨로 'Hello Wordl'라고 쓰인 Hell.png 파일이 잘 입혀서 나온 것을 확인할 수  있습니다. 실제로 지옥과 같은 그림입니다. 이번에는 Sampling에 대한 실험을 좀 진행해보고 싶습니다. 코드를 적당히 고쳐서 단 하나의 Texture만 출력하도록 합니다. 그러면 쇼펜하우어의 얼굴이 다음과 같이 나오게 됩니다.

    figure 8a

    아까 보았듯 현재 Sampling의 옵션은 다음과 같았습니다.

    figure 8b

    사실 이것 말고도 많은 옵션이 존재합니다.

    figure 8c

    보이는 것만으로도 숨이 막힙니다. 이 중 몇 가지만 실험해 보도록 합니다. Sheet에 약간 하얀 부분이 있는 것은 그림판으로 편집할 때 실수한 부분입니다. 일단 텍스쳐의 좌표를 1보다 큰 값을 줘보겠습니다.

    figure 8d-1
    figure 8d-2

    기존엔 plane 즉 Mesh의 좌표와 Texture가 정확히 일치했습니다. 하지만 2.0f을 값으로 주면서 Pixel이 Texel보다 더 많아졌고 이를 처리하기 위해 Wrapping 옵션에 따라 처리를 한 것입니다.

    figure 8d-3

    그래서 이번엔 Warpping이 아닌 Clampping을 하도록 해보겠습니다. W는 이게 삼차원 텍스쳐가 아니기 때문에 안 바꿔도 영향을 주지 않습니다.

    figure 9a-1
    figure 9a-2

    보기에도 처리하는 방식이 다르다는 것을 알 수 있습니다. 이번에는 Boarder를 옵션으로 주겠습니다.

    figure 10a-1
    figure 10a-2

    figure 9a-2의 결과와 다른 것이 없는 것 같으나 잘 보면 Texture의 이미지가 반복된 것이 아니라 아예 새까맣게 되어 있다는 것을 발견할 수 있습니다.

     

    'Graphics' 카테고리의 다른 글

    [52] - Lighting(Illumination)  (0) 2021.09.13
    [51] - imgui  (0) 2021.08.28
    [49] - Texture - 1  (0) 2021.08.17
    [48] - Rasterization  (0) 2021.08.13
    [47] - Bindable/Drawable System - 3  (0) 2021.08.12
Designed by Tistory.