0

I've been trying to code a very simple ray tracer in Java as a beginner learning experience. So far, I can render ambient and Lambertian shading and I've been trying to add specular highlights and reflections with no success.

Every website I've checked mentions the ambient + diffuse + specular equation but I don't understand how adding a certain specular value to R,G, and B for each pixels is suppose to add a white highlight.

I am also having trouble to figure out how to mix the reflected color and the object color with the shading.

Here are the renders

Edit: After some tweaking, here are the new results

My engine class code looks like this:


    Color color = new Color(0, 0, 0);
    Color reflected_color = new Color(0, 0, 0);
    Sphere obj = (Sphere) this.find_nearest_obj(ray, scene).get(0);
    Vector l = null;
    double obj_dist = (double) this.find_nearest_obj(ray, scene).get(1);

    if (obj == null)
      return color;

    for (Object o : scene.getObjects()) {
      if (o instanceof Vector) {
        l = (Vector) o;
      }
    }

    /*
     * Calculate specific fragment elements
     */

    Vector hit_pos = ray.getPoint().add(ray.getDir().mult(obj_dist));
    Vector normal = hit_pos.sub(obj.getCenter());
    Ray reflected_ray = get_reflected_ray(normal, ray, hit_pos, l);
    // Vector view = normal.mult(2).mult(-1 * normal.dot(ray.getDir()));
    Vector view = scene.getCamera().sub(hit_pos);

    if (obj.isReflective() && ctrl < 5) {
      ctrl++;
      reflected_color = ray_trace(reflected_ray, scene);
      // TODO: recursive reflection implementation
    }

    color = colorAt(obj, scene, normal, reflected_color, view, reflected_ray); // return fragment color

    return color;
  }

  public List<Object> find_nearest_obj(Ray ray, Scene scene) {
    double obj_dist = 0;
    Sphere obj_hit = null;
    List<Object> pair = new ArrayList<Object>();
    for (Object s : scene.getObjects()) { // Find scene objects
      if (s instanceof Sphere) {
        double dist = ((Sphere) s).intersects(ray);
        if (dist > 0 && (obj_hit == null || dist < obj_dist)) {
          obj_dist = dist;
          obj_hit = (Sphere) s;
        }
      }
    }
    pair.add(obj_hit);
    pair.add(obj_dist);
    return pair;
  }

  public Ray get_reflected_ray(Vector normal, Ray ray, Vector hit_pos, Vector l) {
    return new Ray(new Point(hit_pos.x, hit_pos.y, hit_pos.z),
        ray.getDir().add(normal.mult(2).mult(-1 * normal.dot(ray.getDir()))));
//    return new Ray(new Point(hit_pos.x, hit_pos.y, hit_pos.z), l.sub(normal.mult(2).mult(normal.dot(l))));
  }

  public Color colorAt(Sphere obj, Scene scene, Vector normal, Color reflected_color, Vector view, Ray reflected) {
    Vector l = null;
    Vector frag_color = null;
    for (Object o : scene.getObjects()) {
      if (o instanceof Vector) {
        l = (Vector) o;
        if (l != null) {
          double diffuse = l.norm().dot(normal.norm());
          double specular = Math.pow(view.dot(reflected.getDir()), specular_coef);
          if (diffuse < 0)
            diffuse = 0;
          if (specular < 0)
            specular = 0;
            frag_color = (obj.getColor().add(reflected_color)).mult(ambient_control * ambient_coef + (1 - ambient_coef) * diffuse + specular);
        }
      }
    }
    return new Color(frag_color.x, frag_color.y, frag_color.z);
  }
}
symbolads
  • 43
  • 6
  • The specular part is not just "*a certain specular value*". It is calculated for each pixel. And this calculation will produce zero contribution where there should be no highlight. Considering reflection should be a separate question after your local lighting is up and running. If you need help with the illumination calculation, please post the code for `colorAt`. – Nico Schertler Dec 27 '19 at 20:12
  • Thank you for clarifying. I did some extra tweaking and I forgot to normalize some vectors for the reflected ray calculations. I added new images for the renders. The colorAt method body is included in the post. – symbolads Dec 27 '19 at 20:52
  • It also seems that the specular highlights are present on both sides of the spheres (if you look at the reflection of the blue ball on the yellow ball for example). – symbolads Dec 27 '19 at 21:02
  • Looks good in general. It is not a standard illumination model, but it can still make sense. `specular` should be set to 0 if `diffuse < 0` (the pow might make it positive). You usually just add the reflected light to the total light (multiplied by a reflectivity fraction). – Nico Schertler Dec 27 '19 at 21:59
  • Thank you for the feedback. I added the changes you suggested and it does look a lot better. – symbolads Dec 27 '19 at 22:21

0 Answers0