Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Simple Ray Tracing in C# Part III (Reflection)

0.00/5 (No votes)
15 Jul 2016 1  
Ray tracing in C# part III - implementing reflection

 

Screenshot - raytracingXVI.png
recursivity level = 10

Screenshot - 30.png
recursivity level = 2

Center Sphere alpha = 0.2 ( simulating glass refraction )

Other Spheres have alpha = 1.0 (simulating only reflection)

Introduction

Previously we have seen ray tracing and mapping in spheres and triangles with simple illumination model, now we will extend this with reflections and refractions.

If you need previous background please check it out on the last articles below:

Background

A background in Linear Algebra is required, related to R3 points and vectors, object equations, intersections, vector reflections, rotations around axis, dot and cross products, angle between vectors and so. For this I created a helper class called tAlgebra as below:

Algebra class

public class tAlgebra
     {
     public tAlgebra()
          {
          }
     public static double GetCoord(double i1, double i2, double w1, 
                                      double w2, double p)
          {
          return ((p - i1) / (i2 - i1)) * (w2 - w1) + w1;
          }
     public static void Cross3(double ax, double ay, double az,
            double bx, double by, double bz,
            ref double outx, ref double outy, ref double outz)
          {
          outx = ay * bz - az * by;
          outy = az * bx - ax * bz;
          outz = ax * by - ay * bx;
          }
     public static void Refract(double n1, double n2, 
                                   double inx, double iny, double inz,
                                   double mirrorx, double mirrory, 
                                   double mirrorz,
                                   ref double outx, ref double outy, 
                                   ref double outz)
          {
          double c1 = -Dot3(mirrorx, mirrory, mirrorz, inx, iny, inz);
          double n = n1 / n2;
          
          double c2 = Math.Sqrt(1.0 - n * n * (1.0 - c1 * c1));
          outx = (n * inx) + (n * c1 - c2) * mirrorx;
          outy = (n * iny) + (n * c1 - c2) * mirrory;
          outz = (n * inz) + (n * c1 - c2) * mirrorz;
          }
     public static void Reflect(double inx, double iny, double inz,
            double mirrorx, double mirrory, double mirrorz,
            ref double outx, ref double outy, ref double outz)
          {
          double c1 = -Dot3(mirrorx, mirrory, mirrorz, inx, iny, inz);
          
          //Rl = V + (2 * N * c1 )
          outx = -(inx + (2 * mirrorx * c1));
          outy = -(iny + (2 * mirrory * c1));
          outz = -(inz + (2 * mirrorz * c1));
          }
     public static double Dot3(double x1, double y1, double z1, 
                                  double x2, double y2, double z2)
          {
          return ((x1 * x2) + (y1 * y2) + (z1 * z2));
          } 
     // * note: use normalized vectors here!
     public static double GetCosAngleV1V2(double v1x, double v1y, 
                              double v1z, double v2x, double v2y, double v2z)
          {
          // cos(t) = (v.w) / (|v|.|w|) = (v.w) / 1
          return Dot3(v1x, v1y, v1z, v2x, v2y, v2z);
          }
     public static double modv(double vx, double vy, double vz)
          {
          return System.Math.Sqrt(vx * vx + vy * vy + vz * vz);
          }
     public static bool Normalize(ref double vx, ref double vy, 
                                     ref double vz)
          {
          double mod_v = tAlgebra.modv(vx, vy, vz);
          double eps = 1.0E-20;
          if (Math.Abs(mod_v) < eps)
               return true;
          
          vx = vx / mod_v;
          vy = vy / mod_v;
          vz = vz / mod_v;
          return false;
          }
     public static void RotX(double angle, ref double y, ref double z)
          {
          double y1 = y * System.Math.Cos(angle) - z * 
                        System.Math.Sin(angle);
          double z1 = y * System.Math.Sin(angle) + z * 
                        System.Math.Cos(angle);
          y = y1;
          z = z1;
          }
     public static void RotY(double angle, ref double x, ref double z)
          {
          double x1 = x * System.Math.Cos(angle) - z * 
                        System.Math.Sin(angle);
          double z1 = x * System.Math.Sin(angle) + z * 
                        System.Math.Cos(angle);
          x = x1;
          z = z1;
          }
     public static void RotZ(double angle, ref double x, ref double y)
          {
          double x1 = x * System.Math.Cos(angle) - y * 
                        System.Math.Sin(angle);
          double y1 = x * System.Math.Sin(angle) + y * 
                        System.Math.Cos(angle);
          x = x1;
          y = y1;
          }
     }

