BRDF и сферическая координата в трассировке лучей

9

Я разработал трассировщик лучей, который использует стандартную модель освещения фонг / блинн фонг. Сейчас я модифицирую его для поддержки физического рендеринга, поэтому я реализую различные модели BRDF. На данный момент я сосредоточен на модели Oren-Nayar и Torrance-Sparrow. Каждая из них основана на сферических координатах, используемых для выражения падающего и исходящего двух направлений света.

У меня вопрос: каким путем правильно преобразовать wi и wo из декартовой координаты в сферическую?

Я применяю стандартную формулу, указанную здесь https://en.wikipedia.org/wiki/Spherical_coordinate_system#Coordinate_system_conversions , но я не уверен , что я делаю правильно, потому что мой вектор не с хвостом в происхождении декартова система координат, но центрированная в точке пересечения луча с объектом.

Здесь вы можете найти мою текущую реализацию:

Может ли кто-нибудь помочь мне дать объяснение правильного способа преобразования вектора wi и wo из декартовой в сферическую координату?

ОБНОВИТЬ

Я копирую здесь соответствующую часть кода:

вычисление сферических координат

float Vector3D::sphericalTheta() const {

    float sphericalTheta = acosf(Utils::clamp(y, -1.f, 1.f));

    return sphericalTheta;
}

float Vector3D::sphericalPhi() const {

    float phi = atan2f(z, x);

    return (phi < 0.f) ? phi + 2.f * M_PI : phi;
}

Орен Найяр

OrenNayar::OrenNayar(Spectrum<constant::spectrumSamples> reflectanceSpectrum, float degree) : reflectanceSpectrum{reflectanceSpectrum} {

    float sigma = Utils::degreeToRadian(degree);
    float sigmaPowerTwo = sigma * sigma;

    A = 1.0f - (sigmaPowerTwo / 2.0f * (sigmaPowerTwo + 0.33f));
    B = 0.45f * sigmaPowerTwo / (sigmaPowerTwo + 0.09f);
};

Spectrum<constant::spectrumSamples> OrenNayar::f(const Vector3D& wi, const Vector3D& wo, const Intersection* intersection) const {

    float thetaI = wi.sphericalTheta();
    float phiI = wi.sphericalPhi();

    float thetaO = wo.sphericalTheta();
    float phiO = wo.sphericalPhi();

    float alpha = std::fmaxf(thetaI, thetaO);
    float beta = std::fminf(thetaI, thetaO);

    Spectrum<constant::spectrumSamples> orenNayar = reflectanceSpectrum * constant::inversePi * (A + B * std::fmaxf(0, cosf(phiI - phiO) * sinf(alpha) * tanf(beta)));

    return orenNayar;
}

Торранс-Sparrow

float TorranceSparrow::G(const Vector3D& wi, const Vector3D& wo, const Vector3D& wh, const Intersection* intersection) const {

    Vector3D normal = intersection->normal;
    normal.normalize();

    float normalDotWh = fabsf(normal.dot(wh));
    float normalDotWo = fabsf(normal.dot(wo));
    float normalDotWi = fabsf(normal.dot(wi));
    float woDotWh = fabsf(wo.dot(wh));

    float G = fminf(1.0f, std::fminf((2.0f * normalDotWh * normalDotWo)/woDotWh, (2.0f * normalDotWh * normalDotWi)/woDotWh));

    return G;
}

float TorranceSparrow::D(const Vector3D& wh, const Intersection* intersection) const {

    Vector3D normal = intersection->normal;
    normal.normalize();

    float cosThetaH = fabsf(wh.dot(normal));

    float Dd = (exponent + 2) * constant::inverseTwoPi * powf(cosThetaH, exponent);

    return Dd;
}

Spectrum<constant::spectrumSamples> TorranceSparrow::f(const Vector3D& wi, const Vector3D& wo, const Intersection* intersection) const {

    Vector3D normal = intersection->normal;
    normal.normalize();

    float thetaI = wi.sphericalTheta();
    float thetaO = wo.sphericalTheta();

    float cosThetaO = fabsf(cosf(thetaO));
    float cosThetaI = fabsf(cosf(thetaI));

    if(cosThetaI == 0 || cosThetaO == 0) {

        return reflectanceSpectrum * 0.0f;
    }

    Vector3D wh = (wi + wo);
    wh.normalize();

    float cosThetaH = wi.dot(wh);

    float F = Fresnel::dieletricFresnel(cosThetaH, refractiveIndex);
    float g = G(wi, wo, wh, intersection);
    float d = D(wh, intersection);

    printf("f %f g %f d %f \n", F, g, d);
    printf("result %f \n", ((d * g * F) / (4.0f * cosThetaI * cosThetaO)));

    Spectrum<constant::spectrumSamples> torranceSparrow = reflectanceSpectrum * ((d * g * F) / (4.0f * cosThetaI * cosThetaO));

    return torranceSparrow;
}

