Advertisement
Guest User

Ray Tracer

a guest
Apr 15th, 2010
461
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.42 KB | None | 0 0
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement