GGX几何术语的正确形式


9

我正在尝试在raytracer中实现微面BRDF,但是遇到了一些问题。我读过的许多论文和文章都将局部几何术语定义为视图和半矢量的函数:G1(v,h)。但是,实现此目标时,我得到以下结果:

使用半向量的GGX几何项

(最下面一行是粗糙度为1.0-0.0的电介质,最上面一行是粗糙度为1.0-0.0的金属电介质)

边缘周围有一个怪异的高光,nl == 0附近有一个截止。我使用Unity作为参考来检查我的渲染,因此我检查了它们的着色器源,以查看它们的用途,并从中可以看出它们的几何项根本没有被半向量参数化!因此,我尝试了相同的代码,但使用了宏观表面法线而不是半向量,并得到以下结果:

GGX几何术语,使用宏观曲面法线

在我未经训练的眼睛看来,这似乎更接近预期的结果。但是我有感觉这是不正确的?我阅读的大多数文章都使用半向量,但不是全部。是否有这种差异的原因?

我将以下代码用作几何术语:

float RayTracer::GeometryGGX(const Vector3& v, const Vector3& l, const Vector3& n, const Vector3& h, float a)
{
    return G1GGX(v, h, a) * G1GGX(l, h, a);
}

float RayTracer::G1GGX(const Vector3& v, const Vector3& h, float a)
{
    float NoV = Util::Clamp01(cml::dot(v, h));
    float a2 = a * a;

    return (2.0f * NoV) / std::max(NoV + sqrt(a2 + (1.0f - a2) * NoV * NoV), 1e-7f);
}

供参考,这是我的正态分布函数:

float RayTracer::DistributionGGX(const Vector3& n, const Vector3& h, float alpha)
{
    float alpha2 = alpha * alpha;
    float NoH = Util::Clamp01(cml::dot(n, h));
    float denom = (NoH * NoH * (alpha2 - 1.0f)) + 1.0f;
    return alpha2 / std::max((float)PI * denom * denom, 1e-7f);
}

Answers:


5

G1


为了避免混淆,我假设使用BRDF的各向同性版本,Smith微面模型(与V腔模型相对)和GGX微面分布。

G1

χ+(ωvωm)21+1+αo2tan2θv

根据Walter 2007,公式为

χ+(ωvωgωvωm)21+1+α2tan2θv

ωmωgωvαχ+(a)a>0

ωmG1ωv

ωv

G1

float SmithMaskingFunctionGgx(
    const Vec3f &aDir,  // the direction to compute masking for (either incoming or outgoing)
    const Vec3f &aMicrofacetNormal,
    const float  aRoughnessAlpha)
{
    PG3_ASSERT_VEC3F_NORMALIZED(aDir);
    PG3_ASSERT_VEC3F_NORMALIZED(aMicrofacetNormal);
    PG3_ASSERT_FLOAT_NONNEGATIVE(aRoughnessAlpha);

    if (aMicrofacetNormal.z <= 0)
        return 0.0f;

    const float cosThetaVM = Dot(aDir, aMicrofacetNormal);
    if ((aDir.z * cosThetaVM) < 0.0f)
        return 0.0f; // up direction is below microfacet or vice versa

    const float roughnessAlphaSqr = aRoughnessAlpha * aRoughnessAlpha;
    const float tanThetaSqr = Geom::TanThetaSqr(aDir);
    const float root = std::sqrt(1.0f + roughnessAlphaSqr * tanThetaSqr);

    const float result = 2.0f / (1.0f + root);

    PG3_ASSERT_FLOAT_IN_RANGE(result, 0.0f, 1.0f);

    return result;
}

谢谢您的回复。我已经实现了您提供的公式,并且得到的结果与我自己的公式相同(使用宏观曲面法线时)。因此,看来这只是一种不同的形式(我来自:graphicrants.blogspot.nl/2013/08/specular-brdf-reference.html)我对半向量感到困惑,因为SIGGRAPH 2015 PBS数学课程专门说明了几何形状函数取决于视图,光和半向量。所以这是幻灯片中的错误?
欧文

nvhv

我在新实现中确实使用了N点V,这与我发布的第二张图片的结果相同。但是我仍然不清楚为什么PBS课程幻灯片会指出应使用中途向量(请参阅:blog.selfshadow.com/publications/s2015-shading-course/hoffman/…,幻灯片88)。
欧文

hvnvG1hv

是的,这就是问题所在。但是我的主要问题是:半向量用于什么,因为它出现在函数定义中。据我所知,它仅用于检查H点V是否为正。感谢您抽出宝贵的时间写答案。
欧文(Erwin)2013年
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.