• 이번 챕터에서는 총 두가지 이론을 다룰 것이다.
    • 평평한 2차원 모니터 화면을 통해서 3차원 세상을 보고 있다는 환상의 주요 요소
    • 색상을 수학적으로, 그리고 Direct3D 코드 안에서 표현하고 다루는 방법

3차원의 환상

  • 3차원 세계의 깊이와 부피를 2차원 평면으로 나타내는 방법은 이미 충분히 연구되어 왔다.
    • 소실점(Vanishing Point)
      • 시각 평행선들이 수렴하는 점.
    • 물체 겹침(Object Overlay)
      • 불투명한 물체가 그 뒤에 있는 물체의 일부 또는 전체를 가리는 현상.
    • 조명, 셰이딩
      • 광원으로 인한 밝기 변화를 적용함으로써 부피를 표현
    • 그림자
      • 그림자는 장면에서 광원이 있는 위치를 말해준다.
      • 또한 물체의 위치를 대략적으로 제시하기도 한다.

모형의 표현

  • Direct3D Application에서는 일반적으로 Solid의 3차원 물체를 삼각형 Mesh로 Approximation한다.
  • 실제 세상의 그 어떤 3차원 물체라도 삼각형 mesh로 표현이 가능하다.
  • 일반적으로, 근사하는데 사용한 삼각형이 많을수록 요구되는 처리 능력이 높아진다.
    • 따라서 사용자의 Hardware 성능에 근거하여 적절한 균형점을 찾아야 한다.
  • 삼각형 외에 섬이나 점도 물체를 근사하는데 유용하다.
    • 예를 들어 곡선은 한 Pixel 굵기의 짧은 선분들로 근사가 가능하다.
  • 모든 3차원 물체를 삼각형 mesh로 표현이 가능하지만, 이를 일일이 나열하는 작업은 매우 성가시다.
    • 그래서 간단한 모형이 아닌 이상 모형을 생성, 조작할 때에는 3D Modeler를 사용한다.
    • 3D Studio Max, LightWave 3D, Maya, Softimage, Blender 등

색상 표현의 기초

  • 컴퓨터 모니터는 Pixel마다 Red, Green, Blue 색의 빛을 섞어서 방출한다.
  • 모니터가 방출하는 RGB의 세기에는 상한과 하한이 존재한다.
    • 보통 [0, 1]의 정규화된 값을 사용한다.
    • 0은 빛이 전혀 ㅇ벗는 것이고, 1은 세기가 최대인 것이다.
    • 예를 들어 (0.25, 0.67, 1.0)은 25%의 Red, 67%의 Green, 100%의 Blue가 혼합되었다는 의미이다.
  • 이는 하나의 색상을 하나의 3차원 색상 Vector (r, g, b)로 나타낼 수 있음을 의미한다.

색상 연산

  • Vector 연산 중 몇가지 연산은 색상 Vector에도 그대로 적용이 가능하다.
    • 덧셈, 뺄셈, 스칼라 곱 등은 그대로 적용이 된다.
  • 반면 Dot Product, Cross Product와 같은 연산은 의미를 퇴색한다.
  • 색상 Vector만의 연산도 존재한다.
    • 변조(Modulation) 혹은 성분별 곱셈(Componentwise multiplication)이라고도 한다.

Modulation

  • Modulation은 주로 조명 공식에 쓰인다.
  • 색상 연산은 성분이 [0, 1] 범위 바깥으로 나갈 수 있다.
    • 하지만 1.0이 최대 세기이므로 이보다 큰 성분은 1.0으로 clamping 해야 한다.
    • 마찬가지로 음의 세기도 0.0으로 clamping 해야 한다.

128비트 색상

  • 보통 RGB 외에 A(Alpha)라는 성분을 색상 Vector에 추가하는 경우가 많다.
  • Alpha는 색상의 불투명도를 나타내는데, 이는 색상 혼합에 유용하다.
  • Alpha를 색상 Vector에 추가함으로서 하나의 색상은 각 성분 별 32bit float형으로 총 128bit로 표현된다.
    • 수학적으로는 하나의 4차원 Vector이므로, 코드상에서도 그냥 XMVector를 이용한다.
    • 그러면 XNA Math 라이브러리의 Vector 함수들로 연산 할 때 SIMD의 이득을 취할 수 있다
  • 색상 Vector의 Modulate에 대해서는 XNA Math 라이브러리의 다음 함수를 사용한다.
