전체 화면 쿼드로 렌더 대상에 대한 완벽한 픽셀 렌더링


9

rendertarget에 많은 값을 렌더링하는 데 문제가 있습니다. 값은 내가 원하는 정확한 범위로 끝나지 않습니다. 기본적으로 전체 화면 쿼드 및 픽셀 셰이더를 사용하여 렌더 대상 텍스처에 렌더링 한 다음 셰이더에서 일부 계산의 기준으로 텍스처 좌표를 사용하려고합니다. 쿼드의 텍스처 좌표는 왼쪽 상단의 (0,0)에서 오른쪽 하단의 (1,1)까지입니다. 보간 후 이러한 값은 픽셀 쉐이더에 도달하지 않습니다. .

예 : 4x4 텍스처로 렌더링 하고이 경우 셰이더는 단순히 빨강 및 녹색 채널의 텍스처 좌표 (u, v)를 출력합니다.

return float4(texCoord.rg, 0, 1);

내가 꺼내고 싶은 것은 왼쪽 상단의 픽셀이 RGB (0,0,0)이므로 검은 색이므로 오른쪽 상단의 픽셀은 RGB (255,0,0)이므로 밝습니다. 빨간색이며 왼쪽 하단의 픽셀은 RGB (0,255,0)이며 밝은 녹색입니다.

그러나 대신 오른쪽에 이것을 얻습니다.

(직선 쿼드 렌더링, 보정 없음)
쿼드의 직선 렌더링, 보정 없음

왼쪽 상단 픽셀은 검은 색이지만 다른 모서리에는 상대적으로 짙은 빨간색과 짙은 녹색 만 있습니다. RGB 값은 (191,0,0) 및 (0,191,0)입니다. 쿼드의 샘플링 위치와 관련이 있다고 생각합니다. 왼쪽 상단 픽셀은 쿼드의 왼쪽 상단을 올바르게 샘플링하고 UV 좌표로 (0,0)을 얻지 만 다른 코너 픽셀은 샘플링되지 않습니다. 쿼드의 다른 모서리. 왼쪽 이미지에서 쿼드를 나타내는 파란색 상자와 흰색 점이 상위 샘플링 좌표를 사용하여 이것을 설명했습니다.

이제 Direct3D9에서 화면 정렬 된 쿼드를 렌더링 할 때 좌표에 적용해야하는 절반 픽셀 오프셋에 대해 알고 있습니다. 내가 어떤 종류의 결과를 얻었는지 보자.

(DX9의 반 픽셀 오프셋으로 렌더링 된 쿼드)
반 픽셀 오프셋으로 렌더링 된 쿼드

빨강과 초록이 밝아졌지만 여전히 정확하지 않습니다. 빨강 또는 초록색 채널에서 얻을 수있는 최대 값은 223입니다. 그러나 이제는 더 이상 순수한 검은 색이 아니라 RGB (32,32,0)의 어두운 황색 회색입니다!

실제로 필요한 것은 이런 종류의 렌더링입니다.

(대상 렌더링, 축소 된 쿼드 크기)
정확한 보간을 가진 순수한 검정, 녹색 및 빨강

첫 번째 그림과 비교하여 쿼드의 오른쪽과 아래쪽 테두리를 정확히 한 픽셀 위로 왼쪽으로 이동 해야하는 것처럼 보입니다. 그런 다음 오른쪽 열과 픽셀의 맨 아래 행은 모두 쿼드의 경계에서 UV 좌표를 올바르게 가져옵니다.

VertexPositionTexture[] quad = new VertexPositionTexture[]
{
    new VertexPositionTexture(new Vector3(-1.0f,  1.0f, 1f), new Vector2(0,0)),
    new VertexPositionTexture(new Vector3(1.0f - pixelSize.X,  1.0f, 1f), new Vector2(1,0)),
    new VertexPositionTexture(new Vector3(-1.0f, -1.0f + pixelSize.Y, 1f), new Vector2(0,1)),
    new VertexPositionTexture(new Vector3(1.0f - pixelSize.X, -1.0f + pixelSize.Y, 1f), new Vector2(1,1)),
};

그러나 이것은 제대로 작동하지 않아 아래쪽 및 오른쪽 픽셀이 전혀 렌더링되지 않습니다. 이 픽셀의 중심이 더 이상 쿼드로 덮여 있지 않으므로 쉐이더로 처리되지 않는다고 가정합니다. 쿼드를 조금 더 크게 만들기 위해 픽셀 크기 계산을 약간 씩 변경하면 적어도 4x4 텍스처에서 작동합니다. 더 작은 텍스처에서는 작동하지 않으며 더 큰 텍스처에서도 uv 값의 균일 한 분포가 미묘하게 왜곡 될 것 같습니다.

