가상 텍스처링은 텍스처 아틀라스의 논리적 극단입니다.
텍스처 아틀라스는 그 안에 개별 메시에 대한 텍스처를 포함하는 하나의 거대한 텍스처입니다.
텍스쳐 아틀라스는 텍스처 변경으로 인해 GPU에서 전체 파이프 라인 플러시가 발생하기 때문에 대중화되었습니다. 메시를 만들 때 UV는 압축 / 시프 팅되어 전체 텍스처 아틀라스의 올바른 '부분'을 나타냅니다.
주석에서 @ nathan-reed가 언급했듯이 텍스처 아틀라스의 주요 단점 중 하나는 반복, 클램프, 테두리 등과 같은 랩 모드를 잃는 것입니다. 또한 텍스처에 테두리가 충분하지 않으면 실수로 실수로 할 수 있습니다 필터링 할 때 인접한 텍스처에서 샘플링합니다. 이것은 출혈 인공물로 이어질 수 있습니다.
Texture Atlases에는 크기라는 큰 제한이 있습니다. 그래픽 API는 텍스처의 크기에 대한 소프트 제한을 설정합니다. 즉, 그래픽 메모리는 너무 큽니다. 따라서 v-ram의 크기에 따라 질감 크기에 대한 제한도 있습니다. 가상 텍스처는 가상 메모리 에서 개념을 빌려이 문제를 해결합니다 .
가상 텍스처는 대부분의 장면에서 모든 텍스처의 작은 부분 만 볼 수 있다는 사실을 이용합니다. 따라서 텍스처의 하위 집합 만 vram에 있어야합니다. 나머지는 기본 RAM 또는 디스크에있을 수 있습니다.
그것을 구현하는 몇 가지 방법이 있지만, 나는 Sean Barrett이 그의 GDC talk 에서 설명한 구현을 설명 할 것이다 . (저는 시청하는 것이 좋습니다)
가상 텍스처, 물리적 텍스처 및 조회 테이블의 세 가지 주요 요소가 있습니다.
가상 텍스처는 모든 것에 맞도록 충분한 vram을 가지고 있다면 이론적 인 메가 아틀라스를 나타냅니다. 실제로 메모리 어디에도 존재하지 않습니다. 실제 텍스처는 실제로 vram에있는 픽셀 데이터를 나타냅니다. 조회 테이블은 둘 사이의 매핑입니다. 편의상 세 요소를 모두 같은 크기의 타일 또는 페이지로 나눕니다.
룩업 테이블은 실제 텍스처에서 타일의 왼쪽 상단 모서리 위치를 저장합니다. 따라서 전체 가상 텍스처에 UV가 주어지면 실제 텍스처에 해당하는 UV를 어떻게 얻습니까?
먼저 실제 텍스처 내에서 페이지의 위치를 찾아야합니다. 그런 다음 페이지 내에서 UV의 위치를 계산해야합니다. 마지막으로이 두 오프셋을 더하여 물리적 텍스처 내 UV 위치를 얻을 수 있습니다
float2 pageLocInPhysicalTex = ...
float2 inPageLocation = ...
float2 physicalTexUV = pageLocationInPhysicalTex + inPageLocation;
pageLocInPhysicalTex 계산
룩업 테이블을 가상 텍스처의 타일 수와 동일한 크기로 만들면 가장 가까운 이웃 샘플링으로 룩업 테이블을 샘플링하면 실제 텍스처 내에서 페이지의 왼쪽 상단 모서리 위치를 얻을 수 있습니다.
float2 pageLocInPhysicalTex = lookupTable.Sample(virtTexUV, nearestNeighborSampler);
PageLocation에서 계산
inPageLocation은 전체 텍스처의 왼쪽 위가 아니라 페이지 왼쪽 위를 기준으로하는 UV 좌표입니다.
이를 계산하는 한 가지 방법은 페이지 왼쪽 상단의 UV를 빼고 페이지 크기로 조정하는 것입니다. 그러나 이것은 약간의 수학입니다. 대신, IEEE 부동 소수점이 어떻게 표현되는지를 활용할 수 있습니다. IEEE 부동 소수점은 일련의 기수 2 분수로 숫자의 소수 부분을 저장합니다.
이 예에서 숫자는 다음과 같습니다.
number = 0 + (1/2) + (1/8) + (1/16) = 0.6875
이제 가상 텍스처의 단순화 된 버전을 살펴 보겠습니다.
1/2 비트는 텍스처의 왼쪽 절반에 있는지 아니면 오른쪽에 있는지 알려줍니다. 1/4 비트는 우리가 반의 1/4을 알려줍니다.이 예에서는 텍스처가 16 또는 4로 나뉘어져 있기 때문에 처음 두 비트는 우리가 어떤 페이지에 있는지 알려줍니다. 비트는 페이지 내의 위치를 알려줍니다.
exp2 ()로 float를 이동시키고 fract ()로 제거하여 나머지 비트를 얻을 수 있습니다.
float2 inPageLocation = virtTexUV * exp2(sqrt(numTiles));
inPageLocation = fract(inPageLocation);
여기서 numTiles는 텍스처의 측면 당 타일 수를 제공하는 int2입니다. 이 예에서는 (4, 4)입니다.
녹색 점에 대한 inPageLocation을 계산해 봅시다. (x, y) = (0.6875, 0.375)
inPageLocation = float2(0.6875, 0.375) * exp2(sqrt(int2(4, 4));
= float2(0.6875, 0.375) * int2(2, 2);
= float2(1.375, 0.75);
inPageLocation = fract(float2(1.375, 0.75));
= float2(0.375, 0.75);
우리가 끝나기 전에 할 마지막 일. 현재 inPageLocation은 가상 텍스처 '공간'의 UV 좌표입니다. 그러나 물리적 텍스처 '공간'에는 UV 좌표가 필요합니다. 이를 위해 가상 텍스처 크기와 실제 텍스처 크기의 비율로 PagePage에서 크기를 조정하면됩니다.
inPageLocation *= physicalTextureSize / virtualTextureSize;
완성 된 기능은 다음과 같습니다.
float2 CalculatePhysicalTexUV(float2 virtTexUV, Texture2D<float2> lookupTable, uint2 physicalTexSize, uint2 virtualTexSize, uint2 numTiles) {
float2 pageLocInPhysicalTex = lookupTable.Sample(virtTexUV, nearestNeighborSampler);
float2 inPageLocation = virtTexUV * exp2(sqrt(numTiles));
inPageLocation = fract(inPageLocation);
inPageLocation *= physicalTexSize / virtualTexSize;
return pageLocInPhysicalTex + inPageLocation;
}