XMVECTOR    XM_CALLCONV     XMColorModulate(FXMVECTOR C1, FXMVECTOR C2);

32비트 색상

  • 각 성분당 1Byte를 할당해서 32bit로 하나의 색상을 표현할 수도 있다.
    • 성분 당 0에서 255로 16,777,216가지의 색을 표현하는 것이 가능하다.
  • XNA Math 라이브러리는 이를 위해 다음 구조체를 제공한다.
struct XMCOLOR {
  union {
    struct {
      uint8_t b;
      uint8_t g;
      uint8_t r;
      uint8_t a;
    };
    uint32_t c;
  };
  void         XMCOLOR();
  void         XMCOLOR(
    const XMCOLOR & 
  );
  XMCOLOR &    operator=(
    const XMCOLOR & 
  );
  void         XMCOLOR(
    XMCOLOR && 
  );
  XMCOLOR &    operator=(
    XMCOLOR && 
  );
  XM_CONSTEXPR XMCOLOR(
    uint32_t Color
  );
  void         XMCOLOR(
    float _r,
    float _g,
    float _b,
    float _a
  );
  void         XMCOLOR(
    const float *pArray
  );
  void         operator uint32_t();
  XMCOLOR &    operator=(
    const uint32_t Color
  );
};

https://docs.microsoft.com/en-us/windows/win32/api/directxpackedvector/ns-directxpackedvector-xmcolor

 

XMCOLOR (directxpackedvector.h) - Win32 apps

A 32-bit Alpha Red Green Blue (ARGB) color vector, where each color channel is specified as an unsigned 8 bit integer.

docs.microsoft.com

  • 32bit 색상을 128bit 색상으로 바꿀 때는 각 성분을 255로 나누면 된다.
  • 반대로 128bit 색상을 32bit 색상으로 바꿀 때는 각 성분을 255를 곱하면 된다.
    • 단, 32bit 색상은 4개의 8bit 색상 성분을 하나의 32bit 정수형 자료형(ex. unsigned int)에 넣은 형태이다.
    • 때문에 추가적인 비트 연산이 필요하다. 이는 XMCOLOR도 해당된다.
  • 이에 대해서 XNA Math 라이브러리는 다음 함수를 제공한다.
XMVECTOR XM_CALLCONV XMLoadColor(
  const XMCOLOR *pSource
);
  • 반대로 XMVECTOR 색상을 XMCOLOR로 변환하는 함수도 제공한다.
void XM_CALLCONV XMStoreColor(
  XMCOLOR   *pDestination,
  FXMVECTOR V
);
  • 하지만 이 함수들과 XMColor는 DirectX11이나 DirectXPackedVector.h에 존재한다.
  • DirectX12 예시에서는 XNA Math가 아니라 DirectXMath.h를 사용하는데, 이 안에 흔적을 찾을 수 없었다.
    • 아무래도 DirectX12에 와서는 일반 XMUInt4를 사용하는 것 같다.
struct XMUINT4
{
    uint32_t x;
    uint32_t y;
    uint32_t z;
    uint32_t w;

    XMUINT4() = default;

    XMUINT4(const XMUINT4&) = default;
    XMUINT4& operator=(const XMUINT4&) = default;

    XMUINT4(XMUINT4&&) = default;
    XMUINT4& operator=(XMUINT4&&) = default;

    XM_CONSTEXPR XMUINT4(uint32_t _x, uint32_t _y, uint32_t _z, uint32_t _w) : x(_x), y(_y), z(_z), w(_w) {}
    explicit XMUINT4(_In_reads_(4) const uint32_t *pArray) : x(pArray[0]), y(pArray[1]), z(pArray[2]), w(pArray[3]) {}
};

XMVECTOR    XM_CALLCONV     XMLoadUInt4(_In_ const XMUINT4* pSource);
void        XM_CALLCONV     XMStoreUInt4(_Out_ XMUINT4* pDestination, _In_ FXMVECTOR V);
  • 다시 돌아와, 128bit 색상은 Pixel Shader와 같이 다수의 색상 연산이 진행되는 곳에 쓰인다.
    • 정밀도를 위한 비트가 많으므로 산술 오차가 과도하게 누적되는 일이 없기 때문이다.
  • 하지만 최종적인 Pixel 색상은 일반적으로 Back Buffer에 32bit로 저장된다.
  • 현재의 물리적 디스플레이 장치들은 고해상도 색상의 장점을 취하지 못한다.

+ Recent posts