Now, as seen before, we need a class to define materials, in terms of ambient, diffuse and specular parameters:

Material Class

public class tMaterial
    {
    public double ambientR, ambientG, ambientB, ambientA;
    public double specularR, specularG, specularB, specularA;
    public double shininess;
    public double alpha;
    }

R3 Point Class

public class tPoint
    {
        public double x = 0, y = 0, z = 0;
    }

In order to create the objects, spheres and triangles I have created a base abstract class tObject, and the derived tSphere and tTriangle:

Object Class

public abstract class tObject
     {
     public tObject()
          {
          }
     public tPoint get_point_color(System.Collections.ArrayList lights, 
                                   tRay ray)
          {
          tPoint color = new tPoint();
          tPoint normal = new tPoint();
          tPoint rayV = ray.getRay();
 
          //for each light // i leave it to the next article :) 
          tPoint light = (tPoint)lights[0];
          getNormal(hitpoint.x, hitpoint.y, hitpoint.z,
                ref normal.x, ref normal.y, ref normal.z);
 
          double lvX = light.x - hitpoint.x,
                   lvY = light.y - hitpoint.y,
                   lvZ = light.z - hitpoint.z;
          
          tAlgebra.Normalize(ref normal.x, ref normal.y, ref normal.z);
          tAlgebra.Normalize(ref lvX, ref lvY, ref lvZ);
 
          double cost = tAlgebra.GetCosAngleV1V2(lvX, lvY, lvZ,
                normal.x, normal.y, normal.z);
          double cosf = 0;
 
          tAlgebra.Reflect(-lvX, -lvY, -lvZ,
                             normal.x, normal.y, normal.z,
                             ref vReflX, ref vReflY, ref vReflZ);
          tAlgebra.Normalize(ref vReflX, ref vReflY, ref vReflZ);
          tAlgebra.Normalize(ref rayV.x, ref rayV.y, ref rayV.z);
 
          cosf = tAlgebra.GetCosAngleV1V2(rayV.x, rayV.y, rayV.z, 
                             vReflX, vReflY, vReflZ);
          double result1 = Math.Max(0, cost) * 255.0;
          double result2 = Math.Pow(Math.Max(0, cosf), 
                           material.shininess) * 255.0;
          
          double rgbR = (material.ambientR * 255.0) +
                (material.diffuseR * result1) +
                (material.specularR * result2);
          double rgbG = (material.ambientG * 255.0) +
                (material.diffuseG * result1) +
                (material.specularG * result2);
          double rgbB = (material.ambientB * 255.0) +
                (material.diffuseB * result1) +
                (material.specularB * result2);
 
          color.x = rgbR;
          color.y = rgbG;
          color.z = rgbB;
          return color;
          }
     public tRay get_reflected_ray(tRay original_ray)
          {
          tRay ray = new tRay();
          double inx = 0, iny = 0, inz = 0, nx = 0, ny = 0, nz = 0, 
                 rx = 0, ry = 0, rz = 0;
  
          getNormal(hitpoint.x, hitpoint.y, hitpoint.z, 
                    ref nx, ref ny, ref nz);
 
          inx = original_ray.getRay().x;
          iny = original_ray.getRay().y;
          inz = original_ray.getRay().z;
 
          tAlgebra.Normalize(ref inx, ref iny, ref inz);
          tAlgebra.Normalize(ref nx, ref ny, ref nz);
          tAlgebra.Reflect(-inx, -iny, -inz, nx, ny, nz, ref rx, 
                          ref ry, ref rz);
          tAlgebra.Normalize(ref rx, ref ry, ref rz);
 
          ray.x0 = hitpoint.x;
          ray.y0 = hitpoint.y;
          ray.z0 = hitpoint.z;
          ray.x1 = (hitpoint.x + rx);
          ray.y1 = (hitpoint.y + ry);
          ray.z1 = (hitpoint.z + rz);
          return ray;
          }
     public tMaterial material
          {
          get
               {
               return tmaterial;
               }
          set
               {
               tmaterial = value;
               }
          }
     public tPoint hitpoint
          {
          get
               {
               return tHitPoint;
               }
          set
               {
               tHitPoint = value;
               }
          } 
     private tMaterial tmaterial;
     private tPoint tHitPoint;
     private double vReflX = 0, vReflY = 0, vReflZ = 0;
 
     public abstract double GetIntersect(double p1x, double p1y, double p1z,
                                 double p2x, double p2y, double p2z);
     public abstract void getNormal(double x, double y, double z,
            ref double nx, ref double ny, ref double nz);
 
     public tRay get_refracted_ray(tRay original_ray)
          {
          tRay ray = new tRay();
          double inx = 0, iny = 0, inz = 0, 
                 nx = 0, ny = 0, nz = 0, rx = 0, ry = 0, rz = 0;
          getNormal(hitpoint.x, hitpoint.y, hitpoint.z, 
                    ref nx, ref ny, ref nz);
 
          inx = original_ray.getRay().x;
          iny = original_ray.getRay().y;
          inz = original_ray.getRay().z;
 
          tAlgebra.Normalize(ref inx, ref iny, ref inz);
          tAlgebra.Normalize(ref nx, ref ny, ref nz);
 
          double n1 = 1.00;
          double n2 = 1.50;
 
          tAlgebra.Refract(n1, n2, -inx, -iny, -inz, nx, ny, nz, 
                           ref rx, ref ry, ref rz);
          tAlgebra.Normalize(ref rx, ref ry, ref rz);
 
          ray.x0 = hitpoint.x;
          ray.y0 = hitpoint.y;
          ray.z0 = hitpoint.z;
          ray.x1 = (hitpoint.x + rx);
          ray.y1 = (hitpoint.y + ry);
          ray.z1 = (hitpoint.z + rz);
          return ray;
          }
     }

