title: Refraction in Raytracing?
body: <p>I've been  working on my raytracer again. I added reflection and multithreading support. Currently I am working on adding refractions, but its only half working.
  <img src="https://i.stack.imgur.com/uoPCp.jpg" alt="Spheres"></p>
  
  <p>As you can see, there is a center sphere(without specular highlight), a reflecting sphere(to the right) and a refracting sphere(left). I'm pretty happy about reflections, it does look very good. For refractions its kinda working...the light is refracted and all shadows of the spheres are visible in the sphere(refraction index 1.4), but there is an outer black ring.</p>
  
  <p>EDIT: Apparently the black ring gets bigger, and therefore the sphere smaller, when I increase the refraction index of the sphere. On the contrary, when decreasing the index of refraction, the Sphere gets larger and the black ring smaller...until, with index of refraction set to one, the ring totally disappears.
  IOR = 1.9
  <img src="https://i.stack.imgur.com/yMmR6.jpg" alt="enter image description here">
  IOR = 1.1
  <img src="https://i.stack.imgur.com/V7NBm.jpg" alt="enter image description here">
  IOR = 1.00001
  <img src="https://i.stack.imgur.com/RLnss.jpg" alt="enter image description here">
  And interestingly enough at IOR = 1 the sphere loses its transparency and becomes white.
  <img src="https://i.stack.imgur.com/nKpwN.jpg" alt="enter image description here"></p>
  
  <p>I think I covered total internal reflection and it is not the issue here.</p>
  
  <p>Now the code:
  I'm using the <code>operator |</code> for dot product, so <code>(vec|vec)</code> is a dot product and the <code>operator ~</code> to invert vectors. The objects, both ligths and spheres are stored in <code>Object **objects;</code>.
  Raytrace function</p>
  
  <pre><code>Colour raytrace(const Ray &amp;r, const int &amp;depth)
  {
      //first find the nearest intersection of a ray with an object
      Colour finalColour = skyBlue *(r.getDirection()|Vector(0,0,-1)) * SKY_FACTOR;
      double t, t_min = INFINITY;
      int index_nearObj = -1;
      for(int i = 0; i &lt; objSize; i++)
      {
          if(!dynamic_cast&lt;Light *&gt;(objects[i]))//skip light src
          {
              t = objects[i]-&gt;findParam(r);
              if(t &gt; 0 &amp;&amp; t &lt; t_min)
              {
                  t_min = t;
                  index_nearObj = i;
              }
          }
      }
      //no intersection
      if(index_nearObj &lt; 0)
          return finalColour;
  
      Vector intersect = r.getOrigin() + r.getDirection()*t_min;
      Vector normal = objects[index_nearObj]-&gt;NormalAtIntersect(intersect);
      Colour objectColor = objects[index_nearObj]-&gt;getColor();
      Ray rRefl, rRefr; //reflected and refracted Ray
      Colour refl = finalColour, refr = finalColour; //reflected and refracted colours
      double reflectance = 0, transmittance = 0;
  
      if(objects[index_nearObj]-&gt;isReflective() &amp;&amp; depth &lt; MAX_TRACE_DEPTH)
      {
          //handle reflection
          rRefl = objects[index_nearObj]-&gt;calcReflectingRay(r, intersect, normal);
          refl = raytrace(rRefl, depth + 1);
          reflectance = 1;
      }
  
      if(objects[index_nearObj]-&gt;isRefractive() &amp;&amp; depth &lt; MAX_TRACE_DEPTH)
      {
          //handle transmission
          rRefr = objects[index_nearObj]-&gt;calcRefractingRay(r, intersect, normal, reflectance, transmittance);
          refr = raytrace(rRefr, depth + 1);
      }
  
      Ray rShadow; //shadow ray
      bool shadowed;
      double t_light = -1;
  
      Colour localColour;
      Vector tmpv;
  
      //get material properties
      double ka = 0.2; //ambient coefficient
      double kd; //diffuse coefficient
      double ks; //specular coefficient
  
      Colour ambient = ka * objectColor; //ambient component
      Colour diffuse, specular;
      double brightness;
      localColour = ambient;
      //look if the object is in shadow or light
      //do this by casting a ray from the obj and
      // check if there is an intersection with another obj
      for(int i = 0; i &lt; objSize; i++)
      {
          if(dynamic_cast&lt;Light *&gt;(objects[i])) //if object is a light
          {
              //for each light
              shadowed = false;
              //create Ray to light
              tmpv = objects[i]-&gt;getPosition() - intersect;
              rShadow = Ray(intersect  + (!tmpv) * BIAS, tmpv);
              t_light = objects[i]-&gt;findParam(rShadow);
  
              if(t_light &lt; 0) //no imtersect, which is quite impossible
                  continue;
  
              //then we check if that Ray intersects one object that is not a light
              for(int j = 0; j &lt; objSize; j++)
              {
                      if(!dynamic_cast&lt;Light *&gt;(objects[j]) &amp;&amp; j != index_nearObj)//if obj is not a light
                      {
                          t = objects[j]-&gt;findParam(rShadow);
                          //if it is smaller we know the light is behind the object
                          //--&gt; shadowed by this light
                          if (t &gt;= 0 &amp;&amp; t &lt; t_light)
                          {
                              // Set the flag and stop the cycle
                              shadowed = true;
                              break;
                          }
                      }
              }
  
              if(!shadowed)
              {
                  rRefl = objects[index_nearObj]-&gt;calcReflectingRay(rShadow, intersect, normal);
                  //reflected ray from ligh src, for ks
                  kd = maximum(0.0, (normal|rShadow.getDirection()));
                  if(objects[index_nearObj]-&gt;getShiny() &lt;= 0)
                      ks = 0;
                  else
                      ks = pow(maximum(0.0, (r.getDirection()|rRefl.getDirection())), objects[index_nearObj]-&gt;getShiny());
                  diffuse = kd * objectColor;// * objects[i]-&gt;getColour();
                  specular = ks * objects[i]-&gt;getColor();
                  brightness = 1 /(1 + t_light * DISTANCE_DEPENDENCY_LIGHT);
                  localColour += brightness * (diffuse + specular);
              }
          }
      }
      finalColour = localColour + (transmittance * refr + reflectance * refl);
      return finalColour;
  }
  </code></pre>
  
  <p>Now the function that calculates the refracted Ray, I used several different sites for resource, and each had similar algorithms. This is the best I could do so far. It may just be a tiny detail I'm not seeing...</p>
  
  <pre><code>Ray Sphere::calcRefractingRay(const Ray &amp;r, const Vector &amp;intersection,Vector &amp;normal, double &amp; refl, double &amp;trans)const
  {
      double n1, n2, n;
      double cosI = (r.getDirection()|normal);
      if(cosI &gt; 0.0)
      {
          n1 = 1.0;
          n2 = getRefrIndex();
          normal = ~normal;//invert
      }
      else
      {
          n1 = getRefrIndex();
          n2 = 1.0;
          cosI = -cosI;
      }
      n = n1/n2;
      double sinT2 = n*n * (1.0 - cosI * cosI);
      double cosT = sqrt(1.0 - sinT2);
      //fresnel equations
      double rn = (n1 * cosI - n2 * cosT)/(n1 * cosI + n2 * cosT);
      double rt = (n2 * cosI - n1 * cosT)/(n2 * cosI + n2 * cosT);
      rn *= rn;
      rt *= rt;
      refl = (rn + rt)*0.5;
      trans = 1.0 - refl;
      if(n == 1.0)
          return r;
      if(cosT*cosT &lt; 0.0)//tot inner refl
      {
          refl = 1;
          trans = 0;
          return calcReflectingRay(r, intersection, normal);
      }
      Vector dir = n * r.getDirection() + (n * cosI - cosT)*normal;
      return Ray(intersection + dir * BIAS, dir);
  }
  </code></pre>
  
  <p>EDIT: I also changed the refraction index around.From </p>
  
  <pre><code>    if(cosI &gt; 0.0)
      {
          n1 = 1.0;
          n2 = getRefrIndex();
          normal = ~normal;
      }
      else
      {
          n1 = getRefrIndex();
          n2 = 1.0;
          cosI = -cosI;
      }
  </code></pre>
  
  <p>to</p>
  
  <pre><code>if(cosI &gt; 0.0)
  {
      n1 = getRefrIndex();
      n2 = 1.0;
      normal = ~normal;
  }
  else
  {
      n1 = 1.0;
      n2 = getRefrIndex();
      cosI = -cosI;
  }
  </code></pre>
  
  <p>Then I get this, and almost the same(still upside down) with an index of refraction at 1!
  <img src="https://i.stack.imgur.com/u1C7d.jpg" alt="enter image description here">
  And the reflection calculation:</p>
  
  <pre><code>Ray Sphere::calcReflectingRay(const Ray &amp;r, const Vector &amp;intersection, const Vector &amp;normal)const
  {
      Vector rdir = r.getDirection();
      Vector dir = rdir - 2 * (rdir|normal) * normal;
      return Ray(intersection + dir*BIAS, dir);
      //the Ray constructor automatically normalizes directions
  }
  </code></pre>
  
  <p>So my question is: How do I fix the outer black circle? Which version is correct?</p>
  
  <p>Help is greatly appreciated :)</p>
  
  <p>This is compiled on Linux using g++ 4.8.2.</p>