텍셀을 픽셀에 직접 매핑(Direct3D 9)

미리 변환된 꼭짓점을 사용하여 2D 출력을 렌더링하는 경우 각 텍셀 영역이 단일 픽셀 영역에 올바르게 해당하도록 주의해야 합니다. 그렇지 않으면 텍스처 왜곡이 발생할 수 있습니다. Direct3D가 삼각형을 래스터화하고 텍스처링할 때 따르는 프로세스의 기본 사항을 이해하면 Direct3D 애플리케이션이 2D 출력을 올바르게 렌더링하도록 할 수 있습니다.

6x6 해상도 디스플레이 그림

앞의 다이어그램은 제곱으로 모델링된 픽셀을 보여 줍니다. 그러나 실제로 픽셀은 제곱이 아닌 점입니다. 이전 다이어그램의 각 사각형은 픽셀에 의해 점이 켜진 영역을 나타내지만 픽셀은 항상 정사각형 가운데에 있는 점일 뿐입니다. 이 구별은 겉보기에는 작지만 중요합니다. 동일한 디스플레이에 대한 더 나은 그림이 다음 다이어그램에 표시됩니다.

픽셀로 구성된 디스플레이 그림

위의 다이어그램은 각 실제 픽셀을 각 셀의 가운데에 있는 지점으로 올바르게 표시합니다. 화면 공간 좌표(0, 0)는 왼쪽 위 픽셀에 직접 위치하므로 왼쪽 위 셀의 중앙에 있습니다. 따라서 디스플레이의 왼쪽 위 모서리는 왼쪽에 0.5개 셀, 왼쪽 위 픽셀에서 0.5개 셀이므로 (-0.5, -0.5)입니다. Direct3D는 다음 그림과 같이 모서리가 (0, 0) 및 (4, 4)인 쿼드를 렌더링합니다.

(0, 0)과 (4, 4) 사이의 래스터화되지 않은 쿼드의 윤곽선 그림

앞의 그림에서는 수학 쿼드가 디스플레이와 관련된 위치를 보여 주지만 Direct3D가 쿼드를 래스터화하고 디스플레이에 보내면 쿼드의 모양은 표시되지 않습니다. 실제로 쿼드의 가장자리가 픽셀 셀 사이의 경계와 일치하지 않으므로 래스터 디스플레이가 표시된 대로 쿼드를 정확하게 채우는 것은 불가능합니다. 즉, 각 픽셀은 단일 색만 표시할 수 있으므로 각 픽셀 셀은 단일 색으로 채워집니다. 디스플레이가 표시된 대로 쿼드를 정확하게 렌더링하는 경우 쿼드 가장자리를 따라 픽셀 셀에는 배경만 표시되는 쿼드로 덮인 파란색과 흰색이라는 두 가지 고유한 색이 표시되어야 합니다.

대신 그래픽 하드웨어는 쿼드를 근사치로 채워야 하는 픽셀을 결정하는 작업을 수행합니다. 이 프로세스를 래스터화라고 하며 래스터화 규칙(Direct3D 9)에 자세히 설명되어 있습니다. 이 특정 사례의 경우 래스터화된 쿼드는 다음 그림에 나와 있습니다.

(0,0)에서 (4,4)로 그린 텍스트가 없는 쿼드 그림

Direct3D에 전달된 쿼드의 모서리는 (0, 0) 및 (4, 4)이지만 래스터화된 출력(이전 그림)의 모서리는 (-0.5,-0.5) 및 (3.5,3.5)입니다. 렌더링 차이점에 대한 앞의 두 일러스트레이션을 비교합니다. 디스플레이가 실제로 렌더링하는 것은 올바른 크기이지만 x 및 y 방향에서 -0.5 셀로 이동되었음을 알 수 있습니다. 그러나 다중 샘플링 기술을 제외하고 쿼드에 가장 적합한 근사치입니다. 다중 샘플링에 대한 철저한 검사는 Antialias 샘플을 참조하세요. 래스터라이저가 쿼드가 교차하는 모든 셀을 채운 경우 결과 영역은 원하는 4 x 4 대신 차원 5 x 5가 됩니다.