Sphere Class

public class tSphere : tObject
     {
     public tSphere(double x, double y, double z, double r)
          {
          cx = x;
          cy = y;
          cz = z;
          radius = r;
          }
     void Move(double vx, double vy, double vz)
          {
          cx += vx;
          cy += vy;
          cz += vz;
          }
     void MoveTo(double vx, double vy, double vz)
          {
          cx = vx;
          cy = vy;
          cz = vz;
          }
     public override double GetIntersect(double px, double py, double pz, 
                                 double x, double y, double z)
          {
          // x-xo 2 + y-yo 2 + z-zo 2 = r 2
          // x,y,z = p+tv 
          // At2 + Bt + C = 0
          double vx = x - px;
          double vy = y - py;
          double vz = z - pz;
 
          double A = (vx * vx + vy * vy + vz * vz);
          double B = 2.0 * (px * vx + py * vy + 
                      pz * vz - vx * cx - vy * cy - vz * cz);
          double C = px * px - 2 * px * cx + cx * cx + 
                      py * py - 2 * py * cy + cy * cy + pz * pz - 
                      2 * pz * cz + cz * cz - radius * radius;
          double D = B * B - 4 * A * C;
          double t = -1.0;
 
          if (D >= 0)
               {
               double t1 = (-B - System.Math.Sqrt(D)) / (2.0 * A);
               double t2 = (-B + System.Math.Sqrt(D)) / (2.0 * A);
               if (t1 < t2) 
                    t = t1; 
               else 
                    t = t2;
 
               tPoint pt = new tPoint();
               pt.x = px + t * vx;
               pt.y = py + t * vy;
               pt.z = pz + t * vz;
               hitpoint = pt;
               }
          return t;
          }
     public override void getNormal(double x, double y, double z, 
                     ref double nx, ref double ny, ref double nz)
          {
          nx = x - cx;
          ny = y - cy;
          nz = z - cz;
          }
     public double cx, cy, cz, radius, clR, clG, clB;
     }

Triangle Class

