I am writing a raytracer and shading using the Phong illumination model. In this example, my material does not have any ambient term. When I render, I get the following image:
As you can see, there appears to be a lighter ring around the specularity. If I disable specularity entirely and only render the diffuse, I obtain the following:
So, this only happens when I introduce specularity. I have done shading multiple times and I have never seen this before. The entire shading code is as follows (I normalized a few more vectors than I needed to just to make sure this wasn't the issue):
glm::vec3 shading(std::shared_ptr<scene::scene> scene, std::shared_ptr<hit> hit, uint16_t level)
{
glm::vec3 normal = glm::normalize(hit->normal);
glm::vec3 result = hit->mat->ka; // Initialize ambient lighting with unit (global) intensity.
glm::vec3 point = hit->r.origin + (glm::normalize(hit->r.direction) * hit->t); // Surface vertex.
glm::vec3 viewing = glm::normalize(scene->camera_pos - point); // Direction vector to the camera.
// Iterate through every light source in the scene, as this contributes to the overall lighting.
for (auto& light_source : scene->lights)
{
glm::vec3 light = glm::normalize(light_source.position - point); // Direction vector to the light.
// Calculate diffuse.
float diffuse_dot = glm::dot(normal, light); // N . L
if (diffuse_dot > 0.0f)
{
glm::vec3 diffuse = light_source.intensity * (diffuse_dot * hit->mat->kd); // Compute diffuse component.
result += diffuse; // Add diffuse component to result.
}
// Calculate specularity.
glm::vec3 reflected = glm::reflect(-light, normal); // GLM takes opposite light vector.
float specularity_dot = glm::dot(viewing, reflected); // R . V
if (specularity_dot > 0.0f)
{
float specularity_coefficient = glm::pow(specularity_dot, hit->mat->ns); // Add specularity component to result.
glm::vec3 specularity = light_source.intensity * (specularity_coefficient * hit->mat->ks);
result += specularity; // Add specularity.
}
}
return glm::clamp(result, 0.0f, 1.0f);
}
The colour is written to a PPM file, and each pixel is written as such:
// Writes the color; currently not thread safe.
void write_color(std::ostream& out, glm::vec3& color)
{
out << static_cast<int>(255.999 * color.x) << ' '
<< static_cast<int>(255.999 * color.y) << ' '
<< static_cast<int>(255.999 * color.z) << '\n';
}
Lastly, the material is defined as follows:
static std::shared_ptr<rt::material> material_blue = std::make_shared<rt::material>(
glm::vec3{ 0.0f }, // Ka
glm::vec3{ 0.0f, 0.0f, 1.0f }, // Kd
glm::vec3{ 1.0f, 1.0f, 1.0f }, // Ks
10.0f, // Ns/Shininess/the power the specularity is raised to
// -snip-
);
I suspect that this may have something to do with glm::clamp
. If I change my code at the end to be the code below, I get the debug render shown below.
if (result.x > 1.0f || result.y > 1.0f || result.z > 1.0f)
{
return glm::vec3{ 1.0f, 0.0f, 0.0f };
}
return glm::clamp(result, 0.0f, 1.0f);
This shape looks awfully familiar to the shape the outline of this ring makes. Therefore I suspect it could be an issue related to clamping, but countless hours of debugging have not gotten me further.
TL;DR I have a weird "ring" around my specularity (see first image) and I want to know how to get rid of it.