Як реалізується функція Anti Aliasing у програмі Ray Tracing?


13

Прочитавши кілька статей в Інтернеті, я з упевненістю можу сказати, що я не знаю, як працює функція Anti-Aliasing під час використання Ray Tracing .

Я розумію, що один піксель / промінь розділений на 4 пікселі та 4 промені, а не на 1 .

Невже хтось може пояснити, як це робиться (бажано з кодом)?


2
Чи можу я просто запропонувати вам переглянути "superampling" en.wikipedia.org/wiki/Supersampling і, можливо, також en.wikipedia.org/wiki/Distributed_ray_tracing ?
Simon F

2
Я також можу порекомендувати прочитати цю главу PBRT pbrt.org/chapters/pbrt_chapter7.pdf та прочитати цей документ lgdv.cs.fau.de/get/785 (який пояснює інший метод, ніж той, що реалізований у pbrt).
Том ван Буссель

1
foreach pixel : p{acc = 0; foreach subsample : s { acc+=sample_scene(s);} store(p, acc);}
щурячий вирод

Відповіді:


12

Я думаю, що можна впевнено сказати, що існують два різні способи здійснення AA в режимі ретрайсингу:

1: якщо у вас є кінцеве зображення та зображення глибини, можна застосувати майже всі існуючі методи, які використовуються в іграх (FXAA тощо). Вони працюють безпосередньо на кінцевому зображенні та не пов'язані з просвічуванням

2: другий метод - врахування декількох променів на кожен піксель, а потім усереднення результату. Для дуже простої версії подумайте про це так:

  • спочатку ви створюєте зображення розміром 1024x1024, один промінь для кожного пікселя (наприклад)
  • після візуалізації ви масштабуєте зображення до 512x512 (кожний 4 пікселя збільшено до одного), і ви можете помітити, що краї виходять більш гладкими. Таким чином ви ефективно використовували 4 промені для кожного пікселя в кінцевому зображенні розміром 512x512.

Існують і інші варіанти цього методу. Наприклад, ви можете адаптувати кількість вибірок для пікселів, які знаходяться прямо на краю геометрії, тобто для деяких пікселів у вас буде лише 4 зразки, а для інших 16.

Перевірте посилання в коментарях вище.


Отже, в основному я відтворюю зображення великого розміру і, зберігаючи його на зображенні, зменшую його масштаб на менший розмір? Це здається досить простим :)! Це метод супер вибірки?
Арджан Сінгх

2
@Arjan Singh так, це en.wikipedia.org/wiki/Supersampling , але це найповільніше з усіх, переймовірність дозволяє легко робити адаптивне суперсимплінг, який може працювати набагато краще
Raxvan

14

Раксван абсолютно прав, що "традиційні" методи згладжування будуть працювати в режимі ретрансляції, включаючи ті, які використовують інформацію, таку як глибина, щоб зробити антиализацию. Ви можете навіть зробити тимчасове протизшивання, наприклад, у відстеженні променів.

Жюльєн розширив 2-й пункт Raxvan, який був поясненням супер вибірки, і показав, як ви насправді це зробите, також зазначивши, що ви можете рандомізувати розташування зразків у межах пікселя, але потім ви входите в країну обробки сигналів, яка дуже багато глибше, і це точно є!

Як сказав Жюльєн, якщо ви хочете робити вибірок на піксель, ви можете розбити піксель на рівномірно розподілених точок вибірки (в основному за сіткою) і середньо оцінити ці зразки.NNN

Якщо ви зробите це, ви все одно можете отримати згладжування. Це краще, ніж НЕ робити це, оскільки ви збільшуєте частоту дискретизації, тому ви зможете обробляти дані більш високої частоти (інакше менші деталі), але це все ще може спричинити згладжування.

Якщо замість цього ви берете випадкових зразків у межах пікселя, ви ефективно торгуєте на псевдонім для шуму. Шум легший для очей і виглядає природніше, ніж згладжування, тому зазвичай є кращим результатом. Я вважаю, що це навіть ідеально ідеальна ситуація з більшим підрахунком вибірки, але не маю більше інформації про це):N

