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"))?