Що таке вибіркове значення?


33

У чому полягає важливість вибірки? У кожній статті, яку я прочитав про неї, згадується "PDF", що це також?

З того, що я збираю, вибіркове значення - це методика вибірки лише ділянок на півкулі, які мають значення більше, ніж інші. Тож в ідеалі я повинен пробувати промені до джерел світла, щоб зменшити шум і збільшити швидкість. Крім того, деякі БРР під кутом випасу мають незначну різницю в обчисленні, тому використовуючи важливий вибірки, щоб уникнути, що це добре?

Якби я здійснив вибірку важливості для BRDF Cook-Torrance, як я можу це зробити?


Це посилання, яке добре читається, що пояснює, що таке PDF. TL; DR PDF - це функція, яка описує ймовірність випадкових чисел (безперервна ака з плаваючою точкою). Генерування випадкових чисел з конкретного PDF може бути складним завданням, і для цього є кілька методів. Це говорить про одну з них. Стаття після цієї розповідає про інший шлях. blog.demofox.org/2017/08/05/…
Алан Вулф

Відповіді:


51

Коротка відповідь:

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

PDF - це абревіатура для функції ймовірності щільності . дає можливість випадкової вибірки генерується бути .pdf(x)x

Довга відповідь:

Для початку давайте розглянемо, що таке інтеграція Монте-Карло та як це виглядає математично.

Інтеграція Монте-Карло - це методика оцінки значення інтеграла. Зазвичай він використовується, коли для інтеграла немає рішення закритої форми. Це виглядає приблизно так:

f(x)dx1Ni=1Nf(xi)pdf(xi)

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

Давайте зробимо приклад: Обчислити значення інтеграла .I

I=02πexsin(x)dx

Давайте скористаємося інтеграцією Монте-Карло:

I1Ni=1Nexsin(xi)pdf(xi)

Проста програма python для її обчислення:

import random
import math

N = 200000
TwoPi = 2.0 * math.pi

sum = 0.0

for i in range(N):
    x = random.uniform(0, TwoPi)

    fx = math.exp(-x) * math.sin(x)
    pdf = 1 / (TwoPi - 0.0)

    sum += fx / pdf

I = (1 / N) * sum
print(I)

Якщо ми запустимо програму, то отримаємоI=0.4986941

Використовуючи розділення на частини, ми можемо отримати точне рішення:

I=12(1e2π)=0.4990663

Ви помітите, що рішення Монте-Карло не зовсім правильне. Це тому, що це оцінка. Однак, коли переходить до нескінченності, оцінка повинна наближатися до наближеної до правильної відповіді. Вже при деякі пробіги майже ідентичні правильній відповіді.NN=2000

Примітка про PDF: У цьому простому прикладі ми завжди беремо рівномірну випадкову вибірку. Рівномірний випадковий зразок означає, що кожен зразок має точно таку ж ймовірність бути обраним. Вибираємо вибір у діапазоні так,[0,2π]pdf(x)=1/(2π0)

Вибірки Важливість роботи по НЕ рівномірно вибірки. Натомість ми намагаємося вибирати більше зразків, які багато сприяють результату (важливо), і менше вибірок, які лише трохи сприяють результату (менш важливі). Звідси назва, важливість вибірки.

Якщо ви вибрали функцію вибірки, чий pdf дуже відповідає формі , ви можете значно зменшити дисперсію, а це означає, що ви можете брати менше вибірок. Однак якщо ви виберете функцію вибірки, значення якої сильно відрізняється від , ви можете збільшити дисперсію. Дивіться малюнок нижче: Зображення з дисертації Войцеха Яроша Додаток АffПорівняння хорошої вибірки та поганої вибірки

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

Вихідні промені можуть йти в будь-яку точку півкулі

Ми могли б рівномірно відібрати півсферу для генерування нового променя. Однак ми можемо використати той факт, що рівняння візуалізації має в ньому косинусний фактор:

Lo(p,ωo)=Le(p,ωo)+Ωf(p,ωi,ωo)Li(p,ωi)|cosθi|dωi

Зокрема, ми знаємо, що будь-які промені на горизонті будуть сильно ослаблені (конкретно, ). Отже, промені, що утворюються біля горизонту, не дуже сприятимуть кінцевому значенню.cos(x)

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

У вашому випадку ви вказали, що будете використовувати файл BRDF на основі Cookface Torrance. Поширена форма:

f(p,ωi,ωo)=F(ωi,h)G(ωi,ωo,h)D(h)4cos(θi)cos(θo)

де

F(ωi,h)=Fresnel functionG(ωi,ωo,h)=Geometry Masking and Shadowing functionD(h)=Normal Distribution Function