public class tTriangle : tObject
     {
     public tTriangle()
          {
          }
     public void Init()
          {
          GetNormal(ref tnormalX, ref tnormalY, ref tnormalZ);
          }
     public bool SameSide(double p1x, double p1y, double p1z,
                             double p2x, double p2y, double p2z,
                             double ax, double ay, double az,
                             double bx, double by, double bz)
          {
          double cp1x = 0, cp1y = 0, cp1z = 0, cp2x = 0, cp2y = 0,
                   cp2z = 0;
          tAlgebra.Cross3(bx - ax, by - ay, bz - az, p1x - ax,
              p1y - ay, p1z - az, ref cp1x, ref cp1y, ref cp1z);
          tAlgebra.Cross3(bx - ax, by - ay, bz - az, p2x - ax,
              p2y - ay, p2z - az, ref cp2x, ref cp2y, ref cp2z);
          if (tAlgebra.Dot3(cp1x, cp1y, cp1z, cp2x, cp2y, cp2z) >= 0)
               return true;
          else
               return false;
          }
     public bool PointInTriangle(double px, double py, double pz)
          {
          if (SameSide(px, py, pz, tp1x, tp1y, tp1z,
                    tp2x, tp2y, tp2z, tp3x, tp3y, tp3z) &&
                SameSide(px, py, pz, tp2x, tp2y, tp2z,
                    tp1x, tp1y, tp1z, tp3x, tp3y, tp3z) &&
                SameSide(px, py, pz, tp3x, tp3y, tp3z,
                    tp1x, tp1y, tp1z, tp2x, tp2y, tp2z))
                return true;
          else
                return false;
          }
     // ray p1, ray p2
     public override double GetIntersect(double p1x, double p1y, double p1z,
                                 double p2x, double p2y, double p2z)
          {
          double v1x = tp3x - p1x;
          double v1y = tp3y - p1y;
          double v1z = tp3z - p1z;
          double v2x = p2x - p1x;
          double v2y = p2y - p1y;
          double v2z = p2z - p1z;
          double dot1 = tAlgebra.Dot3(tnormalX, tnormalY, tnormalZ,
                                        v1x, v1y, v1z);
          double dot2 = tAlgebra.Dot3(tnormalX, tnormalY, tnormalZ,
                                        v2x, v2y, v2z);
          if (Math.Abs(dot2) < 1.0E-6)
                return -1; // division by 0 means parallel
          double u = dot1 / dot2;
          // point in triangle?
          if (!PointInTriangle(p1x + u * (p2x - p1x),
                            p1y + u * (p2y - p1y), p1z + u * (p2z - p1z)))
               return -1;
 
          tPoint pt = new tPoint();
          pt.x = p1x + u * v2x;
          pt.y = p1y + u * v2y;
          pt.z = p1z + u * v2z;
          
          hitpoint = pt;
          return u;
          }
     protected void GetNormal(ref double nx, ref double ny, ref double nz)
          {
          double ux = tp3x - tp1x, uy = tp3y - tp1y, uz = tp3z - tp1z;
          double wx = tp2x - tp1x, wy = tp2y - tp1y, wz = tp2z - tp1z;

          // u x w
          nx = wz * uy - wy * uz;
          ny = wx * uz - wz * ux;
          nz = wy * ux - wx * uy;
          }        
     public override void getNormal(double x, double y, double z, 
                  ref double nx, ref double ny, ref double nz)
          {
          nx = -tnormalX;
          ny = -tnormalY;
          nz = -tnormalZ;
          }

     // should be private with get/set
     public double tp1x, tp1y, tp1z;
     public double tp2x, tp2y, tp2z;
     public double tp3x, tp3y, tp3z;
     public double tnormalX, tnormalY, tnormalZ;
    }

Now (Finally) the Ray Tracing Class

