problem z próbkowaniem ważności
Próbowałem pobierać próbki na lambertowskiej powierzchni, najpierw jednakowo wybieram kierunek ze sfery jednostkowej.
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;
Przy 10 próbkach na piksel daje:
następnie wybieram losowy kierunek z półkuli jednostkowej nad powierzchnią
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;
wynik jest bardzo podobny, z wyjątkiem mniejszego hałasu
a następnie używam metody próbkowania ważności z (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;
jednak wynik jest inny:
Podstawowy kolor ściany to vec3 (0,8f, 0,8f, 0,8f), a kolor światła kopuły to vec3 (1,0f, 1,0f, 1,0f). W niektórych samouczkach element cosinus znajduje się wewnątrz lambertowskiego brdf, a niektóre znajdują się w równaniu renderowania i whttp://in1weekend.blogspot.com/ „weekend one” w ogóle nie ma pozycji cosinus. Naprawdę mam problemy z tymi koncepcjami. Czy ktoś mi pomoże? wielkie dzięki.
inny rendering z baseColor = vec3 (1.0f, 1.0f, 1.0f) i kolor kopuły = vec3 (0.5f, 0.5f, 0.5f) (próbkowanie ważności) średni kolor końcowego obrazu we wszystkich pikselach to vec3 (0,470884f , 0,470884f, 0,470884f).
Odpowiedzi
W twojej matematyce jest kilka błędów. Znalazłeś już problem z funkcjami próbkowania 2π i 4π w funkcji próbkowania półkuli i sfery, ale także te linie w próbkowaniu półkuli cosinusowej są błędne:
float x = cos(phi) * 2.0f * sqrt(r2);
float y = sin(phi) * 2.0f * sqrt(r2);
Nie powinno w nich być współczynnika 2: to zniekształca rozkład cosinusów.
Również,
vec3 pdf = dotp(uvw.w(), direction)/Pi;
throughput = throughput * brdf_result * cosine / pdf;
To nie jest złe, ale jest niepotrzebne: pdfanuluje wartość cosine, więc byłoby lepiej ustawić pdftylko 1 / π i pozostawić współczynnik cosinus wyłączony. W rzeczywistości to również anuluje 1 / π w brdf_result, więc możesz pominąć oba te czynniki pi i pdfcałkowicie się ich pozbyć .
Więcej o współczynniku cosinus: cała idea próbkowania z półkulą ważoną cosinusem polega na tym, aby uniknąć konieczności stosowania współczynnika cosinus w przepustowości ścieżki. Zasadniczo chcesz, aby cosinus znajdował się w jednym miejscu: albo w rozkładzie próbkowania, albo w przepustowości, ale nie w obu. Lepiej jest umieścić go w rozkładzie próbkowania, ponieważ wtedy wariancja w próbkach jest mniejsza (ponieważ nie mają one silnie zmieniającego się współczynnika cosinus w ich przepustowości), więc renderowanie zbiega się szybciej.
Jest to również ogólna maksyma w śledzeniu ścieżki: generalnie chcesz przenieść czynniki z przepustowości do dystrybucji promieni, kiedy tylko jest to możliwe. To jest idea ważnego próbkowania BRDF (przenoszenie czynników z BRDF do rozkładu promieni) i jawnego próbkowania światła (przenoszenie części przychodzącego światła do rozkładu promienia), a także bardziej zaawansowanych rzeczy, takich jak próbkowanie wielu ważnych elementów lub prowadzenie ścieżki.
Właśnie stwierdziłem, że jeśli użyję pdf = 1,0f / (4,0f * Pi) w próbkowaniu jednostkowej sfery lub pdf = 1,0f / (2,0f * Pi) w próbkowaniu z półkuli jednostkowej, wynik jest prawie taki sam, jak próbkowanie ważności (Otrzymuję ten sam wynik, gdy ustawię baseColor na vec3 (0.4f, 0.4f, 0.4f), połowę vec3 (0.8f, 0.8f, 0.8f). A pole powierzchni kuli jednostkowej wynosi tylko 4,0 f * Pi (zapomniałem dlaczego wcześniej używam 2.0f * Pi) MUSZĘ dojść do dwóch wniosków:
1: próbkowanie ważności jest prawidłowe!
2: Jestem za głupi !!!!!!