problema con il campionamento dell'importanza
Stavo cercando di fare il campionamento dell'importanza sulla superficie lambertiana. All'inizio scelgo uniformemente la direzione dalla sfera unitaria.
vec3 direction = camera->genDirection();
...
direction = random_in_unit_sphere();
float cosine = dotp(direction,surfaceNormal);
/*
float dotp(float val){
val = dot(val);
if(val>0.0001f) return val;
else return 0.0001f;
}
*/
vec3 brdf_result = material->baseColor/Pi;//lambertian
vec3 pdf = 1.0f/(2.0f*Pi);
throughput = throughput * brdf_result * cosine / pdf;
Con 10 campioni per pixel, produce:

quindi scelgo una direzione casuale dall'emisfero unitario sopra la superficie
direction = random_in_unit_hemisphere(surfaceNormal);
float cosine = dotp(direction,surfaceNormal);
vec3 brdf_result = material->baseColor/Pi;
vec3 pdf = 1.0f/(1.0f*Pi);
throughput = throughput * brdf_result * cosine / pdf;
il risultato è molto simile, tranne per il minor rumore

e poi utilizzo il metodo di campionamento dell'importanza da (http://in1weekend.blogspot.com/)
class onb {
public:
vec3 operator[](int i)const { return axis[i]; }
vec3 u()const { return axis[0]; }
vec3 v()const { return axis[1]; }
vec3 w()const { return axis[2]; }
vec3 local(float a, float b, float c) { return a * u() + b * v() + c * w(); }
vec3 local(const vec3& a) { return a.x * u() + a.y * v() + a.z * w(); }
void buildFromNormal(const vec3& n) {
axis[2] = normalize(n);
vec3 a;
if (std::abs(w().x) > 0.9f)
a = vec3(0.0f, 1.0f, 0.0f);
else
a = vec3(1.0f, 0.0f, 0.0f);
axis[1] = normalize(cross(w(), a));
axis[0] = cross(w(), v());
}
private:
vec3 axis[3];
};
vec3 randCosDir() {
float r1 = randFloat01();
float r2 = randFloat01();
float z = sqrt(1.0f - r2);
float phi = 2.0f * Pi * r1;
float x = cos(phi) * 2.0f * sqrt(r2);
float y = sin(phi) * 2.0f * sqrt(r2);
return vec3(x, y, z);
}
,
onb uvw;
uvw.buildFromNormal(surfaceNormal);
direction = normalize(uvw.local(randCosDir()));
float cosine = dotp(direction,surfaceNormal);
vec3 brdf_result = material->baseColor/Pi;
vec3 pdf = dotp(uvw.w(), direction)/Pi;
throughput = throughput * brdf_result * cosine / pdf;
tuttavia il risultato è diverso:

Il colore base del muro è vec3 (0.8f, 0.8f, 0.8f) e il colore della luce della cupola è vec3 (1.0f, 1.0f, 1.0f). In alcuni tutorial l'elemento coseno è all'interno del lambertiano brdf, e alcuni sono nell'equazione di rendering e inhttp://in1weekend.blogspot.com/ "fine settimana uno" non c'è alcun elemento del coseno. Mi sono davvero incasinato con quei concetti. C'è qualcuno che mi aiuta? Grazie mille.
un altro rendering con baseColor = vec3 (1.0f, 1.0f, 1.0f) e dome color = vec3 (0.5f, 0.5f, 0.5f) (campionamento dell'importanza) il colore medio dell'immagine finale su tutti i pixel è vec3 (0.470884f , 0.470884f, 0.470884f).


Risposte
Ci sono alcuni bug nella tua matematica. Hai già riscontrato il problema con 2π e 4π nelle funzioni di campionamento dell'emisfero e della sfera, ma anche queste linee nel campionamento dell'emisfero coseno sono sbagliate:
float x = cos(phi) * 2.0f * sqrt(r2);
float y = sin(phi) * 2.0f * sqrt(r2);
Non dovrebbe esserci un fattore 2 in questi: questo sta distorcendo la distribuzione del coseno.
Anche,
vec3 pdf = dotp(uvw.w(), direction)/Pi;
throughput = throughput * brdf_result * cosine / pdf;
Questo non è sbagliato, ma non è necessario: pdf
cancella il cosine
, quindi sarebbe preferibile impostare pdf
solo 1 / π e lasciare il fattore del coseno disattivato. In effetti, questo annulla anche 1 / π in brdf_result
, quindi potresti tralasciare entrambi i fattori pi e sbarazzartene pdf
completamente.
Maggiori informazioni sul fattore coseno: l'intera idea di campionamento con un emisfero ponderato per il coseno è di evitare di dover avere il fattore coseno nel throughput del percorso. Fondamentalmente vuoi solo il coseno in un posto: o nella distribuzione del campionamento o nel throughput, ma non entrambi. È preferibile metterlo nella distribuzione del campionamento perché quindi la varianza nei campioni è inferiore (poiché non hanno il fattore coseno fortemente variabile nel loro throughput), quindi il rendering converge più velocemente.
Questa è anche una massima generale nel tracciamento del percorso: generalmente si desidera spostare i fattori dal throughput alla distribuzione dei raggi ogni volta che è possibile. Questa è l'idea del campionamento dell'importanza dei BRDF (sposta i fattori dal BRDF nella distribuzione dei raggi) e del campionamento della luce esplicita (sposta parti della distribuzione della luce in entrata nella distribuzione dei raggi) così come cose più avanzate come il campionamento a più importanza o la guida del percorso.
Ho appena scoperto che se uso pdf = 1.0f / (4.0f * Pi) nel campionamento della sfera unitaria o pdf = 1.0f / (2.0f * Pi) nel campionamento dell'emisfero unitario, il risultato è quasi lo stesso del campionamento dell'importanza (Ottengo lo stesso risultato anche impostando baseColor su vec3 (0.4f, 0.4f, 0.4f), la metà di vec3 (0.8f, 0.8f, 0.8f). E l'area della superficie di una sfera unitaria è solo 4.0 f * Pi (dimentico perché ho usato 2.0f * Pi prima). DEVO arrivare a due conclusioni:
1: l'importanza del campionamento è corretta!
2: sono troppo stupido !!!!!!