Want more features on Pastebin? Sign Up, it's FREE!
Guest

Ray Tracer

By: a guest on Apr 15th, 2010  |  syntax: C++  |  size: 11.42 KB  |  views: 233  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. #include <cmath>
  2. #include <cstdlib>
  3. #include <cstdio>
  4. #include <cassert>
  5. #include "textureData.h"
  6.  
  7. const int IMAGE_WIDTH = 64;
  8.  
  9. typedef struct Normal
  10. {
  11.         Normal() : x(0), y(0), z(0) {}
  12.         Normal(float xx) : x(xx), y(xx), z(xx) {}
  13.         Normal(float xx, float yy, float zz) : x(xx), y(yy), z(zz) {}
  14.         Normal operator * (const float &r) const
  15.         { return Normal(x*r, y*r, z*r); }
  16.         Normal operator - () const
  17.         { return Normal(-x, -y, -z); }
  18.         float x, y, z;
  19. };
  20.  
  21. typedef struct Vector
  22. {
  23.         Vector() : x(0), y(0), z(0) {}
  24.         Vector(float xx) : x(xx), y(xx), z(xx) {}
  25.         Vector(float xx, float yy, float zz) : x(xx), y(yy), z(zz) {}
  26.         Vector(const Normal &n) : x(n.x), y(n.y), z(n.z) {}
  27.         Vector cross(const Vector &v) const {return
  28.                 Vector((y*v.z)-(z*v.y),(z*v.x)-(x*v.z),(x*v.y)-(y*v.x)); }
  29.         float length() const { return sqrtf(x*x+y*y+z*z); }
  30.         float dot(const Vector &v) const { return x*v.x+y*v.y+z*v.z; }
  31.         Vector operator * (const float &r) const
  32.         { return Vector(x*r, y*r, z*r); }
  33.         float x, y, z;
  34.         Vector operator - (const Vector &v) const
  35.         { return Vector(x - v.x, y - v.y, z - v.z); }
  36.         Vector operator + (const Vector &v) const
  37.         { return Vector(x + v.x, y + v.y, z + v.z); }
  38.         Vector operator - () const
  39.         { return Vector(-x, -y, -z); }
  40.        
  41. };
  42.  
  43. typedef struct Point
  44. {
  45.         Point() : x(0), y(0), z(0) {}
  46.         Point(float xx) : x(xx), y(xx), z(xx) {}
  47.         Point(float xx, float yy, float zz) : x(xx), y(yy), z(zz) {}
  48.         Vector operator - (const Point &p) const
  49.         { return Vector(x - p.x, y - p.y, z - p.z); }
  50.         Point operator - (const Vector &v) const
  51.         { return Point(x - v.x, y - v.y, z - v.z); }
  52.         Point operator + (const Vector &v) const
  53.         { return Point(x+v.x, y+v.y, z+v.z); }
  54.         float x, y, z;
  55. };
  56.  
  57. void Normalize(Vector *v)
  58. {
  59.         float len2, lenInv;
  60.         len2 = v->x*v->x + v->y*v->y + v->z*v->z;
  61.         if (len2) {
  62.                 lenInv = 1.f/sqrtf(len2);
  63.                 v->x *= lenInv;
  64.                 v->y *= lenInv;
  65.                 v->z *= lenInv;
  66.         }
  67. }
  68.  
  69. typedef struct Color
  70. {
  71.         Color() : r(0), g(0), b(0) {}
  72.         Color(float rr) : r(rr), g(rr), b(rr) {}
  73.         Color(float rr, float gg, float bb) : r(rr), g(gg), b(bb) {}
  74.         Color operator * (const float &f) const { return Color(r * f, g * f, b * f); }
  75.         Color operator + (const Color &c) const
  76.         { return Color(r + c.r, g + c.g, b + c.b); }
  77.         Color operator * (const Color &c) const
  78.         { return Color(r * c.r, g * c.g, b * c.b); }
  79.         Color& operator *= (const Color &c)
  80.         { r *= c.r, g *= c.g, b *= c.b; return *this;}
  81.         Color& operator *= (const float &f)
  82.         { r *= f, g *= f, b *= f; return *this;}
  83.         float r, g, b;
  84. };
  85.  
  86. typedef struct Ray
  87. {
  88.         Vector direction;
  89.         Point origin;
  90. };
  91.  
  92. typedef enum MATERIAL_TYPE { MATTE, DIFFUSE, GLASS, TEXTDIF, TEXTMATTE };
  93.  
  94. typedef struct Object
  95. {
  96.         Object(const Point &c, const float &r,
  97.                    const Color &col = Color(1), MATERIAL_TYPE matType = MATTE,
  98.                    float l = 0,  float ior = 1.3) :
  99.         center(c), radius(r), radius2(r*r), color(col), materialType(matType),
  100.         isLight(l), indexOfRefraction(ior) {}
  101.         Point center;
  102.         float radius, radius2;
  103.         Color color;
  104.         MATERIAL_TYPE materialType;
  105.         int isLight;
  106.         float indexOfRefraction;
  107. };
  108.  
  109. Color getColor(const Object *object,const Ray *ray, float *t)
  110. {
  111.         if (object->materialType == TEXTDIF || object->materialType == TEXTMATTE) {
  112.                 float distance = *t;
  113.                 Point pnt = ray->origin + ray->direction * distance;
  114.                 Point oc = object->center;
  115.                 Vector ve = Point(oc.x,oc.y,oc.z+1) - oc;
  116.                 Normalize(&ve);
  117.                 Vector vn = Point(oc.x,oc.y+1,oc.z) - oc;
  118.                 Normalize(&vn);
  119.                 Vector vp = pnt - oc;
  120.                 Normalize(&vp);
  121.                
  122.                 double phi = acos(-vn.dot(vp));
  123.                
  124.                 float v = phi / M_PI;
  125.                 float u;
  126.                
  127.                 float num1 = (float)acos(vp.dot(ve));
  128.                 float num = (num1 /(float) sin(phi));
  129.                
  130.                 float theta = num /(float) (2 * M_PI);
  131.                 if (theta < 0 || theta == NAN) {theta = 0;}
  132.                 if (vn.cross(ve).dot(vp) > 0) {
  133.                         u = theta;
  134.                 }
  135.                 else {
  136.                         u = 1 - theta;
  137.                 }
  138.                 int x = (u * IMAGE_WIDTH) -1;
  139.                 int y = (v * IMAGE_WIDTH) -1;
  140.                 int p = (y * IMAGE_WIDTH + x)*3;
  141.                
  142.                 return Color(TEXT_DATA[p+2],TEXT_DATA[p+1],TEXT_DATA[p]);
  143.                
  144.         }
  145.         else {
  146.                 return object->color;
  147.         }
  148. };
  149.  
  150. typedef struct Light
  151. {
  152.         const Object *object;
  153. };
  154.  
  155.  
  156. static void computePrimRay(const int &i, const int &j, const int &imageWidth,
  157.                                                    const int &imageHeight, const float &frameAspectRatio, Ray *ray)
  158. {
  159.         float fov = 45;
  160.         float angle = tan(fov * 0.5f * M_PI / 180.0f);
  161.         ray->origin = Point(0);
  162.         float dx = 2 * frameAspectRatio/(float)imageWidth;
  163.         float dy = 2 / (float)imageHeight;
  164.         ray->direction.x = angle * ((i + 0.5) * dx - frameAspectRatio);
  165.         ray->direction.y = angle * (-(j + 0.5) * dy + 1);
  166.         ray->direction.z = 1;
  167.         Normalize(&ray->direction);
  168. }
  169.  
  170. int Intersect(const Object *object, const Ray *ray, float *t)
  171. {
  172.         // use geometric method
  173.         Vector oc = object->center - ray->origin;
  174.         // square distance to center of sphere
  175.         float oc2 = oc.dot(oc);
  176.         // distance to point on ray closest to sphere center
  177.         float tca = oc.dot(ray->direction);
  178.        
  179.         bool outside = oc2 > object->radius2;
  180.         if (tca < 0 && outside) return 0;
  181.        
  182.         // square distance from sphere center to closest point on ray
  183.         float d2 = oc2 - tca*tca;
  184.         // square distance from perpendicular bisector to center
  185.         float thc = object->radius2 - d2;
  186.        
  187.         if (thc < 0)
  188.                 return 0;
  189.         if (outside)
  190.                 *t = tca - sqrtf(thc);
  191.         else
  192.                 *t = tca + sqrtf(thc);
  193.        
  194.         if (*t < 0) return 0;
  195.         return 1;
  196. }
  197.  
  198. #ifdef INFINITY
  199. #undef INFINITY
  200. #endif
  201. #define INFINITY 1e6
  202.  
  203. #define MAX_DEPTH_LEVEL 3
  204.  
  205. void snell(
  206.                    const Vector &incidentRay,
  207.                    const Normal &surfaceNormal,
  208.                    const double &n1,
  209.                    const double &n2,
  210.                    Vector *reflectionDir,
  211.                    Vector *refractionDir )
  212. {
  213.         float n1n2 = n1 / n2;
  214.         float cost1 = incidentRay.dot(surfaceNormal);
  215.         float cost2 = sqrt(1.0 - (n1n2 * n1n2) * (1.0 - cost1 * cost1));
  216.         *reflectionDir = incidentRay - surfaceNormal * (2 * cost1);
  217.         *refractionDir = incidentRay * n1n2 + surfaceNormal * (cost2 - n1n2 * cost1);
  218. }
  219.  
  220. void fresnel( const float &etai, const float &etat, const float &cosi,
  221.                          const float &cost, float *Kr )
  222. {
  223.         float Rp = ((etat * cosi) - (etai * cost)) / ((etat * cosi) + (etai * cost));
  224.         float Rs = ((etai * cosi) - (etat * cost)) / ((etai * cosi) + (etat * cost));
  225.         *Kr = ( Rp*Rp + Rs*Rs ) * .5;
  226. }
  227.  
  228. static Color Trace(
  229.                                    const Ray *ray,
  230.                                    const int &depth,
  231.                                    const Object **objects,
  232.                                    const int &numObjects,
  233.                                    const Light *light,
  234.                                    const Color &bgColor)
  235. {
  236.         if (depth > MAX_DEPTH_LEVEL) {
  237.                 return bgColor;
  238.         }
  239.        
  240.         float bias = 0.001;
  241.         const Object *object = NULL;
  242.         float minDistance = INFINITY;
  243.         Point pHit;
  244.         Normal nHit;
  245.         float t;
  246.         for (int k = 0; k < numObjects; k++) {
  247.                 if (Intersect(objects[k], ray, &t)) {
  248.                         if (t < minDistance) {
  249.                                 minDistance = t;
  250.                                 object = objects[k];
  251.                         }
  252.                 }
  253.         }
  254.         if (object == NULL)
  255.                 return bgColor;
  256.        
  257.         pHit = ray->origin + ray->direction * minDistance;
  258.         nHit.x = pHit.x - object->center.x;
  259.         nHit.y = pHit.y - object->center.y;
  260.         nHit.z = pHit.z - object->center.z;
  261.         Normalize((Vector*)&nHit);
  262.        
  263.         if (object->materialType == GLASS) {
  264.                 // compute reflection and refraction direction
  265.                 Ray reflectionRay, refractionRay;
  266.                 reflectionRay.origin = pHit + nHit * bias;
  267.                 refractionRay.origin = pHit - nHit * bias;
  268.                 snell(ray->direction, -nHit, 1.0, object->indexOfRefraction,
  269.                           &reflectionRay.direction, &refractionRay.direction);
  270.                 Normalize(&reflectionRay.direction);
  271.                 Normalize(&refractionRay.direction);
  272.                 float cosi = ray->direction.dot(-nHit);
  273.                 float cost = refractionRay.direction.dot(-nHit);
  274.                 float Kr;
  275.                 fresnel(1.0, object->indexOfRefraction, cosi, cost, &Kr);
  276.                 if (Kr < 0)
  277.                         Kr = 0;
  278.                 if (Kr > 1)
  279.                         Kr = 1;
  280.                 Color reflectionColor = Trace(&reflectionRay, depth + 1, objects,
  281.                                                                           numObjects, light, bgColor);
  282.                 Color refractionColor = Trace(&refractionRay, depth + 1, objects,
  283.                                                                           numObjects, light, bgColor);
  284.                 return object->color * refractionColor * (1-Kr) + reflectionColor * Kr;
  285.         }
  286.        
  287.         if (object->materialType == MATTE)
  288.                 return getColor(object, ray, &t);
  289.        
  290.         Ray shadowRay;
  291.         int isInShadow = 0;
  292.         shadowRay.origin.x = pHit.x + nHit.x * bias;
  293.         shadowRay.origin.y = pHit.y + nHit.y * bias;
  294.         shadowRay.origin.z = pHit.z + nHit.z * bias;
  295.         shadowRay.direction = light->object->center - pHit;
  296.         float len = shadowRay.direction.length();
  297.         Normalize(&shadowRay.direction);
  298.         float LdotN = shadowRay.direction.dot(nHit);
  299.         if (LdotN < 0)
  300.                 return 0;
  301.         Color lightColor = light->object->color;
  302.         for (int k = 0; k < numObjects; k++) {
  303.                 if (Intersect(objects[k], &shadowRay, &t) && !objects[k]->isLight) {
  304.                         if (objects[k]->materialType == GLASS)
  305.                                 lightColor *= getColor(objects[k], &shadowRay, &t); // attenuate light color by glass color
  306.                         else
  307.                                 isInShadow = 1;
  308.                         break;
  309.                 }
  310.         }
  311.         lightColor *= 1.f/(len*len);
  312.         return (isInShadow) ? 0 : getColor(object, &shadowRay, &t) * lightColor * LdotN;
  313. }
  314.  
  315. #define MAX_OBJECTS 4
  316.  
  317. static const Object* createNewObject(const Point &p, const float &r,
  318.                                                                          const Color &col, MATERIAL_TYPE matType, int isLight, Object **&objects,
  319.                                                                          int &numObjects)
  320. {
  321.         assert(numObjects <= MAX_OBJECTS);
  322.         Object *object = new Object(p, r, col, matType, isLight);
  323.         objects[numObjects] = object;
  324.         numObjects++;
  325.         return object;
  326. }
  327.  
  328. int main (int argc, char * const argv[])
  329. {
  330.         static const int imageWidth = 640;
  331.         static const int imageHeight = 480;
  332.        
  333.         // scene data (objects/light)
  334.         Object **objects = new Object*[MAX_OBJECTS];
  335.         int numObjects = 0;
  336.         createNewObject(
  337.                                         Point(0, 0, 15), 3, Color(.5, .7, .5), GLASS, 0, objects, numObjects);
  338.         createNewObject(
  339.                                         Point(-4.5, 4.5, 17), 1.8, Color(1, .3, .3), TEXTDIF, 0, objects, numObjects);
  340.         createNewObject(
  341.                                         Point(2, -2, 19), 2, Color(.3, 1, .3), DIFFUSE, 0, objects, numObjects);
  342.         Light light;
  343.         light.object = createNewObject(
  344.                                                                    Point(3, 3, 13), .5, Color(50), MATTE, 1, objects, numObjects);
  345.        
  346.         // main render loop
  347.         assert(imageWidth >= imageHeight);
  348.         float frameAspectRatio = imageWidth/(float)imageHeight;
  349.         Color **pixels;
  350.         pixels = new Color*[imageWidth];
  351.         Color bgColor(0.5f, 0.62f, 0.78f);
  352.         for (int i = 0; i < imageWidth; ++i)
  353.                 pixels[i] = new Color[imageHeight];
  354.         for (int j = 0; j < imageHeight; ++j) {
  355.                 for (int i = 0; i < imageWidth; ++i) {
  356.                         // compute primary ray direction
  357.                         Ray primRay;
  358.                         computePrimRay(i, j, imageWidth, imageHeight, frameAspectRatio, &primRay);
  359.                         pixels[i][j] = Trace(&primRay, 0, (const Object**)objects, numObjects,
  360.                                                                  &light, bgColor);
  361.                         // clamp
  362.                         if (pixels[i][j].r > 1.f) pixels[i][j].r = 1.f;
  363.                         if (pixels[i][j].g > 1.f) pixels[i][j].g = 1.f;
  364.                         if (pixels[i][j].b > 1.f) pixels[i][j].b = 1.f;
  365.                 }
  366.         }
  367.        
  368.         // save to disk
  369.         FILE *fp;
  370.         fp = fopen("./raytrace.ppm", "w");
  371.         if (fp != NULL) {
  372.                 fprintf(fp, "%s\n", "P6");
  373.                 fprintf(fp, "%d %d\n", imageWidth, imageHeight);
  374.                 fprintf(fp, "%d\n", 255);
  375.                 char r, g, b;
  376.                 float gamma = 1; // mac
  377.                 for (int j = 0; j < imageHeight; ++j) {
  378.                         for (int i = 0; i < imageWidth; ++i) {
  379.                                 pixels[i][j].r = 255 * powf(pixels[i][j].r, gamma);
  380.                                 pixels[i][j].g = 255 * powf(pixels[i][j].g, gamma);
  381.                                 pixels[i][j].b = 255 * powf(pixels[i][j].b, gamma);
  382.                                 r = (pixels[i][j].r > 255) ? 255 : pixels[i][j].r;
  383.                                 g = (pixels[i][j].g > 255) ? 255 : pixels[i][j].g;
  384.                                 b = (pixels[i][j].b > 255) ? 255 : pixels[i][j].b;
  385.                                 fprintf(fp, "%c%c%c", r, g, b);
  386.                         }
  387.                 }
  388.                 fclose(fp);
  389.         }
  390.        
  391.         // free memory
  392.         for (int i = 0; i < imageWidth; ++i)
  393.                 delete [] pixels[i];
  394.         delete [] pixels;
  395.         for (int i = 0; i < numObjects; ++i)
  396.                 delete objects[i];
  397.         delete [] objects;
  398.         return 0;
  399. }
clone this paste RAW Paste Data