Vector2 pixelSize = new Vector2((2f / textureWidth) - 0.001f, (2f / textureHeight) - 0.001f);

(작은 텍스처, 예를 들어 1D 룩업 테이블의 경우 pixelSize 계산을 0.001f로 수정했습니다. 작동하지 않으며 0.01f 이상으로 늘려야합니다)

물론 이것은 사소한 예이며 UV를 픽셀 센터에 매핑하는 것에 대해 걱정할 필요없이 CPU에서 훨씬 쉽게이 계산을 수행 할 수 있습니다. 그럼에도 불구하고 실제로 완전하고 완전한 [0, 1] rendertarget의 픽셀 범위!?


그것이 도움이되는 것은 아니지만 똑같은 문제가 있습니다.
IUsedToBeAPygmy

1
선형 샘플링도 비활성화하는 것을 잊지 마십시오.
r2d2rigo

사용중인 좌표계가 화면의 픽셀과 일치하는 것처럼 보이지 않습니다. 만약 그렇다면, 여기에 2 × 2 픽셀 만 그리는 것처럼 보입니다. 첫 번째로 해결해야 할 문제는 좌표 공간의 +1이 화면에서 1 픽셀 이동되도록 프로젝트 및 모델 뷰 행렬을 조정하는 것입니다.
Slipp D. Thompson 1

답변:


4

문제는 UV가 텍스처 좌표가되도록 설계되었다는 것입니다. 0,0의 좌표는 텍스처에서 왼쪽 위 픽셀의 왼쪽 위 모서리이며 일반적으로 텍스처를 읽으려는 위치는 아닙니다. 2D의 경우 해당 픽셀 중간의 텍스처를 읽으려고합니다.

내 수학이 옳다면 일을하기 위해해야 ​​할 일이 있습니다.

return float4((texCoord.rg - (0.5f/textureSize)) * (textureSize/(textureSize-1)), 0, 1);

즉, 적절한 오프셋을 빼서 왼쪽 상단 픽셀을 0,0으로 가져온 다음 스케일을 적용하여 오른쪽 하단을 올바르게 만듭니다.

0-1 범위 밖의 지오메트리에 대한 UV 좌표를 확장하여 동일한 작업을 수행 할 수도 있습니다.


마지막 문장을 자세히 설명하려면 쿼드의 네 모서리에 대한 정점 버퍼의 UV에이 변환을 적용한 다음 픽셀 쉐이더에서 적용하면 return float4(texCoord.rg, 0, 1);됩니다.
Nathan Reed

위의 제안 된 공식을 시도했지만 제대로 작동하지 않았습니다. 위의 4x4 샘플 rendertarget에서 R 및 G 채널에서 왼쪽에서 오른쪽으로 또는 위에서 아래로 0, 42, 127 및 212를 얻습니다. 그러나 균등 간격 단계에서 0에서 255 사이의 값을 원합니다 (0, 85, 170 및 255 인 4x4 텍스처의 경우). 또한 UV 좌표를 변경하려고 시도했지만 아직 올바른 오프셋을 찾지 못했습니다.
마리오

0

첫 번째 그림과 비교하여 쿼드의 오른쪽과 아래쪽 테두리를 정확히 한 픽셀 위로 왼쪽으로 이동 해야하는 것처럼 보입니다.

픽셀의 거의 절반에 불과합니다. 쿼드 정점에서 0.5를 빼기 만하면됩니다. 예를 들어 동일한 질감의 256x256 쿼드를 원합니다. 여기에 요점이 있습니다.

p1 = (-0.5, -0.5)
p2 = (-0.5, 255-0.5)
p3 = (255-0.5, 255-0.5)
p4 = (255-0.5, -0.5)

또는 픽셀 셰이더에 텍셀의 절반을 추가 할 수도 있습니다 (texCoord.rg + 0.5 * (1.0 / texSize))

반 픽셀 오프셋은 DX9에서 알려진 사실입니다. 기사는 당신을 잘 도움이 될 수 있습니다.


0

이것은 선형 샘플링으로 인한 것입니다. 전체 검은 색 상단 왼쪽 픽셀의 오른쪽 아래에있는 텍셀을 보면 R 및 / 또는 G 채널에 63 개가 있고 그 중 2 개가 B에 2 개 있다는 것을 알 수 있습니다. 진흙-진한 노랑색; R과 G는 31, B는 1입니다. 이는 2x2 그룹에 대한 평균 텍셀의 결과이므로 텍스처 필터를 포인트로 설정하는 것이 해결책입니다.


-2

버텍스 쉐이더 처리 후 하드 드라이브에 의해 보간되는 버텍스 출력의 texCoords를 사용하고 있기 때문입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.