public class tRay
     {
     // rotation
     public double rx = 0.0, ry = 0.0, rz = 0.0;
     public double x0 = 0, y0 = 0, z0 = 0;
     public double x1 = 0, y1 = 0, z1 = 0;
     public int levels = 3;
     int level = 0;
     System.Collections.ArrayList obj3dArrayList;
     System.Collections.ArrayList lightsArrayList;
 
     public tRay()
          {
          obj3dArrayList = new System.Collections.ArrayList();
          lightsArrayList = new System.Collections.ArrayList();
          }
 
     public void AddTriangle(double ax, double ay, double az,
                                double bx, double by, double bz,
                                double cx, double cy, double cz, 
                                tMaterial mat)
          {
          tTriangle tri = new tTriangle();
          tri.tp1x = ax;
          tri.tp1y = ay;
          tri.tp1z = az;
          tri.tp2x = bx;
          tri.tp2y = by;
          tri.tp2z = bz;
          tri.tp3x = cx;
          tri.tp3y = cy;
          tri.tp3z = cz;
 
          tAlgebra.RotX(rx, ref tri.tp1y, ref tri.tp1z);
          tAlgebra.RotX(rx, ref tri.tp2y, ref tri.tp2z);
          tAlgebra.RotX(rx, ref tri.tp3y, ref tri.tp3z);
          tAlgebra.RotY(ry, ref tri.tp1x, ref tri.tp1z);
          tAlgebra.RotY(ry, ref tri.tp2x, ref tri.tp2z);
          tAlgebra.RotY(ry, ref tri.tp3x, ref tri.tp3z);
          tAlgebra.RotZ(rz, ref tri.tp1x, ref tri.tp1y);
          tAlgebra.RotZ(rz, ref tri.tp2x, ref tri.tp2y);
          tAlgebra.RotZ(rz, ref tri.tp3x, ref tri.tp3y);
 
          tri.material = mat;
          tri.Init();
          AddObject(tri);
          }
     public void AddLight(tPoint light)
          {
          tAlgebra.RotX(rx, ref light.y, ref light.z);
          tAlgebra.RotY(ry, ref light.x, ref light.z);
          tAlgebra.RotZ(rz, ref light.x, ref light.y);
          lightsArrayList.Add(light);
          }
     public void AddObject(tObject obj)
          {
          obj3dArrayList.Add(obj);
          }
     private tObject get_first_intersection(tRay original_ray)
          {
          double eps = 1.0E-4; 
          double t = 1.0E10;
 
          tObject objhit = null;
 
          for (int k = 0; k < (int)obj3dArrayList.Count; k++)
               {
               tObject objn = (tObject)obj3dArrayList[k];
               double taux = objn.GetIntersect(original_ray.x0, 
                                original_ray.y0, original_ray.z0,
                                original_ray.x1, original_ray.y1, 
                                original_ray.z1);

               if (Math.Abs(taux) <= eps) continue; 

               if (taux > 0 && taux < t)
                    {
                    t = taux;
                    objhit = objn;
                    }
                }
          return objhit;
          }
     public tPoint trace_ray(tRay original_ray)
          {
          level++;
          tPoint point_color = new tPoint(), reflect_color = new tPoint(), 
                                refract_color = new tPoint();
          if (level > levels)
               {
               level--;
               point_color.x = 0;
               point_color.y = 0;
               point_color.z = 0; 
               return point_color;
               }
          tObject obj = get_first_intersection(original_ray);
          if (obj != null)
               {
               point_color = obj.get_point_color(lightsArrayList, 
                           original_ray);
               tRay rfl = obj.get_reflected_ray(original_ray);
               tRay rfr = obj.get_refracted_ray(original_ray);
               tPoint clraux = new tPoint();
               bool brfl = false, brfr = false;
               reflect_color = trace_ray(rfl);
               if (reflect_color.x > 0 || reflect_color.y > 0 || 
                   reflect_color.z > 0)
                    {
                    brfl = true;
                    }
               if (obj.material.alpha < 1.0)
                    {
                    refract_color = trace_ray(rfr);
                    if (refract_color.x > 0 || refract_color.y > 0 || 
                        refract_color.z > 0)
                        brfr = true;
                    }
               if (brfl && brfr)
                    {
                    clraux.x = (3 * point_color.x + reflect_color.x + 5 * 
                              refract_color.x) / 9;
                    clraux.y = (3 * point_color.y + reflect_color.y + 5 * 
                              refract_color.y) / 9;
                    clraux.z = (3 * point_color.z + reflect_color.z + 5 * 
                              refract_color.z) / 9;
                    }
               else
               if (brfl)
                    {
                    clraux.x = (point_color.x + reflect_color.x) / 2;
                    clraux.y = (point_color.y + reflect_color.y) / 2;
                    clraux.z = (point_color.z + reflect_color.z) / 2;
                    }
               else
               if (brfr)
                    {
                    clraux.x = (3 * point_color.x + 5 * 
                                   refract_color.x) / 8;
                    clraux.y = (3 * point_color.y + 5 * 
                                   refract_color.y) / 8;
                    clraux.z = (3 * point_color.z + 5 * 
                                   refract_color.z) / 8;
                    }
               else
                    {
                    clraux.x = point_color.x;
                    clraux.y = point_color.y;
                    clraux.z = point_color.z;
                    }
               level--;
               return clraux; // combine with other
               }
          level--;
          return point_color;
          }
     public tPoint getRay()
          {
          tPoint ray = new tPoint();
          ray.x = x1 - x0;
          ray.y = y1 - y0;
          ray.z = z1 - z0;
          return ray;
          }
     public void AddSphere(double cx, double cy, double cz, double radius, 
                           tMaterial mat)
          {
          tAlgebra.RotX(rx, ref cy, ref cz);
          tAlgebra.RotY(ry, ref cx, ref cz);
          tAlgebra.RotZ(rz, ref cx, ref cy);
          tSphere sph = new tSphere(cx, cy, cz, radius);
          sph.material = mat;
          AddObject(sph);
          }
     }

