Saya mengembangkan pelacak sinar yang menggunakan model pencahayaan phong / blinn phong standar. Sekarang saya memodifikasinya untuk mendukung rendering berbasis fisik, jadi saya mengimplementasikan berbagai model BRDF. Saat ini saya sedang fokus pada model Oren-Nayar dan Torrance-Sparrow. Masing-masing didasarkan pada koordinat bola yang digunakan untuk mengekspresikan kejadian dengan arah cahaya keluar.
Pertanyaan saya adalah: jalan mana yang benar mengkonversi wi dan wo dari koordinat kartesius ke koordinat bola?
Saya menerapkan rumus standar yang dilaporkan di sini https://en.wikipedia.org/wiki/Spherical_coordinate_system#Coordinate_system_conversions tapi saya tidak yakin saya melakukan hal yang benar, karena vektor saya tidak dengan ekor pada asal-usul sistem koordinat kartesius, tetapi berpusat pada titik persimpangan sinar dengan objek.
Di sini Anda dapat menemukan implementasi saya saat ini:
https://github.com/chicio/Multispectral-Ray-tracing/tree/brdf/RayTracing/RayTracer/Objects/BRDF
https://github.com/chicio/Multispectral-Ray-tracing/blob/brdf/RayTracing/RayTracer/Math/Vector3D.cpp
Adakah yang bisa membantu saya memberikan penjelasan tentang cara yang benar untuk mengkonversi vektor wi dan wo dari cartesian ke koordinat bola?
MEMPERBARUI
Saya salin di sini bagian kode yang relevan:
perhitungan koordinat bola
float Vector3D::sphericalTheta() const {
float sphericalTheta = acosf(Utils::clamp(y, -1.f, 1.f));
return sphericalTheta;
}
float Vector3D::sphericalPhi() const {
float phi = atan2f(z, x);
return (phi < 0.f) ? phi + 2.f * M_PI : phi;
}
Oren Nayar
OrenNayar::OrenNayar(Spectrum<constant::spectrumSamples> reflectanceSpectrum, float degree) : reflectanceSpectrum{reflectanceSpectrum} {
float sigma = Utils::degreeToRadian(degree);
float sigmaPowerTwo = sigma * sigma;
A = 1.0f - (sigmaPowerTwo / 2.0f * (sigmaPowerTwo + 0.33f));
B = 0.45f * sigmaPowerTwo / (sigmaPowerTwo + 0.09f);
};
Spectrum<constant::spectrumSamples> OrenNayar::f(const Vector3D& wi, const Vector3D& wo, const Intersection* intersection) const {
float thetaI = wi.sphericalTheta();
float phiI = wi.sphericalPhi();
float thetaO = wo.sphericalTheta();
float phiO = wo.sphericalPhi();
float alpha = std::fmaxf(thetaI, thetaO);
float beta = std::fminf(thetaI, thetaO);
Spectrum<constant::spectrumSamples> orenNayar = reflectanceSpectrum * constant::inversePi * (A + B * std::fmaxf(0, cosf(phiI - phiO) * sinf(alpha) * tanf(beta)));
return orenNayar;
}
Torrance-Sparrow
float TorranceSparrow::G(const Vector3D& wi, const Vector3D& wo, const Vector3D& wh, const Intersection* intersection) const {
Vector3D normal = intersection->normal;
normal.normalize();
float normalDotWh = fabsf(normal.dot(wh));
float normalDotWo = fabsf(normal.dot(wo));
float normalDotWi = fabsf(normal.dot(wi));
float woDotWh = fabsf(wo.dot(wh));
float G = fminf(1.0f, std::fminf((2.0f * normalDotWh * normalDotWo)/woDotWh, (2.0f * normalDotWh * normalDotWi)/woDotWh));
return G;
}
float TorranceSparrow::D(const Vector3D& wh, const Intersection* intersection) const {
Vector3D normal = intersection->normal;
normal.normalize();
float cosThetaH = fabsf(wh.dot(normal));
float Dd = (exponent + 2) * constant::inverseTwoPi * powf(cosThetaH, exponent);
return Dd;
}
Spectrum<constant::spectrumSamples> TorranceSparrow::f(const Vector3D& wi, const Vector3D& wo, const Intersection* intersection) const {
Vector3D normal = intersection->normal;
normal.normalize();
float thetaI = wi.sphericalTheta();
float thetaO = wo.sphericalTheta();
float cosThetaO = fabsf(cosf(thetaO));
float cosThetaI = fabsf(cosf(thetaI));
if(cosThetaI == 0 || cosThetaO == 0) {
return reflectanceSpectrum * 0.0f;
}
Vector3D wh = (wi + wo);
wh.normalize();
float cosThetaH = wi.dot(wh);
float F = Fresnel::dieletricFresnel(cosThetaH, refractiveIndex);
float g = G(wi, wo, wh, intersection);
float d = D(wh, intersection);
printf("f %f g %f d %f \n", F, g, d);
printf("result %f \n", ((d * g * F) / (4.0f * cosThetaI * cosThetaO)));
Spectrum<constant::spectrumSamples> torranceSparrow = reflectanceSpectrum * ((d * g * F) / (4.0f * cosThetaI * cosThetaO));
return torranceSparrow;
}
PEMBARUAN 2
Setelah beberapa pencarian saya menemukan implementasi BRDF Oren-Nayar ini .
Dalam implementasi di atas theta untuk wi dan wo diperoleh cukup melakukan arccos (wo.dotProduct (Normal)) dan arccos (wi.dotProduct (Normal)). Ini masuk akal bagi saya, karena kita dapat menggunakan titik persimpangan normal sebagai arah puncak untuk sistem koordinat bola kita dan melakukan perhitungan. Perhitungan gamma = cos (phi_wi - phi_wo) melakukan semacam proyeksi wi dan wo pada apa yang disebutnya "ruang singgung". Dengan asumsi semuanya sudah benar dalam implementasi ini, dapatkah saya menggunakan rumus | View - Normal x (View.dotProduct (Normal)) | dan | Cahaya - Normal x (Light.dotProduct (Normal)) | untuk mendapatkan koordinat phi (alih-alih menggunakan arctan ("sesuatu"))?
sumber
Jawaban:
Sebenarnya lebih baik tidak menggunakan koordinat bola (atau sudut apa pun dalam hal ini) untuk mengimplementasikan BRDF, tetapi bekerja langsung dalam sistem koordinat Cartesian dan menggunakan cosinus sudut antara vektor, yang merupakan produk titik polos antara vektor satuan seperti yang Anda ketahui. Ini lebih kuat dan efisien.
Untuk Oren-Nayar Anda mungkin berpikir Anda harus menggunakan sudut (karena min / maks dari sudut), tetapi Anda dapat menerapkan BRDF langsung di ruang Cartesian: https://fgiesen.wordpress.com/2010/10/21 / selesaikan-derivasi Anda-tolong
Untuk microfacet Torrance-Sparrow atau Cook-Torrance, Anda tidak perlu menggunakan koordinat bola juga. Dalam BRDF ini, sudut diteruskan ke fungsi trigonometrik (biasanya kosinus) dalam istilah D / F / G & penyebut BRDF, sehingga Anda dapat menggunakan identitas titik produk lurus atau trigonometrik tanpa melalui koordinat bola.
sumber
Anda dapat menentukan sistem koordinat yang diberikan N normal dan vektor lainnya. Kami akan memilih wi. Jadi setiap vektor yang memiliki arah yang sama dengan wi ketika diproyeksikan ke bidang garis singgung akan memiliki azimuth 0
Pertama, kami memproyeksikan wi pada bidang tangen: (dengan asumsi wi sudah dinormalisasi)
sekarang, kita bisa melakukan hal yang sama dengan wo:
Sekarang, kecerdasan dan kebohongan terletak pada bidang yang ortogonal ke N, dan bersinggungan dengan titik persimpangan.
Kita dapat menghitung sudut antara keduanya sekarang:
Yang benar-benar azimuth wot sehubungan dengan kecerdasan ketika diproyeksikan pada bidang singgung.
sumber
Jika Anda tahu titik persimpangan, dan titik asal, bukankah itu hanya soal mengurangi satu dari yang lain sehingga Anda mendapatkan hasilnya seolah-olah itu dari titik asal?
Jika Anda tidak percaya hasilnya, dan ingin sampai di sana melalui jalan panjang, Anda juga bisa mendapatkan transformasi rotasi untuk berpindah dari satu titik ke titik lain melalui matriks LookAt, dan kemudian menguraikannya untuk mendapatkan komponen rotasi. Anda juga bisa mendapatkan angka empat dari itu jika Anda mau.
Hasilnya sama. Buktinya agak panjang, tapi tidak rumit, dan diserahkan kepada pembaca.
sumber