I'm sorry if this question is imprecise, or violates any guidelines. This is my first post on Stack Exchange, so any feedback is welcome.

I am working on a ray-marcher in my spare time, which you can see for reference at https://replit.com/@GriffinSchreibe/My-First-Raymarcher (Please press view code to see what's happening, as it does not output anything to the console you can see just from viewing the project). Yes, I am working on an online IDE, purely because I do not have sufficient compute power on my laptop. My code is heavily based on Ray-tracing in one weekend. I have gradually worked through the first few sections, but one section has been stumping me, namely the refraction section.

In my code I have this function that returns the ray color, given a ray shot from the camera:

vec3 ray_color(const ray &r, int depth, float current_medium_ior = 1) {
  // A medium ior of 1 means air.
  if (depth <= 0) {
    return vec3(0, 0, 0);
  // setup parameters and variables
  float total_distance_traveled = 0.0;
  const int NUMBER_OF_STEPS = 64; // 32;
  const float MAXIMUM_HIT_DISTANCE = 0.001;
  const float MAXIMUM_TRACE_DISTANCE = 1000.0;

  vec3 color;

  // iterate through the max number of steps
  for (int i = 0; i < NUMBER_OF_STEPS; ++i) {
    // update the position
    vec3 current_position =
        r.origin() + total_distance_traveled * r.direction();
    // find the distance
    Surface closest_surface = map_the_world(current_position);
    float distance_to_closest = step_size * closest_surface.sd;
    // if we hit something
    float abs_dist = abs(distance_to_closest);
    if (abs_dist < MAXIMUM_HIT_DISTANCE) {
      vec3 normal = calculate_normal(current_position);
      vec3 direction;

      float new_medium_ior = closest_surface.ior;
      if (closest_surface.surface_type == "REFRACTIVE") {

          // Check if the medium has changed
          if (new_medium_ior != current_medium_ior) {
            std::clog<<"Medium change!\n";
              float ior_ratio = new_medium_ior / current_medium_ior;

              vec3 direction = refract(r.direction(), normal, ior_ratio);

              // Recursion
              color = ray_color(ray(current_position + 0.004 * direction, direction), depth - 1, current_medium_ior);
              return color;
          } else {
              // Continue with loop for further intersections within the medium or other behavior
 else {
        direction = closest_surface.scatter_direction(r.direction(), normal);
        // Catch degenerate scatter direction
        if (direction.near_zero())
          direction = normal;
        // Recursion.
        color = 0.5 * ray_color(ray(current_position + 0.004 * normal, direction), depth - 1, current_medium_ior);
        return color;
    // if we have been going for too long
    if (total_distance_traveled > MAXIMUM_TRACE_DISTANCE) {

    // update the distance
    total_distance_traveled += distance_to_closest;

  // if we didn't find anything
  // then we do a blue-white gradient.
  vec3 unit_direction = unit_vector(r.direction());
  auto a = 0.5 * (unit_direction.y() + 1.0);
  return (1.0 - a) * vec3(1.0, 1.0, 1.0) + a * vec3(0.5, 0.7, 1.0);

As you can see, I attempt to implement refraction, but only when the medium changes. After weeks of toil, I am still perplexed as to how to properly implement ray-marched refraction in the spirit of Ray-tracing in one Weekend (By that I mean no "hacky" solutions).

I would be deeply grateful to anyone who could help me solve this problem. Oh, and you can play around with the code in the link above.

EDIT: After fixing the medium change check to see if the origin medium was different from the current medium, I am now getting the refracting sphere as blue. I think that what is happening is that the step size is getting tiny inside the material, as I had the Distance Estimator return 0 inside the material. It then ran out of steps, and returned sky color. I am still curious about the best way to stop the ray-marcher running out of steps, though.


1 Answer 1


The answer, I realized, is to specify a minimum stepsize inside refractive materials.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.