Forma correta do termo de geometria GGX

9

Estou tentando implementar um BRDF de microfacet no meu raytracer, mas estou com alguns problemas. Muitos artigos e artigos que li definem o termo de geometria parcial como uma função da vista e dos meio vetores: G1 (v, h). No entanto, ao implementar isso, obtive o seguinte resultado:

Termo de geometria GGX usando o meio vetor

(A linha inferior é dielétrica com rugosidade 1.0 - 0.0, A linha superior é metálica com rugosidade 1.0 - 0.0)

Há um destaque estranho nas bordas e um corte em torno de nl == 0. Eu realmente não conseguia descobrir de onde isso vem. Estou usando o Unity como referência para verificar minhas renderizações, então verifiquei sua fonte de sombreador para ver o que eles usam e, pelo que posso dizer, o termo geometria não é parametrizado pelo meio vetor! Então, tentei o mesmo código, mas costumava macro superfície normal em vez do meio vetor e obteve o seguinte resultado:

Termo da geometria GGX usando a superfície normal da macro

Para meus olhos destreinados, isso parece muito mais próximo do resultado desejado. Mas tenho a sensação de que isso não está correto? A maioria dos artigos que li usa o meio vetor, mas não todos. Existe uma razão para essa diferença?

Eu uso o seguinte código como meu termo de geometria:

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

E, para referência, esta é minha função de distribuição normal:

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);
}
Erwin
fonte

Respostas:

5

G1


Apenas para evitar confusão, estou assumindo a versão isotrópica do BRDF, o modelo de microfacet Smith (ao contrário do modelo de cavidade em V) e a distribuição de microfacet GGX.

G1

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

e de acordo com Walter 2007 , a fórmula é

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

Onde é a direção normal do microfacet (vetor intermediário), é a direção normal principal (geométrica) (normal), é a direção de entrada ou saída, é a isotrópica parâmetro de rugosidade e é a função característica positiva ou a função Heaviside step (igual a um se e zero em caso contrário). ω g ω v α χ + ( a ) a > 0ω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;
}
ivokabel
fonte
Obrigado por sua resposta. Implementei a fórmula que você forneceu e obtive resultados idênticos aos meus (ao usar a macrosuperfície normal). Parece que é apenas uma forma diferente (entendi: graphicrants.blogspot.nl/2013/08/specular-brdf-reference.html ) Fiquei confuso com o meio vetor porque o curso de matemática SIGGRAPH 2015 PBS especifica especificamente a geometria função dependente da visão, luz e meios vetores. Então isso é um erro nos slides?
Erwin
nvhv
Eu usei o N ponto V na minha nova implementação, que me deu resultados idênticos à segunda imagem que eu publiquei. Mas ainda não estou claro por que os slides do curso PBS afirmam que o vetor intermediário deve ser usado (Veja: blog.selfshadow.com/publications/s2015-shading-course/hoffman/… , Slide 88).
Erwin
hvnvG1hv
Sim, esse era o problema. Mas minha pergunta principal era: para que serve o meio vetor, uma vez que aparece na definição da função. Pelo que entendi agora, só é usado na verificação se o ponto H é positivo. Obrigado por dedicar um tempo para escrever as respostas.
Erwin