Sanal Tekstüre, doku atlaslarının mantıksal aşırı noktasıdır.
Doku atlası, içindeki tek kafesler için dokular içeren tek bir dev dokudır:
Doku atlasları, değişen dokuların GPU'da tam bir boru hattı hizasına yol açması nedeniyle popüler hale geldi. Ağlar oluşturulurken UV'ler sıkıştırılır / kaydırılır, böylece bütün doku atlasının doğru 'kısmını' temsil ederler.
Yorumlarda @ nathan-reed'den bahsedildiği gibi, doku atlaslarının ana dezavantajlarından biri tekrar, kelepçe, kenarlık, vb. Gibi sarma modlarını kaybediyor. filtreleme yaparken bitişik bir dokudan numune alın. Bu kanama artefaktlarına yol açabilir.
Doku Atlaslarının bir büyük sınırlaması vardır: boyut. Grafik API'leri bir dokunun ne kadar büyük olabileceğine yumuşak bir sınır koyar. Bununla birlikte, grafik belleği sadece çok büyük. Bu yüzden v-ram'ınızın boyutuna göre, doku boyutunda da sert bir sınır vardır. Sanal dokular, kavramları sanal bellekten ödünç alarak bu sorunu çözer .
Sanal dokular, çoğu sahnede, tüm dokuların yalnızca küçük bir kısmını gördüğünüz gerçeğinden yararlanır. Bu nedenle, yalnızca bu doku alt kümesinin vramda olması gerekir. Gerisi ana RAM'de veya diskte olabilir.
Uygulamanın birkaç yolu var, ancak Sean Barrett tarafından açıklanan uygulamayı GDC konuşmasında açıklayacağım . (ki izlemenizi şiddetle tavsiye ederim)
Üç ana öğemiz var: sanal doku, fiziksel doku ve arama tablosu.
Sanal doku, herşeye uyacak kadar vram olsaydı sahip olacağımız teorik mega atlası temsil eder. Aslında hiçbir yerde bellekte yok. Fiziksel doku, aslında sahip olduğumuz piksel veriyi temsil ediyor. Arama tablosu ikisi arasındaki eşleşmedir. Kolaylık sağlamak için, her üç elemanı da eşit boyuttaki plakalara veya sayfalara böldük.
Arama tablosu, döşemenin sol üst köşesinin konumunu fiziksel dokuda saklar. Öyleyse, tüm sanal dokuya bir UV verilmişse, fiziksel dokuya karşılık gelen UV'yi nasıl elde ederiz?
İlk önce, sayfanın konumunu fiziksel doku içinde bulmamız gerekiyor. Ardından UV'nin sayfa içindeki konumunu hesaplamamız gerekir. Sonunda UV'nin fiziksel doku içindeki yerini bulmak için bu iki ofseti bir araya getirebiliriz.
float2 pageLocInPhysicalTex = ...
float2 inPageLocation = ...
float2 physicalTexUV = pageLocationInPhysicalTex + inPageLocation;
Sayfa hesaplamaLocInPhysicalTex
Arama tablosunu sanal dokudaki döşemelerin sayısıyla aynı boyutta yaparsak, arama tablosunu en yakın komşu örneklemesiyle örnekleyebiliriz ve sayfanın sol üst köşesinin fiziksel doku içindeki konumunu elde ederiz.
float2 pageLocInPhysicalTex = lookupTable.Sample(virtTexUV, nearestNeighborSampler);
İnPageLocation'ın hesaplanması
inPageLocation, tüm dokunun sol üst kısmına değil, sayfanın sol üst kısmına göre olan bir UV koordinatıdır.
Bunu hesaplamanın bir yolu, sayfanın sol üst kısmındaki UV ışığını çıkarmak, sonra da sayfanın boyutuna ölçeklendirmektir. Ancak, bu biraz matematik. Bunun yerine, IEEE kayan noktalarının nasıl temsil edildiğini kullanabiliriz. IEEE kayan nokta, bir sayının kesirli kısmını, bir dizi baz 2 kesir ile saklar.
Bu örnekte, sayı:
number = 0 + (1/2) + (1/8) + (1/16) = 0.6875
Şimdi sanal dokunun basitleştirilmiş bir versiyonuna bakalım:
1/2 biti bize, dokunun sol yarısında mı yoksa sağ mı olduğumuzu söyler. 1/4 bit bize hangi yarıda olduğumuzu söyler. Bu örnekte, doku 16 veya 4'e bir kenara ayrıldığından, bu ilk iki bit bize hangi sayfada olduğumuzu söyler. bit, bize sayfanın içindeki konumu söyler.
Kalan bitleri, float'ı exp2 () ile değiştirerek ve onları fract () ile çıkartarak elde edebiliriz.
float2 inPageLocation = virtTexUV * exp2(sqrt(numTiles));
inPageLocation = fract(inPageLocation);
NumTiles, dokunun her bir yüzündeki fayans sayısını veren bir int2'dir. Örneğimizde, bu (4, 4) olur
Öyleyse yeşil nokta için inPageLocation değerini hesaplayalım, (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);
Yapmadan önce yapılacak son bir şey. Şu anda, inPageLocation sanal dokudaki 'boşluk' içindeki bir UV koordinatıdır. Bununla birlikte, fiziksel dokuda 'uzayda' bir UV koordinatı istiyoruz. Bunu yapmak için, inPageLocation'ı sanal doku boyutunun fiziksel doku boyutuna oranıyla ölçeklememiz gerekiyor
inPageLocation *= physicalTextureSize / virtualTextureSize;
Yani bitmiş fonksiyon:
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;
}