У блозі "Примітка хлопця Графіка" є чудовим записом щодо вибірки BRDF-файлів Cook-Torrance. Я посилаюсь на його допис у блозі . З цього приводу я спробую створити короткий огляд нижче:

NDF, як правило, є домінуючою частиною BRDF Cook-Torrance, тому, якщо ми збираємося до важливої ​​вибірки, ми повинні зробити вибірку на основі NDF.

Cook-Torrance не визначає конкретний NDF для використання; ми можемо вибирати те, що підходить для нашої фантазії. Однак, є кілька популярних НДФ:

  • GGX
  • Бекман
  • Блінн

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

GGX визначається як:

DGGX(m)=α2π((α21)cos2(θ)+1)2

Для вибірки куля сферичних координат ми можемо використовувати формулу:θ

θ=arccos(α2ξ1(α21)+1)

де - рівномірна випадкова величина.ξ

Ми припускаємо, що NDF є ізотропним, тому ми можемо проводити вибірку рівномірно:ϕ

ϕ=ξ2

Бекмана визначають як:

DBeckmann(m)=1πα2cos4(θ)etan2(θ)α2

Яку можна взяти на вибірку:

θ=arccos(11=α2ln(1ξ1))ϕ=ξ2

Нарешті, Блінн визначається як:

DBlinn(m)=α+22π(cos(θ))α

Яку можна взяти на вибірку:

θ=arccos(1ξ1α+1)ϕ=ξ2

Втілення в практику

Давайте розглянемо основний відстежувальний шлях назад:

void RenderPixel(uint x, uint y, UniformSampler *sampler) {
    Ray ray = m_scene->Camera.CalculateRayFromPixel(x, y, sampler);

    float3 color(0.0f);
    float3 throughput(1.0f);

    // Bounce the ray around the scene
    for (uint bounces = 0; bounces < 10; ++bounces) {
        m_scene->Intersect(ray);

        // The ray missed. Return the background color
        if (ray.geomID == RTC_INVALID_GEOMETRY_ID) {
            color += throughput * float3(0.846f, 0.933f, 0.949f);
            break;
        }

        // We hit an object

        // Fetch the material
        Material *material = m_scene->GetMaterial(ray.geomID);
        // The object might be emissive. If so, it will have a corresponding light
        // Otherwise, GetLight will return nullptr
        Light *light = m_scene->GetLight(ray.geomID);

        // If we hit a light, add the emmisive light
        if (light != nullptr) {
            color += throughput * light->Le();
        }

        float3 normal = normalize(ray.Ng);
        float3 wo = normalize(-ray.dir);
        float3 surfacePos = ray.org + ray.dir * ray.tfar;

        // Get the new ray direction
        // Choose the direction based on the material
        float3 wi = material->Sample(wo, normal, sampler);
        float pdf = material->Pdf(wi, normal);

        // Accumulate the brdf attenuation
        throughput = throughput * material->Eval(wi, wo, normal) / pdf;


        // Shoot a new ray

        // Set the origin at the intersection point
        ray.org = surfacePos;

        // Reset the other ray properties
        ray.dir = wi;
        ray.tnear = 0.001f;
        ray.tfar = embree::inf;
        ray.geomID = RTC_INVALID_GEOMETRY_ID;
        ray.primID = RTC_INVALID_GEOMETRY_ID;
        ray.instID = RTC_INVALID_GEOMETRY_ID;
        ray.mask = 0xFFFFFFFF;
        ray.time = 0.0f;
    }

    m_scene->Camera.FrameBuffer.SplatPixel(x, y, color);
}

IE. ми підстрибуємо навколо сцени, накопичуючи колір і ослаблення світла під час руху. При кожному відскоку ми повинні вибирати новий напрямок для променя. Як було сказано вище, ми могли б рівномірно відібрати півсферу для генерування нового променя. Однак код розумніший; це важливо зразки нового напрямку на базі BRDF. (Примітка. Це напрямок введення, тому що ми відстежуємо шлях назад)

// Get the new ray direction
// Choose the direction based on the material
float3 wi = material->Sample(wo, normal, sampler);
float pdf = material->Pdf(wi, normal);

Що може бути реалізовано як:

void LambertBRDF::Sample(float3 outputDirection, float3 normal, UniformSampler *sampler) {
    float rand = sampler->NextFloat();
    float r = std::sqrtf(rand);
    float theta = sampler->NextFloat() * 2.0f * M_PI;

    float x = r * std::cosf(theta);
    float y = r * std::sinf(theta);

    // Project z up to the unit hemisphere
    float z = std::sqrtf(1.0f - x * x - y * y);

    return normalize(TransformToWorld(x, y, z, normal));
}

