Texture sampling 과 관련해서 주의해야할 사항을 한번 적어보려고 합니다.
Pixel shader 프로그래밍을 하다보면 너무나 자연스럽게 texture sampler 를 사용하게 됩니다. 간단한 예를 보면 다음과 같습니다.
sampler color_map;
float4 ps_main(
float4 inDiff: COLOR,
float4 inTex: TEXCOORD ) : COLOR
{
// Return the hemisphere color modulated
// with the color of the base texture
return inDiff * tex2D(color_map, inTex);
}
여기에서 tex2D 라는 것이 텍스쳐 color_map 이라는 것에 접근해서 값을 꺼내주는 함수입니다.
우선 기억을 되살려야 할것은, 우리가 텍스쳐 그림 파일을 저장하는 방법입니다. 예를 들어, 텍스쳐를 A8R8G8B8 의 32bit 형태로 저장한 그림 파일을 사용한다고 했을때, red 가 8bit 를 사용하고, green 과 blue 도 8bit 를 사용해서 각각 256가지 색깔을 표현할수 있습니다. 구체적으로 이 값들은 8bit integer 형으로 저장되는데 signed 가 아니라 unsigned 형태라는 점도 기억해두어야 합니다.
그런데 우리가 텍스쳐 샘플링을 할때, 다시 말해서 pixel shader 에서 tex2D 라는 함수를 사용해서 텍스쳐로부터 색을 얻어오면, 값의 범위는 0 부터 1 사이입니다. 그리고 이 값은 signed 값입니다. 그리고 float 형태로 값을 넘겨주기 때문에 32bit 형태입니다.
정리하면 이렇게 됩니다.
unsigned 8 bit int 가 signed 32bit float 형태로 샘플링 된다
는 것입니다.
이렇게만 되면 사실 문제는 없는데, 이 과정이 반대로 되면 문제가 발생합니다.
우리가 render target 을 지정해서 이미지를 텍스쳐에 임시로 그려 넣는다고 했을때, 생상 정보는 각 채널당 8bit 이기 때문에 무심결레 float 값을 한 색상 채널에 저장해서 그려두면 32bit 값이 8bit로 쪼그라 들어버립니다. 그런데 나중에 샘플링 해서 사용할때는 tex2D 가 다시 32bit float 을 넘겨주기 때문에, 마치 계속 32bit 값이 유지되고 있는것 같은 착각을 일으킵니다.
이런 이유로 floating-point texture 혹은 fat pixel 이라는 개념이 등장하는 것입니다. fat pixel 은 한 픽셀안에 색상 채널당 32bit 로 구성되어있기 때문에 A32R32G32B32 가 되어서 총 128bit 로 구성됩니다. 일반 색상의 4배가 되는것이죠.
가볍게 생각해버리면, 색상 정보는 24bit 만 있으면 되는데 왜 fat pixel 같은 128bit 픽셀이 필요하지?? 하고 생각할수 있습니다.
하지만, 실제 pixel shader 프로그래밍을 하면 텍스터에다가 색상만 담는게 아니라, 색상 이외의 다른 정보들을 (일종의 꽁수형태로) 저장하는게 일반화 되어있기 때문에 fat pixel 이 필요하게 되는 것입니다.
하지만 fat pixel 은 pixel shader 2.0 표준에서 표함되어있는것이 아니기 때문에 지원되는 하드웨어가 있고 안되는 하드웨어가 있습니다. 이렇게 지원이 안되는 하드웨어에서 32bit 값을 텍스쳐에 저장하는 꽁수로는 32bit float 값을 integer 형태로 인코딩해서 저장하는 방법입니다. 구체적으로는 이런식이 되겠습니다.
float4 ps_main( float4 inDepth: TEXCOORD0 ) : COLOR0
{
// Output the depth as computed by
// the vertex shader
float4 Depth;
Depth.w = 1.0;
Depth.x = floor(inDepth.x*127)/127;
Depth.y = floor((inDepth.x-Depth.x)*127*127)/127;
Depth.z = 0;
return Depth;
}
그러면 나중에 이 택스쳐로 부터 값을 꺼내서 사용할때는 다시 디코딩을 해야하는데 다음과 같이 하면 되겠습니다.
float4 DepthValue = tex2D(Texture2,texCoord);
float Depth = DepthValue.x + DepthValue.y/127 + DepthValue.z/(127*127);
여기에 더해서 texture sampler 가 하는 또하나의 기능은 anti-aliasing filter 를 적용해주는 일입니다. 사실 저도 구체적으로 어떻게 aliasing filter 를 정용하는지 잘 모르기 때문에 이부분은 다음 기회로 미루겠습니다.