화면 좌표가 왼쪽 위 픽셀 대신 디스플레이 그리드의 왼쪽 위 모서리에서 시작된다고 가정하면 쿼드가 예상대로 표시됩니다. 그러나 쿼드에 텍스처가 제공되면 차이가 분명해집니다. 다음 그림에서는 쿼드에 직접 매핑할 4 x 4 텍스처를 보여 줍니다.

4x4 텍스처 그림

텍스처는 4 x 4 텍셀이고 쿼드는 4 x 4 픽셀이므로 쿼드가 그려지는 화면의 위치에 관계없이 질감 쿼드가 질감과 똑같이 나타날 것으로 예상할 수 있습니다. 그러나 이 경우는 그렇지 않습니다. 위치가 약간만 변경되더라도 텍스처가 표시되는 방식에 영향을 미칩니다. 다음 그림에서는 래스터화 및 텍스처화 후 (0, 0) 및 (4, 4) 사이의 쿼드가 표시되는 방법을 보여 줍니다.

(0, 0) 및 (4, 4)에서 그린 텍스처 쿼드 그림

앞의 그림에서 그린 쿼드는 중첩된 래스터화된 윤곽선이 있는 텍스처 출력(선형 필터링 모드 및 클램프 주소 지정 모드 포함)을 보여 줍니다. 이 문서의 나머지 부분에는 출력이 텍스처처럼 보이는 대신 출력이 어떻게 보이는지 정확히 설명하지만 솔루션을 원하는 사용자에게는 입력 쿼드의 가장자리가 픽셀 셀 사이의 경계선에 놓여야 합니다. x 및 y 쿼드 좌표를 -0.5 단위로 이동하면 텍셀 셀이 픽셀 셀을 완벽하게 커버하고 쿼드를 화면에서 완벽하게 다시 만들 수 있습니다. (이 항목의 마지막 그림에서는 수정된 좌표의 쿼드를 보여 줍니다.)

래스터화된 출력이 입력 텍스처와 약간 유사한 이유의 세부 정보는 Direct3D가 텍스처를 주소 지정하고 텍스처를 샘플링하는 방식과 직접 관련이 있습니다. 다음은 텍스처 좌표 공간쌍선형 텍스처 필터링을 잘 이해하고 있다고 가정합니다.

이상한 픽셀 출력에 대한 조사로 돌아가서 출력 색을 픽셀 셰이더로 다시 추적하는 것이 좋습니다. 픽셀 셰이더는 래스터화된 셰이더의 일부로 선택된 각 픽셀에 대해 호출됩니다. 이전 그림에 표시된 단색 파란색 쿼드에는 특히 간단한 셰이더가 있을 수 있습니다.

float4 SolidBluePS() : COLOR
{ 
    return float4( 0, 0, 1, 1 );
} 

텍스처 쿼드의 경우 픽셀 셰이더를 약간 변경해야 합니다.

texture MyTexture;

sampler MySampler = 
sampler_state 
{ 
    Texture = <MyTexture>;
    MinFilter = Linear;
    MagFilter = Linear;
    AddressU = Clamp;
    AddressV = Clamp;
};

float4 TextureLookupPS( float2 vTexCoord : TEXCOORD0 ) : COLOR
{
    return tex2D( MySampler, vTexCoord );
} 

이 코드는 4 x 4 텍스처가 MyTexture에 저장되어 있다고 가정합니다. 표시된 것처럼 MySampler 텍스처 샘플러는 MyTexture에서 쌍선형 필터링을 수행하도록 설정됩니다. 픽셀 셰이더는 래스터화된 각 픽셀에 대해 한 번 호출되며, 반환된 색이 vTexCoord에서 샘플링된 텍스처 색이 될 때마다 호출됩니다. 픽셀 셰이더를 호출할 때마다 vTexCoord 인수는 해당 픽셀의 텍스처 좌표로 설정됩니다. 즉, 셰이더는 다음 그림에 설명된 대로 픽셀의 정확한 위치에서 필터링된 텍스처 색을 텍스처 샘플러에 요청합니다.

텍스처 좌표에 대한 샘플링 위치 그림