Using the Code

Follows a sample of code usage, I made this to display the resulting image in a web page:

Bitmap newBitmap = new Bitmap(300, 300,
                   PixelFormat.Format32bppArgb);

Graphics g = Graphics.FromImage(newBitmap);
Rectangle rect = new Rectangle(0, 0, 300, 300);
double fMax = 610.0;
tRay ray = new tRay();
ray.rx = 0.0; ray.ry = 0.0; ray.rz = 0.0;
ray.levels = 10;
tPoint pt = new tPoint();
pt.x = 250;
pt.y = 250;
pt.z = 630;
ray.AddLight(pt);

tMaterial mat1 = new tMaterial();
mat1.alpha = 1.0;
mat1.ambientR = 0.1324;
mat1.ambientG = 0.0324;
mat1.ambientB = 0.0236;
mat1.specularR = 0.651;
mat1.specularG = 0.351;
mat1.specularB = 0.351;
mat1.shininess = 20;
mat1.diffuseR = 0.4775;
mat1.diffuseG = 0.2775;
mat1.diffuseB = 0.2775;

tMaterial mat2 = new tMaterial();
mat2.alpha = 0.20;
mat2.ambientR = 0.00000;
mat2.ambientG = 0.00000;
mat2.ambientB = 0.00000;
mat2.specularR = 0.35;
mat2.specularG = 0.35;
mat2.specularB = 0.35;
mat2.shininess = 200.0;
mat2.diffuseR = 0.00;
mat2.diffuseG = 0.00;
mat2.diffuseB = 0.00;

tMaterial mat3 = new tMaterial();
mat3.alpha = 1.0;
mat3.ambientR = 0.2324;
mat3.ambientG = 0.2324;
mat3.ambientB = 0.3236;
mat3.specularR = 0.351;
mat3.specularG = 0.351;
mat3.specularB = 0.851;
mat3.shininess = 20;
mat3.diffuseR = 0.3775;
mat3.diffuseG = 0.3775;
mat3.diffuseB = 0.6775;

tMaterial mat4 = new tMaterial();
mat4.alpha = 1.0;
mat4.ambientR = 0.0124;
mat4.ambientG = 0.0124;
mat4.ambientB = 0.0136;
mat4.specularR = 0.451;
mat4.specularG = 0.451;
mat4.specularB = 0.451;
mat4.shininess = 2;
mat4.diffuseR = 0.0775;
mat4.diffuseG = 0.0775;
mat4.diffuseB = 0.0775;

