// 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