float3a TransformToWorld(float x, float y, float z, float3a &normal) {
    // Find an axis that is not parallel to normal
    float3a majorAxis;
    if (abs(normal.x) < 0.57735026919f /* 1 / sqrt(3) */) {
        majorAxis = float3a(1, 0, 0);
    } else if (abs(normal.y) < 0.57735026919f /* 1 / sqrt(3) */) {
        majorAxis = float3a(0, 1, 0);
    } else {
        majorAxis = float3a(0, 0, 1);
    }

    // Use majorAxis to create a coordinate system relative to world space
    float3a u = normalize(cross(normal, majorAxis));
    float3a v = cross(normal, u);
    float3a w = normal;


    // Transform from local coordinates to world coordinates
    return u * x +
           v * y +
           w * z;
}

float LambertBRDF::Pdf(float3 inputDirection, float3 normal) {
    return dot(inputDirection, normal) * M_1_PI;
}

Після вибірки inputDirection ('wi' у коді), ми використовуємо це для обчислення значення BRDF. А потім ділимо на pdf відповідно до формули Монте-Карло:

// Accumulate the brdf attenuation
throughput = throughput * material->Eval(wi, wo, normal) / pdf;

Де Eval () - лише функція BRDF (Ламберт, Блінн-Фонг, Кук-Торранс тощо):

float3 LambertBRDF::Eval(float3 inputDirection, float3 outputDirection, float3 normal) const override {
    return m_albedo * M_1_PI * dot(inputDirection, normal);
}

Гарна відповідь. ОП також запитала про вибірку важливості вибірки Cook-Torrance, на яку ця відповідь не стосується.
PeteUK

6
Я оновив відповідь, щоб додати розділ про Кук-Торранс
RichieSams

Наприклад, GGX, для вибірки кульових координат кута cos (θ) ми використовуємо формулу важливості вибірки для обчислення кута і використовуємо цю функцію в GGX як завжди? Або формула повністю замінює GGX?
Арджан Сінгх

3
Я додав розділ, щоб допомогти відповісти на ваші запитання. Але, коротше кажучи, ваш перший метод правильний. Ви використовуєте формулу вибірки для генерації напрямку, потім використовуєте цей новий напрямок у звичайній формулі GGX і отримуєте pdf для формули Монте-Карло.
RichieSams

Як я можу розрахувати / взяти вибірку для GGX wi? Я розумію, як відібрати вибір куля сферичних координат θ, але для вектора фактичного напрямку як це робиться?
Арджан Сінгх

11

Якщо у вас є функція 1D і ви хочете інтегрувати цю функцію від скажімо 0 до 1, одним із способів виконання цієї інтеграції є взяття N випадкових вибірок у діапазоні [0, 1], оцініть для кожного вибірки та обчислити середнє значення для зразків. Однак, як кажуть, ця «наївна» інтеграція Монте-Карло «зближується повільно», тобто вам потрібно велика кількість зразків, щоб наблизитися до основної істини, особливо якщо функція має високі частоти.f(x)f(x)

З вибіркою важливості, замість того, щоб взяти N випадкових вибірок у діапазоні [0, 1], ви берете більше зразків у "важливих" областях які найбільше сприяють кінцевому результату. Однак, оскільки ви відхиляєте відбір вибірки до важливих областей функції, ці зразки повинні бути зважені меншими, щоб протиставити зміщення, і саме там PDF (функція щільності ймовірності) приходить разом. PDF повідомляє про ймовірність вибірки в заданій позиції і використовується для обчислення середньозваженого середнього рівня зразків шляхом ділення кожного зразка зі значенням PDF у кожній позиції вибірки.f(x)

З урахуванням важливості вибірки Cook-Torrance загальною практикою є розподіл зразків на основі нормальної функції розподілу NDF. Якщо NDF вже нормалізований, він може служити безпосередньо PDF-файлом, що зручно, оскільки він скасовує термін, що виходить з оцінки BRDF. Єдине , що вам потрібно зробити, це поширювати зразки позиції на основі PDF і оцінювати BRDF без члена NDF, тобто і обчислити середнє значення вибірки, помножене на суцільний кут домену, в який ви інтегруєтесь (наприклад, для півсфери).

f=FGπ(nωi)(nωo)
2π

Для NDF потрібно обчислити функцію накопичувального розподілу PDF для перетворення рівномірно розподіленої вибіркової позиції в зважену позицію вибірки в PDF. Для ізотропної NDF це спрощує функцію 1D через симетричність функції. Для отримання більш детальної інформації про виведення CDF ви можете ознайомитись із цією старою статтею Gems Gems .

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