// https://www.scratchapixel.com/lessons/3d-basic-rendering/global-illumination-path-tracing/global-illumination-path-tracing-practical-implementation.html // https://alexanderameye.github.io/notes/sampling-the-hemisphere/ void PointLight::global_illuminate(Ray ray, Output* out, int bounces) { // when using global lighting ignore specural if (bounces >= out->maxbounces || static_cast<float>(rand()) / static_cast<float>(RAND_MAX) < out->probterminate) { // diffuse calculation = surface->dc * surface->kd * NdotL; for (const auto& s : get_surfaces()) { if (s->ray_intersection(ray)) { Eigen::Vector3f light_direction = this->centre - s->point; light_direction.normalize(); float cos_pheta = std::max(0.0f, ((s->normal).dot(light_direction))); this->final_colour.x() = s->kd * s->dc.x() * cos_pheta; this->final_colour.y() = s->kd * s->dc.y() * cos_pheta; this->final_colour.z() = s->kd * s->dc.z() * cos_pheta; } } this->final_colour = this->final_colour / bounces; return; // fmax(0.0f, surface->point.normal.dot(L)) * diffuse intensity * diffuse colour } else { for (const auto& s : get_surfaces()) { if (s->ray_intersection(ray)) { // cosine weighted hemisphere sampling float r1 = static_cast<float>(rand()) / static_cast<float>(RAND_MAX); // between 0 and 1 float r2 = static_cast<float>(rand()) / static_cast<float>(RAND_MAX); // between 0 and 1 float theta = 2 * M_PI * r2; float x = std::sqrt(r1) * cos(theta); float y = std::sqrt(r1) * sin(theta); Eigen::Vector3f new_direction(x, y, std::sqrt(std::max(0.0f, 1-r1))); // create a new ray with out random sampling direction Ray bounce_ray(s->point, new_direction); // here is where we recursive and do the cosine weighted hemisphere sampling to determin direction of random ray Eigen::Vector3f light_direction = this->centre - s->point; light_direction.normalize(); float cos_pheta = std::max(0.0f, ((s->normal).dot(light_direction))); this->final_colour = this->final_colour + (s->kd * s->dc * cos_pheta); global_illuminate(bounce_ray,out, bounces + 1); } else { // if we dont hitanything continue; } } // if our ray doesnt hit anything return; } // check for ray intersection with objects // if no we need to remove it from our samples and from our average // else return global_illuminate(reflection reflection_ray, bounces-1) * direct illumunation with diffuse * cospheta value (N dot L) // at each bounces where we intersect we calculate the light contribution which is only the diffuse value // and at the end these product up to the pixel colour value ( add them up and divive by num bounces ) }
Preview:
downloadDownload PNG
downloadDownload JPEG
downloadDownload SVG
Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!
Click to optimize width for Twitter