텍스처(겹쳐서 표시됨)는 픽셀 위치에서 직접 샘플링됩니다(검은색 점으로 표시됨). 텍스처 좌표는 래스터화의 영향을 받지 않습니다(원래 쿼드의 프로젝션된 화면 공간에 남아 있음). 검은색 점은 래스터화 픽셀이 있는 위치를 표시합니다. 각 픽셀의 텍스처 좌표는 각 꼭짓점에 저장된 좌표를 보간하여 쉽게 결정됩니다. (0,0)의 픽셀은 (0, 0)의 꼭짓점과 일치합니다. 따라서 해당 픽셀의 텍스처 좌표는 해당 꼭짓점 UV(0.0, 0.0)에 저장된 텍스처 좌표일 뿐입니다. (3, 1)의 픽셀에 대해 보간된 좌표는 UV(0.75, 0.25)입니다. 그 픽셀은 텍스처 너비의 3/4와 높이의 1/4에 위치하기 때문입니다. 이러한 보간된 좌표는 픽셀 셰이더에 전달됩니다.

텍셀은 이 예제의 픽셀과 일치하지 않습니다. 각 픽셀(따라서 각 샘플링 지점)은 4개의 텍셀 모서리에 배치됩니다. 필터링 모드가 선형으로 설정되므로 샘플러가 해당 모서리를 공유하는 4개의 텍셀의 색을 평균화합니다. 이것은 빨간색으로 예상되는 픽셀이 실제로 3/4 회색과 1/4 빨간색이고, 녹색으로 예상되는 픽셀이 반 회색과 1/4 빨간색, 1/4 녹색 등인 이유를 설명합니다.

이 문제를 해결하려면 쿼드를 래스터화할 픽셀에 올바르게 매핑하여 텍셀을 픽셀에 올바르게 매핑하기만 하면 됩니다. 다음 그림에서는 처음부터 의도한 쿼드인 (-0.5, -0.5) 및 (3.5, 3.5) 사이에 동일한 쿼드를 그리는 결과를 보여 줍니다.

래스터화된 쿼드와 일치하는 텍스처 쿼드 그림

앞의 그림은 쿼드((-0.5, -0.5)에서 (3.5, 3.5)로 윤곽선으로 표시된) 래스터화된 영역과 정확히 일치하는 것을 보여 줍니다.

요약

요약하자면 픽셀과 텍셀은 실제로 단색 블록이 아닌 점입니다. 화면 공간은 왼쪽 위 픽셀에서 시작되지만 텍스처 좌표는 텍스처 그리드의 왼쪽 위 모서리에서 시작됩니다. 가장 중요한 것은 텍셀을 픽셀과 올바르게 정렬하기 위해 변환된 화면 공간에서 작업할 때 꼭짓점 위치의 x 및 y 구성 요소에서 0.5 단위를 빼야 합니다.

다음 코드는 변환된 화면 공간에 256 by 256 텍스처를 제대로 표시하기 위해 256 by 256 정사각형의 꼭짓점을 오프셋하는 예제입니다.

//define FVF with vertex values in transformed screen space
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_TEX1)

struct CUSTOMVERTEX
{
    FLOAT x, y, z, rhw; // position
    FLOAT tu, tv;       // texture coordinates
};

//unadjusted vertex values
float left = 0.0f;
float right = 255.0f;
float top = 0.0f;
float bottom = 255.0f;


//256 by 256 rectangle matching 256 by 256 texture
CUSTOMVERTEX vertices[] =
{
    { left,  top,    0.5f, 1.0f, 0.0f, 0.0f}, // x, y, z, rhw, u, v
    { right, top,    0.5f, 1.0f, 1.0f, 0.0f},
    { right, bottom, 0.5f, 1.0f, 1.0f, 1.0f},
    { left,  top,    0.5f, 1.0f, 0.0f, 0.0f},
    { right, bottom, 0.5f, 1.0f, 1.0f, 1.0f},
    { left,  bottom, 0.5f, 1.0f, 0.0f, 1.0f},
    
};
//adjust all the vertices to correctly line up texels with pixels 
for (int i=0; i<6; i++)
{
    vertices[i].x -= 0.5f;
    vertices[i].y -= 0.5f;
}

텍스처 좌표