Tôi đang cố gắng triển khai BRDF microfacet trong raytracer của mình nhưng tôi đang gặp phải một số vấn đề. Rất nhiều bài báo và bài báo tôi đã đọc xác định thuật ngữ hình học một phần là một hàm của khung nhìn và một nửa vectơ: G1 (v, h). Tuy nhiên, khi thực hiện điều này tôi nhận được kết quả như sau:
(Hàng dưới cùng là điện môi có độ nhám 1.0 - 0.0, Hàng trên cùng là kim loại có độ nhám 1.0 - 0.0)
Có một điểm nổi bật kỳ lạ xung quanh các cạnh và một điểm cắt xung quanh nl == 0. Tôi thực sự không thể tìm ra nơi này đến từ đâu. Tôi đang sử dụng Unity làm tài liệu tham khảo để kiểm tra kết xuất của mình vì vậy tôi đã kiểm tra nguồn shader của họ để xem những gì họ sử dụng và từ những gì tôi có thể nói thuật ngữ hình học của họ không bị tham số bởi một nửa vector! Vì vậy, tôi đã thử cùng một mã nhưng được sử dụng để macro bề mặt bình thường thay vì một nửa vectơ và nhận được kết quả như sau:
Đối với mắt chưa được huấn luyện của tôi, điều này dường như gần với kết quả mong muốn. Nhưng tôi có cảm giác điều này không đúng? Phần lớn các bài báo tôi đọc sử dụng một nửa vectơ nhưng không phải tất cả chúng. Có một lý do cho sự khác biệt này?
Tôi sử dụng mã sau đây làm thuật ngữ hình học của mình:
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);
}
Và để tham khảo, đây là chức năng phân phối bình thường của tôi:
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);
}