ฉันกำลังพยายามนำ BRDF ของ microfacet ไปใช้ใน raytracer ของฉัน แต่ฉันพบปัญหาบางอย่าง เอกสารและบทความจำนวนมากที่ฉันได้อ่านให้นิยามคำเรขาคณิตบางส่วนเป็นฟังก์ชันของมุมมองและเวกเตอร์ครึ่งหนึ่ง: G1 (v, h) อย่างไรก็ตามเมื่อใช้งานนี้ฉันได้รับผลลัพธ์ดังต่อไปนี้:
(แถวล่างเป็นฉนวนความหยาบ 1.0 - 0.0, แถวบนสุดเป็นโลหะที่มีความหยาบ 1.0 - 0.0)
มีไฮไลท์แปลก ๆ อยู่รอบ ๆ ขอบและตัดรอบ ๆ nl == 0 ฉันไม่สามารถเข้าใจได้ว่ามันมาจากไหน ฉันใช้ Unity เป็นข้อมูลอ้างอิงในการตรวจสอบการแสดงผลของฉันดังนั้นฉันจึงตรวจสอบแหล่งที่มาของ shader เพื่อดูว่าพวกเขาใช้อะไรและจากสิ่งที่ฉันสามารถบอกได้ว่าเทอมเรขาคณิตของพวกเขานั้นไม่ได้ถูกพาราเมท ดังนั้นฉันจึงลองใช้รหัสเดียวกัน แต่ใช้กับพื้นผิวมาโครปกติแทนที่จะเป็นครึ่งเวคเตอร์และได้ผลลัพธ์ดังนี้
สำหรับดวงตาที่ไม่ผ่านการฝึกฝนของฉันสิ่งนี้ดูเหมือนจะใกล้เคียงกับผลลัพธ์ที่ต้องการ แต่ฉันมีความรู้สึกว่ามันไม่ถูกต้อง? บทความที่ฉันอ่านส่วนใหญ่ใช้เวกเตอร์ครึ่งตัว แต่ไม่ใช่ทั้งหมด มีเหตุผลสำหรับความแตกต่างนี้หรือไม่?
ฉันใช้รหัสต่อไปนี้เป็นคำเรขาคณิตของฉัน:
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);
}