Коли ви використовуєте просто "звичайні" випадкові числа, такі як ви отримаєте від rand () або std :: uniform_int_distribution, який називається "білий шум", оскільки він містить усі частоти, як, наприклад, як біле світло складається з усіх інших кольорів (частоти ) світла.

Використання білого шуму для рандомізації зразків у межах пікселя має проблему, що іноді ваші зразки збиваються разом. Наприклад, якщо ви в середньому 100 зразків у пікселі, але вони ВСЕ в кінці знаходяться у верхньому лівому куті пікселя, ви не збираєтесь отримувати БУДЬ-яку інформацію про інші частини пікселя, тож ваш остаточний колір пікселя буде відсутня інформація про те, якого кольору він повинен бути.

Кращий підхід - використовувати щось, що називається синім шумом, який містить лише високочастотні компоненти (наприклад, як синє світло - високочастотне світло).

Перевага блакитного шуму полягає в тому, що ви отримуєте рівномірне покриття над пікселем, як і з рівномірною сіткою вибірки, але ви все одно отримуєте деяку випадковість, яка перетворюється в псевдонім на шум і дає вам краще виглядати зображення.

На жаль, синій шум може бути дуже дорогим для обчислення, і найкращі методи всі, здається, запатентовані (що за чорт ?!), але один із способів зробити це, винайдений pixar (і запатентований теж я думаю, але не на 100% впевнений) полягає в тому, щоб зробити рівну сітку зразкових точок, а потім випадковим чином зрушити кожну точку вибірки на невелику кількість - як випадкову кількість між плюсом або мінусом половини ширини та висоти сітки вибірки. Таким чином ви отримуєте сорт синього відбору шуму досить дешево.

Зауважте, що це форма стратифікованої вибірки, а вибірка пуассонівських дисків - це також форма, яка також є способом генерування синього шуму: https://www.jasondavies.com/poisson-disc/

Якщо ви зацікавлені у заглибленні, ви, напевно, також захочете перевірити це питання та відповісти!

Яке основне міркування для антизбудження з використанням декількох випадкових зразків у межах пікселя?

Нарешті, цей матеріал починає проникати у царство простеження шляху Монте-Карло, що є загальним методом фотореалістичного проміння. якщо вам цікаво дізнатися більше про це, прочитайте це!

http://blog.demofox.org/2016/09/21/path-tracing-getting-started-with-diffuse-and-emissive/


Щойно я побачив ваше ім’я, я зрозумів, що ви включите щось із синього шуму :)
Хаббл,

Оскільки це знову з'явилося як активне: Щоб пояснити, чому це так, - схеми відбору проб синього шуму переважають при інтеграції функцій з більшістю енергії, сконцентрованої на низьких частотах. Таким чином, використовуючи синій зразок шуму, ви ефективно припускаєте, що ваш сигнал здебільшого плавний / переважають низькі частоти. Для високочастотних сигналів це може бути насправді контрпродуктивним. На щастя, природні зображення мають свою енергію, сконцентровану на низьких частотах. Детальніше дивіться: sampling.mpi-inf.mpg.de/2019-singh-fourier.html
lightxbulb

7

Припустимо, досить типовий промінь основного циклу:

struct Ray
{
    vec3 origin;
    vec3 direction;
};

RGBColor* image = CreateImageBuffer(width, height);

for (int j=0; j < height; ++i)
{
    for (int i=0; i < width; ++i)
    {
        float x = 2.0 * (float)i / (float)max(width, height) - 1.0;
        float y = 2.0 * (float)j / (float)max(width, height) - 1.0;

        vec3 dir = normalize(vec3(x, y, -tanHalfFov));
        Ray r = { cameraPosition, dir };

        image[width * j + i] = ComputeColor(r);
    }
}

Однією з можливих модифікацій його для виконання 4-х зразків SSAA буде:

float jitterMatrix[4 * 2] = {
    -1.0/4.0,  3.0/4.0,
     3.0/4.0,  1.0/3.0,
    -3.0/4.0, -1.0/4.0,
     1.0/4.0, -3.0/4.0,
};

