In this post, I try to implement a simple Ray-Tracing algorithm which support to render some basic shape (sphere, box, plane, disk). And the corresponding codes can be downloaded in hudongyue1/myGL (github.com)  The reference is Scratchapixel .
1. The Whole Pipeline 
The picture above shows the whole procedure in my simple ray-tracer.
Degree to radians 1 2 3 4 inline float  deg2rad (const  float  °)      return  deg * M_PI / 180 ; } 
Clamp 1 2 3 4 inline float  clamp (const  float  &lo, const  float  &hi, const  float  &v)      return  std::max (lo, std::min (hi, v)); } 
MixColor 1 2 3 4 inline Vec3f mix (const  Vec3f &a, const  Vec3f& b, const  float  &mixValue)  {    return  a * (1  - mixValue) + b * mixValue; } 
The parent class for all shape Different kind of shape should implement these virtual function separately, and the detailed method could be found in the previous post: Scratchapixel: Intersection .
1 2 3 4 5 6 7 8 9 10 11 12 class  Object  {public :    Object () : color (dis (gen), dis (gen), dis (gen)) {}     virtual  ~Object () {}          virtual  bool  intersect (const  Vec3f &, const  Vec3f &, float  &)  const  0 ;          virtual  void  getSurfaceData (const  Vec3f &, Vec3f &, Vec2f &)  const  0 ;     Vec3f color; }; 
3. Important Functions render The render could be splited as two steps:
Iterating over each pixel of the image, and calling the function 
Using the result of 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 void  render (const  Options &options, const  std::vector<std::unique_ptr<Object>> &objects)      Vec3f *framebuffer = new  Vec3f[options.width * options.height];     Vec3f *pix = framebuffer;     float  scale = tan (deg2rad (options.fov * 0.5 ));     float  imageAspectRatio = options.width / (float ) options.height;     Vec3f orig;     options.cameraToWorld.multVecMatrix (Vec3f (0 ), orig);     for (uint32_t  j=0 ; j<options.height; ++j) {         for (uint32_t  i=0 ; i<options.width; ++i) {             float  x = (2  * (i + 0.5 ) / (float ) options.width - 1 ) * scale * imageAspectRatio;             float  y = (1  - 2  * (j + 0.5 ) / (float ) options.height) * scale;             Vec3f dir;             options.cameraToWorld.multDirMatrix (Vec3f (x, y, -1 ), dir);             dir.normalize ();             *(pix++) = castRay (orig, dir, objects);         }     }     std::ofstream ofs ("./out/out.ppm" , std::ios::out | std::ios::binary)  ;     ofs << "P6\n"  << options.width << " "  << options.height << "\n225\n" ;     for (uint32_t  i=0 ; i<options.height * options.width; ++i) {         char  r = (char )(255 *clamp (0 , 1 , framebuffer[i].x));         char  g = (char )(255 *clamp (0 , 1 , framebuffer[i].y));         char  b = (char )(255 *clamp (0 , 1 , framebuffer[i].z));         ofs << r << g << b;     }     ofs.close ();     delete  [] framebuffer; } 
castRay Using the result of 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Vec3f castRay (const  Vec3f &orig, const  Vec3f &dir, const  std::vector<std::unique_ptr<Object>> &objects)   {    Vec3f hitColor = 0 ;     const  Object *hitObject = nullptr ;     float  t;     if (trace (orig, dir, objects, t, hitObject)) {         Vec3f Phit = orig + dir * t;         Vec3f Nhit;         Vec2f tex;         hitObject->getSurfaceData (Phit, Nhit, tex);         float  scale = 4 ;         float  pattern = (fmodf (tex.x * scale, 1 ) > 0.5 ) ^ (fmodf (tex.y * scale, 1 ) > 0.5 );         hitColor = std::max (0.f , Nhit.dotProduct (-dir)) * mix (hitObject->color, hitObject->color * 0.8 , pattern);     }     return  hitColor; } 
trace Iterating all the objects in world space, finding the first intersection with these objects for the specific ray (if do not parallel).
1 2 3 4 5 6 7 8 9 10 11 12 13 bool  trace (const  Vec3f &orig, const  Vec3f &dir, const  std::vector<std::unique_ptr<Object>> &objects, float  &tNear, const  Object *&hitObject)      tNear = kInfinity;     std::vector<std::unique_ptr<Object>>::const_iterator iter = objects.begin ();     for (; iter != objects.end (); ++iter) {         float  t = kInfinity;         if ((*iter)->intersect (orig, dir, t) && t < tNear) {             hitObject = iter->get ();             tNear = t;         }     }     return  (hitObject != nullptr ); }