Guest User

Untitled

a guest
Jan 19th, 2018
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.00 KB | None | 0 0
  1. #include <iostream>
  2. #include <cstring>
  3. #include <getopt.h>
  4. #include <stdio.h>
  5. #include <cmath>
  6. #include <cstdlib>
  7. #include <string>
  8.  
  9. #include "sys/tasking.hpp"
  10. #include "sys/ref.hpp"
  11. #include "sys/thread.hpp"
  12. #include "sys/mutex.hpp"
  13. #include "sys/sysinfo.hpp"
  14.  
  15. //! Short command line options for get_opt
  16. static const char * SHORT_OPTIONS = "hvo:r:s:";
  17. //! Long options for getopt_long
  18. static const struct option LONG_OPTIONS[]=
  19. {
  20.     {"help",no_argument,NULL,'h'}, // Print help
  21.     {"verbose",no_argument,NULL,'v'}, // Verbose mode
  22.     {"output",required_argument,NULL,'o'}, // Verbose mode
  23.     {"resolution",required_argument,NULL,'r'}, // Verbose mode
  24.     {"samples",required_argument,NULL,'s'}, // Verbose mode
  25.     {NULL, 0, NULL, 0} // End of array need by getopt_long do not delete it
  26. };
  27.  
  28. namespace brute
  29. {
  30.     //! Handle command line options
  31.     struct Options
  32.     {
  33.         bool verbose;
  34.         unsigned int width;
  35.         unsigned int height;
  36.         unsigned int samples;
  37.         std::string outputFile;
  38.     };
  39.     //! Parse command line options and fill BruteOptions structure
  40.     void parseArgs(int argc, char **argv, Options & options);
  41.     //! Print usage on standard output
  42.     void usage();
  43.  
  44.     //! Basic vector
  45.     struct Vec
  46.     {
  47.         //! position, also color (r,g,b)
  48.         double x, y, z, w;
  49.         Vec(double x_=0, double y_=0, double z_=0){ x=x_; y=y_; z=z_; w = 1.0;}
  50.         Vec operator+(const Vec &b) const { return Vec(x+b.x,y+b.y,z+b.z); }
  51.         Vec operator-(const Vec &b) const { return Vec(x-b.x,y-b.y,z-b.z); }
  52.         Vec operator*(double b) const { return Vec(x*b,y*b,z*b); }
  53.         Vec mult(const Vec &b) const { return Vec(x*b.x,y*b.y,z*b.z); }
  54.         Vec& norm(){ return *this = *this * (1/sqrt(x*x+y*y+z*z)); }
  55.         double dot(const Vec &b) const { return x*b.x+y*b.y+z*b.z; } // cross:
  56.         Vec operator%(Vec&b){return Vec(y*b.z-z*b.y,z*b.x-x*b.z,x*b.y-y*b.x);}
  57.     };
  58.  
  59.     //! Ray structure
  60.     struct Ray
  61.     {
  62.         //! Origin
  63.         Vec o;
  64.         //! Direction
  65.         Vec d;
  66.         Ray(Vec o_, Vec d_) : o(o_), d(d_) {}
  67.     };
  68.  
  69.     //! Material types, used in radiance()
  70.     enum Refl_t { DIFF, SPEC, REFR };
  71.  
  72.     //! Sphere structure
  73.     struct Sphere
  74.     {
  75.         //! Radius
  76.         double rad;
  77.         //! Position
  78.         Vec p;
  79.         //! Emission
  80.         Vec e;
  81.         //! Color
  82.         Vec c;
  83.         //! Reflection type (DIFFuse, SPECular, REFRactive)
  84.         Refl_t refl;
  85.         Sphere(double rad_, Vec p_, Vec e_, Vec c_, Refl_t refl_):
  86.             rad(rad_), p(p_), e(e_), c(c_), refl(refl_) {}
  87.         //! Returns distance, 0 if nohit
  88.         double intersect(const Ray &r) const
  89.             {
  90.                 Vec op = p-r.o; // Solve t^2*d.d + 2*t*(o-p).d + (o-p).(o-p)-R^2 = 0
  91.                 double t, eps=1e-4, b=op.dot(r.d), det=b*b-op.dot(op)+rad*rad;
  92.                 if (det<0) return 0; else det=sqrt(det);
  93.                 return (t=b-det)>eps ? t : ((t=b+det)>eps ? t : 0);
  94.             }
  95.     };
  96.  
  97.     //! Scene structure
  98.     struct Scene
  99.     {
  100.         //! Number of objects
  101.         unsigned int n;
  102.         //! Sphere array
  103.         Sphere * spheres;
  104.     };
  105.  
  106.     //! Clamp real between 0:1
  107.     inline double clamp(double x){ return x<0.0 ? 0.0 : x>1.0 ? 1.0 : x; }
  108.     //! Cast double to int
  109.     inline int toInt(double x){ return int(pow(clamp(x),1/2.2)*255+.5); }
  110.     //! Intersect ray with scene
  111.     bool intersect(const Scene & scene,  const Ray &r, double &t, int &id);
  112.     //! Accumulate radiance along a ray
  113.     Vec radiance(const Scene & scene, const Ray &r_, int depth_, unsigned short *Xi);
  114.     //! Rendering loop
  115.     void mainLoop(const Options & opts, const Scene & scene);
  116. }
  117. using namespace brute;
  118.  
  119.  
  120. int main(int argc, char **argv)
  121. {
  122.  
  123.     brute::Options options;
  124.     brute::parseArgs(argc, argv, options);
  125.  
  126.     //!Scene: radius, position, emission, color, material
  127.     Sphere spheres[] =
  128.         {
  129.             Sphere(1e5, Vec( 1e5+1,40.8,81.6), Vec(),Vec(.75,.25,.25),DIFF),//Left
  130.             Sphere(1e5, Vec(-1e5+99,40.8,81.6),Vec(),Vec(.25,.25,.75),DIFF),//Rght
  131.             Sphere(1e5, Vec(50,40.8, 1e5),     Vec(),Vec(.75,.75,.75),DIFF),//Back
  132.             Sphere(1e5, Vec(50,40.8,-1e5+170), Vec(),Vec(),           DIFF),//Frnt
  133.             Sphere(1e5, Vec(50, 1e5, 81.6),    Vec(),Vec(.75,.75,.75),DIFF),//Botm
  134.             Sphere(1e5, Vec(50,-1e5+81.6,81.6),Vec(),Vec(.75,.75,.75),DIFF),//Top
  135.             Sphere(16.5,Vec(27,16.5,47),       Vec(),Vec(1,1,1)*.999, SPEC),//Mirr
  136.             Sphere(16.5,Vec(73,16.5,78),       Vec(),Vec(1,1,1)*.999, REFR),//Glas
  137.             Sphere(600, Vec(50,681.6-.27,81.6),Vec(12,12,12),  Vec(), DIFF) //Ligt
  138.         };
  139.     Scene scene =
  140.         {
  141.             9,
  142.             spheres
  143.         };
  144.  
  145.     brute::mainLoop(options, scene);
  146. }
  147.  
  148. namespace brute
  149. {
  150.     void parseArgs(int argc, char **argv, Options & options)
  151.     {
  152.         char c;
  153.         int optIdx;
  154.         options.outputFile = "";
  155.         options.width = 0;
  156.         options.height = 0;
  157.         options.samples = 0;
  158.         while ((c = getopt_long(argc, argv, SHORT_OPTIONS, LONG_OPTIONS, &optIdx)) != -1)
  159.         {
  160.             switch (c)
  161.             {
  162.             case 'h' : // Help
  163.                 usage();
  164.                 exit(1);
  165.                 break;
  166.             case 'v' : // Verbose
  167.                 options.verbose = true;
  168.                 break;
  169.             case 'o' : // Output file
  170.                 options.outputFile = optarg;
  171.                 break;
  172.             case 's' : // Number of samples per pixel
  173.                 options.samples = atoi(optarg);
  174.                 break;
  175.             case 'r' : // Width x Height
  176.                 sscanf(optarg, "%dx%d", &options.width, &options.height);
  177.                 break;
  178.             case '?' : // Wut?
  179.                 std::cerr << "Unknown option" << std::endl;
  180.                 usage();
  181.                 exit(1);
  182.             default :
  183.                 break;
  184.             }
  185.         }
  186.         // Defaults
  187.         if (options.outputFile.empty())
  188.             options.outputFile = "image.ppm";
  189.         if (!options.width)
  190.             options.width = 512;
  191.         if (!options.height)
  192.             options.height = 384;
  193.         if (!options.samples)
  194.             options.samples = 1;
  195.  
  196.     }
  197.  
  198.     void usage()
  199.     {
  200.         std::cout << "brute [-hv] \n\t--output=output_file\n\t--resolution=WxH\n\t--samples=N" << std::endl;
  201.     }
  202.  
  203.  
  204.     class LineTask : public pf::Task
  205.     {
  206.     public :
  207.         LineTask(const Scene & scene, Ray cam, Vec cx, Vec cy, Vec * c, int samps, int line, int w, int h);
  208.         virtual pf::Task * run(void);
  209.     private :
  210.         const Scene & scene;
  211.         Ray cam;
  212.         Vec cx;
  213.         Vec cy;
  214.         Vec * c;
  215.         int samps;
  216.         int line;
  217.         int w;
  218.         int h;
  219.     };
  220.  
  221.     LineTask::LineTask(const Scene & scene, Ray cam, Vec cx, Vec cy, Vec * c, int samps, int line, int w, int h)
  222.         : Task("LineTask"), scene(scene), cam(cam), cx(cx), cy(cy), c(c), samps(samps), line(line), w(w), h(h)
  223.     {
  224.     }
  225.  
  226.     pf::Task * LineTask::run()
  227.     {
  228.         //printf("RUNNING %d\n", line);
  229.         Vec r;
  230.         int y = line;
  231.         // Loop cols
  232.         for (unsigned short x=0, Xi[3]={0,0,y*y*y}; x<w; x++)
  233.         {
  234.             // 2x2 subpixel rows
  235.             for (int sy=0, i=(h-y-1)*w+x; sy<2; sy++)
  236.             {
  237.                 // 2x2 subpixel cols
  238.                 for (int sx=0; sx<2; sx++, r=Vec())
  239.                 {
  240.                     for (int s=0; s<samps; s++)
  241.                     {
  242.                         double r1=2*erand48(Xi), dx=r1<1 ? sqrt(r1)-1: 1-sqrt(2-r1);
  243.                         double r2=2*erand48(Xi), dy=r2<1 ? sqrt(r2)-1: 1-sqrt(2-r2);
  244.                         Vec d = cx*( ( (sx+.5 + dx)/2 + x)/w - .5) +
  245.                             cy*( ( (sy+.5 + dy)/2 + y)/h - .5) + cam.d;
  246.                         r = r + radiance(scene, Ray(cam.o+d*140,d.norm()),0,Xi)*(1./samps);
  247.                     }
  248.                     // Camera rays are pushed ^^^^^ forward to start in interior
  249.                     c[i] = c[i] + Vec(clamp(r.x),clamp(r.y),clamp(r.z))*.25;
  250.                 }
  251.             }
  252.         }
  253.         //printf("STOPPED %d\n", line);
  254.         return 0;
  255.     }
  256.  
  257.     class DoneTask : public pf::Task {
  258.     public:
  259.         virtual pf::Task* run(void) { pf::TaskingSystemInterrupt(); return NULL; }
  260.     };
  261.  
  262.     //! Rendering loop
  263.     void mainLoop(const Options & opts, const Scene & scene)
  264.     {
  265.         int w=opts.width;
  266.         int h=opts.height;
  267.         // # samples
  268.         int samps = opts.samples;
  269.         // Camera position, direction
  270.         Ray cam(Vec(50,52,295.6), Vec(0,-0.042612,-1).norm());
  271.         Vec cx=Vec(w*.5135/h);
  272.         Vec cy=(cx%cam.d).norm()*.5135;
  273.         Vec r;
  274.         Vec * c=new Vec[w*h];
  275.         // Loop over image rows
  276.         pf::TaskingSystemStart();
  277.         pf::Task * done = PF_NEW(DoneTask);
  278.         for (int y=0; y<h; y++)
  279.         {
  280.             pf::Ref<LineTask> line = PF_NEW(LineTask, scene, cam, cx, cy, c, samps, y, w, h);
  281.             line->starts(done);
  282.             line->scheduled();
  283.         }
  284.         done->starts(0);
  285.         done->scheduled();
  286.         printf("Num threads %d\n", pf::TaskingSystemGetThreadNum());
  287.         pf::TaskingSystemEnter();
  288.         pf::TaskingSystemEnd();
  289.         FILE *f = fopen(opts.outputFile.c_str(), "w");         // Write image to PPM file.
  290.         fprintf(f, "P3\n%d %d\n%d\n", w, h, 255);
  291.         for (int i=0; i<w*h; i++)
  292.             fprintf(f,"%d %d %d ", toInt(c[i].x), toInt(c[i].y), toInt(c[i].z));
  293.     }
  294.  
  295.     //! Accumulate radiance along a ray
  296.     Vec radiance(const Scene & scene, const Ray &r_, int depth_, unsigned short *Xi)
  297.     {
  298.         double t;                               // distance to intersection
  299.         int id=0;                               // id of intersected object
  300.         Ray r=r_;
  301.         int depth=depth_;
  302.         // L0 = Le0 + f0*(L1)
  303.         //    = Le0 + f0*(Le1 + f1*L2)
  304.         //    = Le0 + f0*(Le1 + f1*(Le2 + f2*(L3))
  305.         //    = Le0 + f0*(Le1 + f1*(Le2 + f2*(Le3 + f3*(L4)))
  306.         //    = ...
  307.         //    = Le0 + f0*Le1 + f0*f1*Le2 + f0*f1*f2*Le3 + f0*f1*f2*f3*Le4 + ...
  308.         //
  309.         // So:
  310.         // F = 1
  311.         // while (1){
  312.         //   L += F*Lei
  313.         //   F *= fi
  314.         // }
  315.         Vec cl(0,0,0);   // accumulated color
  316.         Vec cf(1,1,1);  // accumulated reflectance
  317.         while (1)
  318.         {
  319.             if (!intersect(scene, r, t, id))  // if miss, return black
  320.                 return cl;
  321.             const Sphere &obj = scene.spheres[id];        // the hit object
  322.             Vec x=r.o+r.d*t;
  323.             Vec n=(x-obj.p).norm();
  324.             Vec nl=n.dot(r.d)<0?n:n*-1;
  325.             Vec f=obj.c;
  326.             double p = f.x>f.y && f.x>f.z ? f.x : f.y>f.z ? f.y : f.z; // max refl
  327.             cl = cl + cf.mult(obj.e);
  328.             if (++depth>5)
  329.             {
  330.                 if (erand48(Xi)<p)
  331.                 {
  332.                     f=f*(1/p);
  333.                 }
  334.                 else
  335.                 {
  336.                     return cl; //R.R.
  337.                 }
  338.             }
  339.             cf = cf.mult(f);
  340.             if (obj.refl == DIFF) // Ideal DIFFUSE reflection
  341.             {
  342.                 double r1=2*M_PI*erand48(Xi), r2=erand48(Xi), r2s=sqrt(r2);
  343.                 Vec w=nl, u=((fabs(w.x)>.1?Vec(0,1):Vec(1))%w).norm(), v=w%u;
  344.                 Vec d = (u*cos(r1)*r2s + v*sin(r1)*r2s + w*sqrt(1-r2)).norm();
  345.                 r = Ray(x,d);
  346.                 continue;
  347.             }
  348.             else if (obj.refl == SPEC) // Ideal SPECULAR reflection
  349.             {
  350.                 r = Ray(x,r.d-n*2*n.dot(r.d));
  351.                 continue;
  352.             }
  353.             Ray reflRay(x, r.d-n*2*n.dot(r.d));     // Ideal dielectric REFRACTION
  354.             bool into = n.dot(nl)>0;                // Ray from outside going in?
  355.             double nc=1, nt=1.5, nnt=into?nc/nt:nt/nc, ddn=r.d.dot(nl), cos2t;
  356.             if ((cos2t=1-nnt*nnt*(1-ddn*ddn))<0) // Total internal reflection
  357.             {
  358.                 r = reflRay;
  359.                 continue;
  360.             }
  361.             Vec tdir = (r.d*nnt - n*((into?1:-1)*(ddn*nnt+sqrt(cos2t)))).norm();
  362.             double a=nt-nc, b=nt+nc, R0=a*a/(b*b), c = 1-(into?-ddn:tdir.dot(n));
  363.             double Re=R0+(1-R0)*c*c*c*c*c,Tr=1-Re,P=.25+.5*Re,RP=Re/P,TP=Tr/(1-P);
  364.             if (erand48(Xi)<P)
  365.             {
  366.                 cf = cf*RP;
  367.                 r = reflRay;
  368.             }
  369.             else
  370.             {
  371.                 cf = cf*TP;
  372.                 r = Ray(x,tdir);
  373.             }
  374.             continue;
  375.         }
  376.     }
  377.  
  378.     bool intersect(const Scene & scene,  const Ray &r, double &t, int &id)
  379.     {
  380.         double n = scene.n;
  381.         double d;
  382.         double inf=t=1e20;
  383.         Sphere * spheres = scene.spheres;
  384.         for(int i=int(n);i--;)
  385.         {
  386.             if((d=spheres[i].intersect(r))&&d<t)
  387.             {
  388.                 t=d;
  389.                 id=i;
  390.             }
  391.         }
  392.         return t<inf;
  393.     }
  394.  
  395. }
Add Comment
Please, Sign In to add comment