#include // smallpt, a Path Tracer by Kevin Beason, 2009 #include // Make : g++ -O3 -fopenmp explicit.cpp -o explicit #include // Remove "-fopenmp" for g++ version < 4.2 #include double get_time() { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); return ts.tv_sec * 1000.0 + ts.tv_nsec / 1000000.0; } struct Vec { // Usage: time ./explicit 16 && xv image.ppm double x, y, z; // position, also color (r,g,b) Vec(double x_=0, double y_=0, double z_=0){ x=x_; y=y_; z=z_; } 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);} }; struct Ray { Vec o, d; Ray(Vec o_, Vec d_) : o(o_), d(d_) {} }; enum Refl_t { DIFF, SPEC, REFR }; // material types, used in radiance() struct Sphere { double rad; // radius Vec p, e, c; // position, emission, color Refl_t refl; // reflection type (DIFFuse, SPECular, REFRactive) Sphere(double rad_, Vec p_, Vec e_, Vec c_, Refl_t refl_): rad(rad_), p(p_), e(e_), c(c_), refl(refl_) {} double intersect(const Ray &r) const { // returns distance, 0 if nohit 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); } }; Sphere spheres[] = {//Scene: radius, position, emission, color, material 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)*.6, SPEC),//Mirr Sphere(16.5,Vec(73,16.5,78), Vec(),Vec(.75,1.,.95), REFR),//Glas Sphere(4.0, Vec(50,81.6-16.5,81.6),Vec(4,4,4)*12, Vec(), DIFF),//Lite }; int numSpheres = sizeof(spheres)/sizeof(Sphere); inline double clamp(double x){ return x<0 ? 0 : x>1 ? 1 : x; } inline int toInt(double x){ return int(pow(clamp(x),1/2.2)*255+.5); } inline bool intersect(const Ray &r, double &t, int &id){ double n=sizeof(spheres)/sizeof(Sphere), d, inf=t=1e20; for(int i=int(n);i--;) if((d=spheres[i].intersect(r))&&df.y && f.x>f.z ? f.x : f.y>f.z ? f.y : f.z; // max refl if (++depth>5||!p) if (erand48(Xi).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(); // Loop over any lights Vec e; for (int i=0; i.1?Vec(0,1):Vec(1))%sw).norm(), sv=sw%su; double cos_a_max = sqrt(1-s.rad*s.rad/(x-s.p).dot(x-s.p)); double eps1 = erand48(Xi), eps2 = erand48(Xi); double cos_a = 1-eps1+eps1*cos_a_max; double sin_a = sqrt(1-cos_a*cos_a); double phi = 2*M_PI*eps2; Vec l = su*cos(phi)*sin_a + sv*sin(phi)*sin_a + sw*cos_a; l.norm(); if (intersect(Ray(x,l), t, id) && id==i){ // shadow ray double omega = 2*M_PI*(1-cos_a_max); e = e + f.mult(s.e*l.dot(nl)*omega)*M_1_PI; // 1/pi for brdf } } return obj.e*E+e+f.mult(radiance(Ray(x,d),depth,Xi,0)); } else if (obj.refl == SPEC) // Ideal SPECULAR reflection return obj.e + f.mult(radiance(Ray(x,r.d-n*2*n.dot(r.d)),depth,Xi)); 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 return obj.e + f.mult(radiance(reflRay,depth,Xi)); 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); return obj.e + f.mult(depth>2 ? (erand48(Xi)

= 2) samps = atoi(argv[1])/4; if (argc >= 3) w = h = atoi(argv[2]); double tbeg = get_time(); Ray cam(Vec(50,52,295.6), Vec(0,-0.042612,-1).norm()); // cam pos, dir Vec cx=Vec(w*.5135/h), cy=(cx%cam.d).norm()*.5135, r, *c=new Vec[w*h]; #pragma omp parallel for schedule(dynamic, 1) private(r) // OpenMP for (int y=0; y