Search code examples
c++raytracingshading

Artifacts and wrong code in ray tracer shading


I'm currently working on a ray tracer for a school project, and for this step of the course we need to implement object shading using an system of lights and the Blinn-Phong algorithm.

Below is the final image if done correctly...

At this point I haven't gotten to the reflections and shadows yet, simply trying to get the shading working first and keep getting this resulting image...

As it's pretty obvious to see, the areas that should have the highest amount of specular are turning green, and I'm getting strange black artifacts in some places around the teapot. I've been reading and testing for hours and cant figure out why! I'm 90% sure I'm implementing the algorithm correctly.

Here is my code that is relevant for this issue...

void shade(RGB& shading, std::vector<Light> lights, Triangle t, Ray& r, Vector3 loc) {
  float intensity = 1 / std::sqrt(lights.size());

  for (std::size_t i = 0; i < lights.size(); ++i) {
    Vector3 n = t.get_normal();
    n.normalize();
    Vector3 v = r.dir * -1;
    v.normalize();
    Vector3 l = lights[i].position - loc;
    l.normalize();
    Vector3 h = v + l;
    h.normalize();

    float diffuse = MAX(0, n.dot(l));
    float spec = std::pow(MAX(0, n.dot(h)), t.fill.shine);

    shading.r += (t.fill.kd * diffuse * t.fill.rgb.r + t.fill.ks * spec) * intensity;
    shading.g += (t.fill.kd * diffuse * t.fill.rgb.g + t.fill.ks * spec) * intensity;
    shading.b += (t.fill.kd * diffuse * t.fill.rgb.b + t.fill.ks * spec) * intensity;
  }
}

// Main function
int main(int argc, char* argv[]) {

  // Set input and output file names
  std::string in_file = (argc > 1) ? argv[1] : "teapot-3.nff";
  std::string out_file = (argc > 2) ? argv[2] : "output.ppm";

  // Parse the NFF file and get the Viewpoint and Background data
  NFFParser parser(in_file);
  parser.read_file();

  Viewpoint view = parser.getViewpoint();
  Background background = parser.getBackground();

  // Camera creation
  Camera camera(view);

  // Allocate array of pixels and create camera instance
  Pixel* pixels = new Pixel[camera.x_res * camera.y_res];

  // Collect object data to iterate over
  std::vector<Polygon> polygons = parser.getPolygons();
  std::vector<Patch> patches = parser.getPatches();
  std::vector<Light> lights = parser.getLights();
  std::vector<Triangle> triangles;

  // Convert all polygons and patches to trianlges and
  // build a vector of triangles to iterator over
  for (std::size_t i = 0; i < polygons.size(); ++i) {
    std::vector<Triangle> v = polygons[i].fan_to_triangles();
    triangles.insert(triangles.end(), v.begin(), v.end());
  }

  for (std::size_t i = 0; i < patches.size(); ++i) {
    std::vector<Triangle> v = patches[i].fan_to_triangles();
    triangles.insert(triangles.end(), v.begin(), v.end());
  }

  std::cout << "Testing for intersections among objects..." << std::endl
            << "...this may take a moment..." << std::endl
            << "==========================================" << std::endl;


  // Iterator over all pixels in the array
  for (int y = 0; y < camera.y_res; ++y) {
    for (int x = 0; x < camera.x_res; ++x) {

      float t = INF;
      Triangle closest;

      // Map pixel to image plane coordinates
      Vector3 image_location = camera.map_to_image(x, y);
      Ray r(camera.e, image_location - camera.e);

      // Iteration over Polygons
      for (std::vector<Triangle>::iterator it = triangles.begin(); it != triangles.end(); ++it) {
        if (it->intersects(&r, t) && t < r.t_min) {
          closest = *it;
          r.t_min = t;
        }
      }

      if (r.t_min == INF) {
        set_pixel(pixels, y, x, camera.y_res, background.rgb);
        continue;
      }

      RGB shading;

      shade(shading, lights, closest, r, image_location);
      set_pixel(pixels, y, x, camera.y_res, shading);

    }
  }


  // Write the array of pixels to the output PPM file
  PPMWriter writer(out_file);
  writer.write_pixels(pixels, camera.x_res, camera.y_res);

  // Deallocate pixels array to avoid memory leaks
  delete [] pixels;

  return 0;
}

Any guidance or help would be greatly appreciated!


EDIT

Green coloring is fixed but RGB component capping, but black artifacting is still an issue.


Solution

  • For the green bits, in your color calculation, you're overflowing what can fit into the red component of a pixel. You can see this if you look at the RGB of the coppery color near the green (0xFE9E4E) vs what's in the green area (0x019D4F).

    You'll need to include some overflow checking in your calculations.