GGX 기하학 용어의 올바른 형식


9

raytracer에서 microfacet 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);
}

답변:


5

TL; DR : 공식이 잘못되었습니다.G1


혼동을 피하기 위해 BRDF의 등방성 버전, Smith 미세면 모델 (V 공동 모델과 반대) 및 GGX 미세면 분포를 가정합니다.

Heitz 2014 에 따르면 마스킹 / 섀도 잉 용어 은G1

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

및 항 월터 2,007 , 화학식은

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

여기서 은 미세면 법선 방향 (하프 벡터), 는 주 (기하학적) 법선 방향 (normal), 는 들어 오거나 나가는 방향, 는 등방성입니다 거칠기 매개 변수 및 는 양의 특성 함수 또는 헤비 사이드 단계 함수 ( , 그렇지 않으면 0)입니다.ωmωgωvαχ+(a)a>0

알다시피, 반 벡터 은 기하학적 구성이 금지 된 경우 이 0 인지 확인하는 데만 사용됩니다 . 보다 정확하게는, 미세 표면의 후면이 거시 표면의 앞면 의 방향에서 절대로 보이지 않도록 하고 그 반대도 마찬가지입니다. 호출 코드가이를 보증하면이 매개 변수를 생략 할 수 있습니다. 그것이 아마도 Unity에서 그렇게 한 이유 일 것입니다.ω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 수학은 물론 구체적 형상을 명시 때문에 반 벡터에 대해 혼란스러워했다) 뷰, 라이트 및 반 벡터에 따라 기능. 슬라이드에 오류가 있습니까?
Erwin

@ Erwin, 이제 수식 자체를 제공 했으므로 훨씬 명확합니다. 다음에 처음 시작할 때 도움이됩니다. 예, 두 버전 (광산 및 사용자)은 동일하지만 사인 또는 탄젠트 함수를 계산하기 위해 중간 벡터를 사용하지 않습니다. 그것은 사용 보다는 당신이 당신의 구현에 그랬던 것처럼 - 실수 것 같다. 새로운 구현에서도 같은 실수를 한 것으로 보입니다. nvhv
ivokabel

새로운 구현에 N dot V를 사용했는데 게시 한 두 번째 이미지와 동일한 결과를 얻었습니다. 그러나 PBS 코스 슬라이드에 왜 하프 웨이 벡터가 사용되어야하는지 명시되어 있지 않습니다 ( blog.selfshadow.com/publications/s2015-shading-course/hoffman/… , Slide 88 참조).
Erwin

대신 를 사용하는 것이 문제라는 것을 올바르게 이해하고 있습니까? 에서 중간 벡터의 사용과 관련하여 : 실제로 게시 한 두 버전 모두에서 사용됩니다 (LaTeX 수식을 만들 때 실수를하고 지오메트리 법선을 첫 번째 수식에 작성했습니다. 곧 수정하겠습니다). 요점은 중간 벡터가 코사인 값을 계산하는 데 사용되지 않는다는 것입니다 (즉, 사용 되지 않음 ). hvnvG1hv
ivokabel

예, 그게 문제였습니다. 그러나 내 주요 질문은 : 하프 벡터가 함수 정의에 나타나기 때문에 사용되는 것은 무엇입니까? 내가 이해하는 한, H dot V가 양수인지 확인에만 사용됩니다. 답을 쓸 시간을 내 주셔서 감사합니다.
Erwin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.