ОБНОВЛЕНИЕ 2

После некоторых поисков я нашел эту реализацию Орен-Наярской БРДФ .

В приведенной выше реализации тэта для wi и wo получается просто с помощью arccos (wo.dotProduct (Normal)) и arccos (wi.dotProduct (Normal)). Это кажется мне разумным, так как мы можем использовать нормаль точки пересечения в качестве направления зенита для нашей сферической системы координат и выполнить расчет. Вычисление gamma = cos (phi_wi - phi_wo) делает своего рода проекцию wi и wo на то, что называется «касательным пространством». Предполагая, что в этой реализации все правильно, могу ли я просто использовать формулы | View - Normal x (View.dotProduct (Normal)) | и | Light - Normal x (Light.dotProduct (Normal)) | получить координату фи (вместо использования arctan ("что-то"))?

Фабрицио Дурони
источник
Кто-нибудь может мне помочь?
Фабрицио Дурони
Можете ли вы показать точный фрагмент кода, а не весь репо?
concept3d
Похоже, что это один из самых загадочных вопросов о трассировке лучей всех времен: D
Фабрицио Дурони
Я призываю вас спросить здесь computergraphics.stackexchange.com
concept3d
Готово @ concept3d. Вы можете найти его здесь computergraphics.stackexchange.com/questions/1799/…
Фабрицио Дурони

Ответы:

2

На самом деле лучше не использовать сферические координаты (или любые другие углы) для реализации BRDF, а работать прямо в декартовой системе координат и использовать косинус угла между векторами, который, как вы знаете, является простым точечным произведением между единичными векторами. Это более надежно и эффективно.

Для Oren-Nayar вы можете подумать, что вам нужно использовать углы (из-за мин / макс углов), но вы можете просто реализовать BRDF прямо в декартовом пространстве: https://fgiesen.wordpress.com/2010/10/21 / отделка-ваша-деривация-пожалуйста

Для микрообъектов Torrance-Sparrow или Cook-Torrance BRDF вам также не нужно использовать сферические координаты. В этих BRDF угол передается тригонометрической (обычно косинусной) функции в терминах D / F / G и знаменателе BRDF, так что вы можете использовать прямые или тригонометрические тождества точечного произведения без прохождения через сферические координаты.

JarkkoL
источник
1

Вы можете указать систему координат, заданную нормалью N и другим вектором. Мы выберем Wi. Таким образом, любой вектор, имеющий направление wi при проецировании на касательную плоскость, будет иметь азимут 0

Сначала мы проецируем wi на касательную плоскость: (при условии, что wi уже нормализовано)

wit = normalize(wi - N * dot(wi, N))

Теперь мы можем сделать то же самое с wo:

wot = normalize(wo - N * dot(wo, N))

Теперь остроумие и wot лежат как на плоскости, которая ортогональна N, так и касается точки пересечения.

Теперь мы можем вычислить угол между ними:

azimuth = arcos ( dot(wit, wot) )

Что на самом деле является азимутом wot по отношению к остроумию при проекции на касательную плоскость.

Гато
источник
0

Если вы знаете точку пересечения и точку происхождения, разве это не будет вопросом вычитания одного из другого, чтобы вы получили результат, как если бы он был из источника?

Если вы не верите результату и хотите пройти долгий путь, вы также можете получить преобразование вращения, чтобы перейти из одной точки в другую через матрицу LookAt, а затем разложить его, чтобы получить компонент вращения. Вы также можете получить кватернион из него, если хотите.

Результаты равны. Доказательство немного длинное, но не сложное и оставлено на усмотрение читателя.

Панда Пижама
источник
Привет, @Panda. Пижама спасибо за твой ответ, но я не могу понять твой ответ. Я пытаюсь уточнить: если бы у меня была точка пересечения и точка зрения, я мог бы вычислить wi и wo. Тогда я могу использовать нормаль в качестве моего зенитного направления для вычисления, но я не могу найти другую ось, необходимую для нахождения азимутального угла на плоскости, ортогональной к зениту. В приведенном выше фрагменте я просто применил формулы преобразования для сферических координат к wi и wo, заданным в мировой системе координат, но я не думаю, что это правильный способ вычисления тэты и фи.
Фабрицио Дурони