tMaterial mat5 = new tMaterial();
mat5.alpha = 1.0;
mat5.ambientR = 0.39124;
mat5.ambientG = 0.39124;
mat5.ambientB = 0.39136;
mat5.specularR = 0.251;
mat5.specularG = 0.251;
mat5.specularB = 0.251;
mat5.shininess = 2;
mat5.diffuseR = 0.5775;
mat5.diffuseG = 0.5775;
mat5.diffuseB = 0.5775;

tMaterial mat6 = new tMaterial();
mat6.alpha = 1.0;
mat6.ambientR = 0.11124;
mat6.ambientG = 0.49124;
mat6.ambientB = 0.11136;
mat6.specularR = 0.151;
mat6.specularG = 0.651;
mat6.specularB = 0.151;
mat6.shininess = 35;
mat6.diffuseR = 0.1775;
mat6.diffuseG = 0.3775;
mat6.diffuseB = 0.1775;

tMaterial mat7 = new tMaterial();
mat7.alpha = 1.0;
mat7.ambientR = 0.23735;
mat7.ambientG = 0.23735;
mat7.ambientB = 0.23735;
mat7.specularR = 0.773911;
mat7.specularG = 0.773911;
mat7.specularB = 0.773911;
mat7.shininess = 89;
mat7.diffuseR = 0.2775;
mat7.diffuseG = 0.2775;
mat7.diffuseB = 0.2775;

ray.AddSphere(300, 300, 150, 150, mat1);
ray.AddSphere(0, 0, 150, 150, mat2);
ray.AddSphere(-300, 300, 150, 150, mat3);
ray.AddSphere(300, -300, 150, 150, mat6);
ray.AddSphere(-300, -300, 150, 150, mat7);

ray.AddTriangle(0, 500, 0, -500, 500, 0, -500, 0, 0, mat4);
ray.AddTriangle(0, 500, 0, -500, 0, 0, 0, 0, 0, mat4);
ray.AddTriangle(0, 0, 0, 0, -500, 0, 500, 0, 0, mat4);
ray.AddTriangle(500, 0, 0, 0, -500, 0, 500, -500, 0, mat4);
ray.AddTriangle(500, 500, 0, 0, 500, 0, 0, 0, 0, mat5);
ray.AddTriangle(500, 500, 0, 0, 0, 0, 500, 0, 0, mat5);
ray.AddTriangle(-500, 0, 0, -500, -500, 0, 0, 0, 0, mat5);
ray.AddTriangle(0, 0, 0, -500, -500, 0, 0, -500, 0, mat5);

ray.x0 = 0; ray.y0 = 0; ray.z0 = 2000;

tPoint color = new tPoint();
for (int i = rect.Left; i <= rect.Right; i++)
     {
     double x = tAlgebra.GetCoord(rect.Left, rect.Right,
               -fMax, fMax, i);
     for (int j = rect.Top; j <= rect.Bottom; j++)
          {
          double y = tAlgebra.GetCoord(rect.Top, rect.Bottom,
                           fMax, -fMax, j);
          ray.x1 = x; ray.y1 = y; ray.z1 = 0.0;
          color.x = 0; color.y = 0; color.z = 0;
          color = ray.trace_ray(ray);
          color.x = Math.Min(color.x, 255);
          color.y = Math.Min(color.y, 255);
          color.z = Math.Min(color.z, 255);
          color.x = Math.Max(color.x, 0);
          color.y = Math.Max(color.y, 0);
          color.z = Math.Max(color.z, 0);

          Color colorpx = Color.FromArgb((int)color.x,
                      (int)color.y, (int)color.z);
          Brush brs = new SolidBrush(colorpx);
          g.FillRectangle(brs, i, j, 1, 1);
          brs.Dispose();
         }
    }

MemoryStream tempStream = new MemoryStream();
newBitmap.Save(tempStream, ImageFormat.Png);
Response.ClearContent();
Response.ContentType = "image/png";
Response.BinaryWrite(tempStream.ToArray());
Response.Flush();

Points of Interest

When working with floating points we have computational issues for values near to zero, so in most of formulas we need to work with a small range around 0. Try to remove this from the code and see the results in the image.

For example if we have:

  • if(x>0.0) ...

it is required we do this:

  • double epsilon = 1.0E-K; // define a nice value for K

    if(Math.Abs(x)>epsilon) ...

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here