Віртуальне текстурування - це логічний крайнощ текстурних атласів.
Атлас текстури - це одна гігантська текстура, яка містить текстури для окремих сіток всередині неї:
Текстурні атласи набули популярності завдяки тому, що зміна текстур спричиняє повний поток конвеєра на графічному процесорі. Під час створення сіток УФ випромінюються / зміщуються таким чином, щоб вони представляли правильну 'частину' всього атласу текстури.
Як згадується в коментарях @ nathan-reed, одним з головних недоліків текстурних атласів є втрата режимів обгортання, таких як повтор, затискання, облямування тощо. Крім того, якщо текстури не мають достатньої межі навколо них, ви можете випадково зразок із сусідньої текстури при фільтруванні. Це може призвести до кровотечі артефактів.
Атласи текстур мають одне основне обмеження: розмір. Графічні API встановлюють чітку межу щодо того, наскільки великою може бути текстура. Однак, графічна пам’ять лише така велика. Отже, існує також жорсткий ліміт щодо розміру текстури, що визначається розміром вашого v-ram. Віртуальні текстури вирішують цю проблему, запозичивши поняття з віртуальної пам'яті .
Віртуальні текстури використовують той факт, що в більшості сцен ви бачите лише невелику частину всіх текстур. Отже, лише той підмножина текстур має бути в vram. Решта може бути в основній оперативній пам'яті або на диску.
Є декілька способів його реалізації, але я поясню реалізацію, описану Шоном Барреттом у своїй розмові про GDC . (яку я дуже рекомендую переглянути)
У нас є три основні елементи: віртуальна текстура, фізична текстура та таблиця пошуку.
Віртуальна текстура являє собою теоретичний мега атлас, який у нас був би, якби у нас було достатньо vram, щоб усе вмістити. Він насправді ніде не існує в пам'яті. Фізична текстура представляє, які дані пікселів у нас фактично є. Таблиця пошуку - це відображення між ними. Для зручності ми розбиваємо всі три елементи на однакові за розміром плитки або сторінки.
У таблиці пошуку зберігається розташування верхнього лівого кута плитки у фізичній текстурі. Отже, з ультрафіолетом всієї віртуальної текстури, як ми можемо отримати відповідний УФ для фізичної текстури?
Спочатку нам потрібно знайти розташування сторінки в межах фізичної текстури. Тоді нам потрібно обчислити розташування УФ всередині сторінки. Нарешті, ми можемо додати ці два компенсації разом, щоб отримати розташування УФ у межах фізичної текстури
float2 pageLocInPhysicalTex = ...
float2 inPageLocation = ...
float2 physicalTexUV = pageLocationInPhysicalTex + inPageLocation;
Розрахунок сторінкиLocInPhysicalTex
Якщо ми зробимо таблицю пошуку такого ж розміру, що і кількість плиток у віртуальній текстурі, ми можемо просто відібрати таблицю пошуку з вибіркою найближчого сусіда, і ми отримаємо розташування верхнього лівого кута сторінки в межах фізичної текстури.
float2 pageLocInPhysicalTex = lookupTable.Sample(virtTexUV, nearestNeighborSampler);
Обчислення inPageLocation
inPageLocation - це УФ-координата, яка відносно верхнього лівого краю сторінки, а не верхнього лівого усього текстури.
Один із способів обчислити це - віднімаючи УФ у верхньому лівому куті сторінки, а потім масштабування до розміру сторінки. Однак це зовсім небагато математики. Натомість ми можемо використовувати, як представлена плаваюча точка IEEE. IEEE з плаваючою точкою зберігає дробову частину числа серією базових дробів.
У цьому прикладі число:
number = 0 + (1/2) + (1/8) + (1/16) = 0.6875
Тепер давайте розглянемо спрощену версію віртуальної текстури:
1/2 біта говорить нам, чи ми знаходимося в лівій половині текстури або в правій. 1/4 біт говорить нам про те, в якій чверті половини ми знаходимося. У цьому прикладі, оскільки текстура розділена на 16, або 4 в бік, ці перші два біти вказують нам, на якій сторінці ми знаходимося. біти повідомляють нам про розташування всередині сторінки.
Решта бітів ми можемо отримати, перемістивши float на exp2 () і викресливши їх 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 - це УФ-координата у віртуальній текстурі 'простір'. Однак ми хочемо, щоб ультрафіолетова координата у фізичному текстурі "простору". Для цього нам просто потрібно масштабувати inPageLocation за відношенням розміру віртуальної текстури до фізичного розміру текстури
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;
}