Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <cstring>
- #include <getopt.h>
- #include <stdio.h>
- #include <cmath>
- #include <cstdlib>
- #include <string>
- #include "sys/tasking.hpp"
- #include "sys/ref.hpp"
- #include "sys/thread.hpp"
- #include "sys/mutex.hpp"
- #include "sys/sysinfo.hpp"
- //! Short command line options for get_opt
- static const char * SHORT_OPTIONS = "hvo:r:s:";
- //! Long options for getopt_long
- static const struct option LONG_OPTIONS[]=
- {
- {"help",no_argument,NULL,'h'}, // Print help
- {"verbose",no_argument,NULL,'v'}, // Verbose mode
- {"output",required_argument,NULL,'o'}, // Verbose mode
- {"resolution",required_argument,NULL,'r'}, // Verbose mode
- {"samples",required_argument,NULL,'s'}, // Verbose mode
- {NULL, 0, NULL, 0} // End of array need by getopt_long do not delete it
- };
- namespace brute
- {
- //! Handle command line options
- struct Options
- {
- bool verbose;
- unsigned int width;
- unsigned int height;
- unsigned int samples;
- std::string outputFile;
- };
- //! Parse command line options and fill BruteOptions structure
- void parseArgs(int argc, char **argv, Options & options);
- //! Print usage on standard output
- void usage();
- //! Basic vector
- struct Vec
- {
- //! position, also color (r,g,b)
- double x, y, z, w;
- Vec(double x_=0, double y_=0, double z_=0){ x=x_; y=y_; z=z_; w = 1.0;}
- Vec operator+(const Vec &b) const { return Vec(x+b.x,y+b.y,z+b.z); }
- Vec operator-(const Vec &b) const { return Vec(x-b.x,y-b.y,z-b.z); }
- Vec operator*(double b) const { return Vec(x*b,y*b,z*b); }
- Vec mult(const Vec &b) const { return Vec(x*b.x,y*b.y,z*b.z); }
- Vec& norm(){ return *this = *this * (1/sqrt(x*x+y*y+z*z)); }
- double dot(const Vec &b) const { return x*b.x+y*b.y+z*b.z; } // cross:
- Vec operator%(Vec&b){return Vec(y*b.z-z*b.y,z*b.x-x*b.z,x*b.y-y*b.x);}
- };
- //! Ray structure
- struct Ray
- {
- //! Origin
- Vec o;
- //! Direction
- Vec d;
- Ray(Vec o_, Vec d_) : o(o_), d(d_) {}
- };
- //! Material types, used in radiance()
- enum Refl_t { DIFF, SPEC, REFR };
- //! Sphere structure
- struct Sphere
- {
- //! Radius
- double rad;
- //! Position
- Vec p;
- //! Emission
- Vec e;
- //! Color
- Vec c;
- //! Reflection type (DIFFuse, SPECular, REFRactive)
- Refl_t refl;
- Sphere(double rad_, Vec p_, Vec e_, Vec c_, Refl_t refl_):
- rad(rad_), p(p_), e(e_), c(c_), refl(refl_) {}
- //! Returns distance, 0 if nohit
- double intersect(const Ray &r) const
- {
- Vec op = p-r.o; // Solve t^2*d.d + 2*t*(o-p).d + (o-p).(o-p)-R^2 = 0
- double t, eps=1e-4, b=op.dot(r.d), det=b*b-op.dot(op)+rad*rad;
- if (det<0) return 0; else det=sqrt(det);
- return (t=b-det)>eps ? t : ((t=b+det)>eps ? t : 0);
- }
- };
- //! Scene structure
- struct Scene
- {
- //! Number of objects
- unsigned int n;
- //! Sphere array
- Sphere * spheres;
- };
- //! Clamp real between 0:1
- inline double clamp(double x){ return x<0.0 ? 0.0 : x>1.0 ? 1.0 : x; }
- //! Cast double to int
- inline int toInt(double x){ return int(pow(clamp(x),1/2.2)*255+.5); }
- //! Intersect ray with scene
- bool intersect(const Scene & scene, const Ray &r, double &t, int &id);
- //! Accumulate radiance along a ray
- Vec radiance(const Scene & scene, const Ray &r_, int depth_, unsigned short *Xi);
- //! Rendering loop
- void mainLoop(const Options & opts, const Scene & scene);
- }
- using namespace brute;
- int main(int argc, char **argv)
- {
- brute::Options options;
- brute::parseArgs(argc, argv, options);
- //!Scene: radius, position, emission, color, material
- Sphere spheres[] =
- {
- Sphere(1e5, Vec( 1e5+1,40.8,81.6), Vec(),Vec(.75,.25,.25),DIFF),//Left
- Sphere(1e5, Vec(-1e5+99,40.8,81.6),Vec(),Vec(.25,.25,.75),DIFF),//Rght
- Sphere(1e5, Vec(50,40.8, 1e5), Vec(),Vec(.75,.75,.75),DIFF),//Back
- Sphere(1e5, Vec(50,40.8,-1e5+170), Vec(),Vec(), DIFF),//Frnt
- Sphere(1e5, Vec(50, 1e5, 81.6), Vec(),Vec(.75,.75,.75),DIFF),//Botm
- Sphere(1e5, Vec(50,-1e5+81.6,81.6),Vec(),Vec(.75,.75,.75),DIFF),//Top
- Sphere(16.5,Vec(27,16.5,47), Vec(),Vec(1,1,1)*.999, SPEC),//Mirr
- Sphere(16.5,Vec(73,16.5,78), Vec(),Vec(1,1,1)*.999, REFR),//Glas
- Sphere(600, Vec(50,681.6-.27,81.6),Vec(12,12,12), Vec(), DIFF) //Ligt
- };
- Scene scene =
- {
- 9,
- spheres
- };
- brute::mainLoop(options, scene);
- }
- namespace brute
- {
- void parseArgs(int argc, char **argv, Options & options)
- {
- char c;
- int optIdx;
- options.outputFile = "";
- options.width = 0;
- options.height = 0;
- options.samples = 0;
- while ((c = getopt_long(argc, argv, SHORT_OPTIONS, LONG_OPTIONS, &optIdx)) != -1)
- {
- switch (c)
- {
- case 'h' : // Help
- usage();
- exit(1);
- break;
- case 'v' : // Verbose
- options.verbose = true;
- break;
- case 'o' : // Output file
- options.outputFile = optarg;
- break;
- case 's' : // Number of samples per pixel
- options.samples = atoi(optarg);
- break;
- case 'r' : // Width x Height
- sscanf(optarg, "%dx%d", &options.width, &options.height);
- break;
- case '?' : // Wut?
- std::cerr << "Unknown option" << std::endl;
- usage();
- exit(1);
- default :
- break;
- }
- }
- // Defaults
- if (options.outputFile.empty())
- options.outputFile = "image.ppm";
- if (!options.width)
- options.width = 512;
- if (!options.height)
- options.height = 384;
- if (!options.samples)
- options.samples = 1;
- }
- void usage()
- {
- std::cout << "brute [-hv] \n\t--output=output_file\n\t--resolution=WxH\n\t--samples=N" << std::endl;
- }
- class LineTask : public pf::Task
- {
- public :
- LineTask(const Scene & scene, Ray cam, Vec cx, Vec cy, Vec * c, int samps, int line, int w, int h);
- virtual pf::Task * run(void);
- private :
- const Scene & scene;
- Ray cam;
- Vec cx;
- Vec cy;
- Vec * c;
- int samps;
- int line;
- int w;
- int h;
- };
- LineTask::LineTask(const Scene & scene, Ray cam, Vec cx, Vec cy, Vec * c, int samps, int line, int w, int h)
- : Task("LineTask"), scene(scene), cam(cam), cx(cx), cy(cy), c(c), samps(samps), line(line), w(w), h(h)
- {
- }
- pf::Task * LineTask::run()
- {
- //printf("RUNNING %d\n", line);
- Vec r;
- int y = line;
- // Loop cols
- for (unsigned short x=0, Xi[3]={0,0,y*y*y}; x<w; x++)
- {
- // 2x2 subpixel rows
- for (int sy=0, i=(h-y-1)*w+x; sy<2; sy++)
- {
- // 2x2 subpixel cols
- for (int sx=0; sx<2; sx++, r=Vec())
- {
- for (int s=0; s<samps; s++)
- {
- double r1=2*erand48(Xi), dx=r1<1 ? sqrt(r1)-1: 1-sqrt(2-r1);
- double r2=2*erand48(Xi), dy=r2<1 ? sqrt(r2)-1: 1-sqrt(2-r2);
- Vec d = cx*( ( (sx+.5 + dx)/2 + x)/w - .5) +
- cy*( ( (sy+.5 + dy)/2 + y)/h - .5) + cam.d;
- r = r + radiance(scene, Ray(cam.o+d*140,d.norm()),0,Xi)*(1./samps);
- }
- // Camera rays are pushed ^^^^^ forward to start in interior
- c[i] = c[i] + Vec(clamp(r.x),clamp(r.y),clamp(r.z))*.25;
- }
- }
- }
- //printf("STOPPED %d\n", line);
- return 0;
- }
- class DoneTask : public pf::Task {
- public:
- virtual pf::Task* run(void) { pf::TaskingSystemInterrupt(); return NULL; }
- };
- //! Rendering loop
- void mainLoop(const Options & opts, const Scene & scene)
- {
- int w=opts.width;
- int h=opts.height;
- // # samples
- int samps = opts.samples;
- // Camera position, direction
- Ray cam(Vec(50,52,295.6), Vec(0,-0.042612,-1).norm());
- Vec cx=Vec(w*.5135/h);
- Vec cy=(cx%cam.d).norm()*.5135;
- Vec r;
- Vec * c=new Vec[w*h];
- // Loop over image rows
- pf::TaskingSystemStart();
- pf::Task * done = PF_NEW(DoneTask);
- for (int y=0; y<h; y++)
- {
- pf::Ref<LineTask> line = PF_NEW(LineTask, scene, cam, cx, cy, c, samps, y, w, h);
- line->starts(done);
- line->scheduled();
- }
- done->starts(0);
- done->scheduled();
- printf("Num threads %d\n", pf::TaskingSystemGetThreadNum());
- pf::TaskingSystemEnter();
- pf::TaskingSystemEnd();
- FILE *f = fopen(opts.outputFile.c_str(), "w"); // Write image to PPM file.
- fprintf(f, "P3\n%d %d\n%d\n", w, h, 255);
- for (int i=0; i<w*h; i++)
- fprintf(f,"%d %d %d ", toInt(c[i].x), toInt(c[i].y), toInt(c[i].z));
- }
- //! Accumulate radiance along a ray
- Vec radiance(const Scene & scene, const Ray &r_, int depth_, unsigned short *Xi)
- {
- double t; // distance to intersection
- int id=0; // id of intersected object
- Ray r=r_;
- int depth=depth_;
- // L0 = Le0 + f0*(L1)
- // = Le0 + f0*(Le1 + f1*L2)
- // = Le0 + f0*(Le1 + f1*(Le2 + f2*(L3))
- // = Le0 + f0*(Le1 + f1*(Le2 + f2*(Le3 + f3*(L4)))
- // = ...
- // = Le0 + f0*Le1 + f0*f1*Le2 + f0*f1*f2*Le3 + f0*f1*f2*f3*Le4 + ...
- //
- // So:
- // F = 1
- // while (1){
- // L += F*Lei
- // F *= fi
- // }
- Vec cl(0,0,0); // accumulated color
- Vec cf(1,1,1); // accumulated reflectance
- while (1)
- {
- if (!intersect(scene, r, t, id)) // if miss, return black
- return cl;
- const Sphere &obj = scene.spheres[id]; // the hit object
- Vec x=r.o+r.d*t;
- Vec n=(x-obj.p).norm();
- Vec nl=n.dot(r.d)<0?n:n*-1;
- Vec f=obj.c;
- double p = f.x>f.y && f.x>f.z ? f.x : f.y>f.z ? f.y : f.z; // max refl
- cl = cl + cf.mult(obj.e);
- if (++depth>5)
- {
- if (erand48(Xi)<p)
- {
- f=f*(1/p);
- }
- else
- {
- return cl; //R.R.
- }
- }
- cf = cf.mult(f);
- if (obj.refl == DIFF) // Ideal DIFFUSE reflection
- {
- double r1=2*M_PI*erand48(Xi), r2=erand48(Xi), r2s=sqrt(r2);
- Vec w=nl, u=((fabs(w.x)>.1?Vec(0,1):Vec(1))%w).norm(), v=w%u;
- Vec d = (u*cos(r1)*r2s + v*sin(r1)*r2s + w*sqrt(1-r2)).norm();
- r = Ray(x,d);
- continue;
- }
- else if (obj.refl == SPEC) // Ideal SPECULAR reflection
- {
- r = Ray(x,r.d-n*2*n.dot(r.d));
- continue;
- }
- Ray reflRay(x, r.d-n*2*n.dot(r.d)); // Ideal dielectric REFRACTION
- bool into = n.dot(nl)>0; // Ray from outside going in?
- double nc=1, nt=1.5, nnt=into?nc/nt:nt/nc, ddn=r.d.dot(nl), cos2t;
- if ((cos2t=1-nnt*nnt*(1-ddn*ddn))<0) // Total internal reflection
- {
- r = reflRay;
- continue;
- }
- Vec tdir = (r.d*nnt - n*((into?1:-1)*(ddn*nnt+sqrt(cos2t)))).norm();
- double a=nt-nc, b=nt+nc, R0=a*a/(b*b), c = 1-(into?-ddn:tdir.dot(n));
- double Re=R0+(1-R0)*c*c*c*c*c,Tr=1-Re,P=.25+.5*Re,RP=Re/P,TP=Tr/(1-P);
- if (erand48(Xi)<P)
- {
- cf = cf*RP;
- r = reflRay;
- }
- else
- {
- cf = cf*TP;
- r = Ray(x,tdir);
- }
- continue;
- }
- }
- bool intersect(const Scene & scene, const Ray &r, double &t, int &id)
- {
- double n = scene.n;
- double d;
- double inf=t=1e20;
- Sphere * spheres = scene.spheres;
- for(int i=int(n);i--;)
- {
- if((d=spheres[i].intersect(r))&&d<t)
- {
- t=d;
- id=i;
- }
- }
- return t<inf;
- }
- }
Add Comment
Please, Sign In to add comment