射线追踪中的BRDF和球坐标


9

我开发了使用标准Phong / Blinn Phong照明模型的光线跟踪器。现在,我正在对其进行修改以支持基于物理的渲染,因此我正在实现各种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;
}

奥伦·纳亚(Oren Nayar)

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;
}

托伦斯麻雀

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

经过一番搜索,我发现了Oren-Nayar BRDF的这种实现

在上面的实现中,仅通过做arccos(wo.dotProduct(Normal))和arccos(wi.dotProduct(Normal))即可获得wi和wo的theta。这对我来说似乎很合理,因为我们可以将交点的法线用作球坐标系的天顶方向并进行计算。γ= cos(phi_wi-phi_wo)的计算在wi和wo所谓的“切线空间”上做了某种投影。假设此实现中的一切正确,我是否可以使用公式| View-Normal x(View.dotProduct(Normal))| 和| Light-普通x(Light.dotProduct(普通))| 获得phi坐标(而不是使用arctan(“ something”))?


有人可以帮助我吗?
Fabrizio Duroni 2015年

您能显示确切的代码片段,而不是整个仓库吗?
concept3d

看来这是关于
远古

我鼓励您在这里提问computergraphics.stackexchange.com
concept3d

完成@ concept3d。你可以在这里找到它computergraphics.stackexchange.com/questions/1799/...
法布里奇奥Duroni

Answers:


2

实际上,最好不要使用球坐标(或与此相关的任何角度)来实现BRDF,而应在笛卡​​尔坐标系中直接工作并使用向量之间的角度的余弦,这是单位向量之间的纯点积。这既更健壮又高效。

对于Oren-Nayar,您可能会认为必须使用角度(由于角度的最小值/最大值),但是您可以直接在笛卡尔空间中直接实现BRDF:https : //fgiesen.wordpress.com/2010/10/21 /请完成您的派生

对于Torrance-Sparrow或Cook-Torrance微面BRDF,您也不需要使用球形坐标。在这些BRDF中,角度以D / F / G术语和BRDF分母传递给三角函数(通常为余弦),因此您可以使用点乘积直线或三角恒等式而无需通过球坐标。


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 Pajama,谢谢您的回答,但我听不懂您的回答。我尝试澄清一下:如果我有交点和视点,则可以计算wi和wo。然后我可以使用法线作为我的天顶方向进行计算,但是我无法找到在与天顶正交的平面上找到方位角所需的其他轴。在上面的片段中,我只是简单地将世界坐标系中给出的wi和wo应用于球坐标的转换公式,但是我认为这不是计算theta和phi的正确方法。
Fabrizio Duroni 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.