I'm trying to implement the multiple importance sampling path tracing, the MIS path tracing uses the MIS to combine the direct light sampling and brdf sampling to evaluate the direct lighting.
The direct lighting estimator part (the intersection point on the object is pos):
- sample a point P on the light plane and get the light intensity Li
- get dir = P - pos, wi = normalize(dir), dist2 = dot(dir, dir), light_pdf = 1 / area / light_cnt
- get the light_pdf wrt solid angle ==> light_pdf_sa = light_pdf * dist2 / dot(light_normal, -wi)
- get the brdf_pdf wrt to wi, wo(the incident direction) and surface intersection info rec
- calculate the
direct lighting part = eval(wi, wo, rec) * Li * dot(wi, n) / light_pdf_sa * powerhueristic(1., light_pdf_sa, 1., brdf_pdf)
The brdf estimator part:
- sample an out direction wi wrt the wo and the material info
- shoot the shadow ray from pos with the direction wi and intersect with the scene
- if the shadow ray hit a light, then get the light color Li, light_pdf = 1/area/light_cnt, and the light_normal, dist2 (the square of the hit point and the surface point) go to 4
- get the light_pdf wrt solid angle ==> light_pdf_sa = light_pdf * dist2 / dot(light_normal, -wi)
- get the brdf_pdf wrt to wi, wo(the incident direction) and surface intersection info rec
- calculate the
brdf part = eval(wi, wo, rec) * Li * dot(wi, n) / brdf_pdf * powerhueristic(1., brdf_pdf, 1., light_pdf_sa)
Finally, add the direct lighting part and the brdf part together
Here is the MIS direct lighting code:
bool direct_lighting_MIS(out vec3 wi, out vec3 weight, out vec3 L, const in vec3 wo, const in record rec){
vec3 n = rec.out_normal;
vec3 pt_on_obj = rec.pos;
vec3 pt_on_lit;
vec3 lit_normal;
float lit_pdf;
vec3 Li;
sample_from_light(pt_on_lit, lit_normal, lit_pdf, Li);
vec3 dir = pt_on_lit - pt_on_obj;
float dist = length(dir);
wi = normalize(dir);
L = vec3(0);
if(is_visible(pt_on_obj, dir, n) && lit_pdf > 0.){
float brdf_pdf = get_pdf(wi, wo, rec);
float lit_pdf_sa = lit_pdf * dist * dist / dot(lit_normal, -wi);
L += eval(wi, wo, rec) * Li * dot(n, wi) / lit_pdf_sa *
PowerHeuristic(1., lit_pdf_sa, 1., brdf_pdf);
}
if(sample_brdf(wi, weight, wo, rec)){
float brdf_pdf = get_pdf(wi, wo, rec);
ray r_t = ray(rec.pos, wi);
record rec_t;
bool valid;
hit(r_t, rec_t, valid);
float dist = length(at(r_t, rec_t.t) - r_t.A);
if(valid){
for(int i = 0; i < light_cnts; i ++){
if(rec_t.obj_id == lights[i] && !rec_t.is_back_face){
lit_pdf = light_pdf(lights[i]);
Li = light_intensity(rec_t.mat_id);
float lit_pdf_sa = lit_pdf * dist * dist / dot(rec_t.normal, -wi);
//float brdf_pdf_area = brdf_pdf * dot(rec_t.normal, -wi) / (dist * dist);
L += eval(wi, wo, rec) * Li * dot(n, wi) / brdf_pdf *
PowerHeuristic(1., brdf_pdf, 1., lit_pdf_sa);
}
}
}
return true;
}
return false;
}
Comparision between the image produced by MIS and the brute force image
Here are the results:
MIS:
Brute force
the difference
Edit 2022/10/5:
After disabling ANGLE in chrome and launching chrome in OpenGL mode, the brightness of MIS and brute force appears to be the same (I don't know why and it's ridiculous...)