for (int j=0; j < height; ++i)
{
    for (int i=0; i < width; ++i)
    {
        // Init the pixel to 100% black (no light).
        image[width * j + i] = RGBColor(0.0);

        // Accumulate light for N samples.
        for (int sample = 0; sample < 4; ++sample)
        {
            float x = 2.0 * (i + jitterMatrix[2*sample]) / (float)max(width, height) - 1.0;
            float y = 2.0 * (i + jitterMatrix[2*sample+1]) / (float)max(width, height) - 1.0;

            vec3 dir = normalize(vec3(x, y, -tanHalfFov) + jitter);
            Ray r = { cameraPosition, dir };

            image[width * j + i] += ComputeColor(r);
        }

        // Get the average.
        image[width * j + i] /= 4.0;
    }
}

Інша можливість полягає в тому, щоб зробити випадкове тремтіння (замість матриці, заснованої вище), але ви незабаром увійдете в сферу обробки сигналів, і це потребує багато читання, щоб знати, як вибрати гарну функцію шуму.

Ідея, однак, залишається такою ж: розгляньте, що піксель представляє собою крихітну квадратну площу, і замість того, щоб знімати лише один промінь, який проходить через центр пікселя, знімайте багато променів, що охоплюють всю піксельну площу. Чим щільніше розподіл променів, тим краще ви отримуєте сигнал.

PS: Я написав код вище на льоту, тому очікував на нього декілька помилок. Це покликане лише показати основну ідею.


Чудова відповідь! Які б були переваги використання цього методу на відміну від використовуваного методу @Raxvan? Чи отримаю я однакові результати, вивівши великі розміри, а потім зменшивши масштаб на менший розмір?
Ар'ян Сінгх

Принципово, за допомогою трасування променів вам просто не потрібно робити більше зображення, а потім масштабувати його. Це означає, що ви маєте набагато більшу гнучкість: у вас може бути багато зразків, ви можете змінювати кількість зразків залежно від регіону, і вам просто не потрібно додавати крок зміни шкали.
Жульєн Герто

2
Що стосується тремтіння, це виявляється досить складною темою. Ось чудовий документ, що аналізує сучасний стан за кілька років тому graphics.pixar.com/library/MultiJitteredSampling/paper.pdf
Mikkel Gjoel

Зразок коду вище використовує 4-зразковий MSAA, якби я хотів зробити 8x MSAA, як виглядатиме матриця тоді? Що мені потрібно змінити в матриці тремтіння, показаній вище?
Арджан Сінгх

1
@SimonF Дякую, що вказали на це. Виправлено.
Жульєн Герто

1

Просто для додання відповідей вище:

Розподілене трасування променів (Кук, Портер та Тесляр). Дозволяє одночасно робити просторовий AA, часовий AA (тобто розмиття руху) та фокус / глибину різкості. Найкраще читати папір, але в основному N-променів, які ви стріляють на піксель, також можна призначати псевдовипадкові рази (для розмиття руху) та положення на лінзі (для отримання ефектів фокусування).

Адаптивне суперсимуляція: Ви спочатку запускаєте певну кількість променів на піксель. Однак якщо промені в місцевому мікрорайоні повертають суттєво різні результати, то ви можете локально збільшити швидкість вибірки (скажімо, 2x), щоб покращити результати. Ви можете вибрати повторення процесу. Це не ідеально, оскільки предмети все ще можуть «потрапляти між зразками», але це можливо дешевше, ніж рівномірна вибірка з більшою швидкістю.

Промінь проміння конусами (Аманатіди): Замість використання нескінченно тонкого променя кожен промінь замість цього наближається конусом, скажімо, діаметром, який охоплює весь піксель (і трохи сусідів), що дозволяє оцінити часткове покриття . Він також має переваги для відбору проб текстури / антиалійного, м'яких тіней та потенційно LOD моделей. Я робив реалізацію багато років тому - це, звичайно, важче зробити, але уникати безлічі додаткових променів. У IIRC також була схема, яка називалася калька олівцем (але в моєму початковому пошуку не знайшлося посилання на папір)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.