#include #include #include #include #include #include #include #include #include "lodepng.h" #define SCREEN_WIDTH (960) #define SCREEN_HEIGHT (640) #define FLOAT_SMALL_NUM (1e-8) using namespace std; /* Scene description file (.rtsc, Ray Trace SCene) =============================================== Z The positive Y-axis points away from you in this picture. ^ _Y | /' | / |/ #------> X A "number" is a floating-point number, unless stated otherwise. A "coordinate" is three numbers, separated by a space. Between numbers, any amount of whitespace is tolerated. First line: coordinate of camera, the coordinate of point the camera looks at directly and a number in [0,2π) indicating the amount the camera is rotated clockwise around the axis between the camera position and the point the camera looks at. Z normally faces up in this right-handed coordinate system. Second line: coordinate of the point light source, followed by the intensity in [0,1]. Further lines: a string in {triangle,sphere} giving the object shape, a coordinate giving the centre of the object and further parameters for the object. For a sphere, give the size (radius); for a triangle give the coordinates of the two other vertices; for a plane, give the normal the position is any point on the plane. Example file: 1 -15 2 0 0 0 0 -2 -2 6 1 sphere 0 0 0 1 sphere 1 10 -3 1.5 */ bool samesign(const double a,const double b){ return (a>0&&b>0)||(a<0&&b<0); } class Vec3{ public: double x,y,z; Vec3(void){x=y=z=0;} Vec3(double _x,double _y,double _z){x=_x;y=_y;z=_z;} Vec3& operator=(const Vec3 &other){ x=other.x; y=other.y; z=other.z; return *this; } Vec3 operator+(const Vec3 other) const{return Vec3(x+other.x,y+other.y,z+other.z);} Vec3 operator-(const Vec3 other) const{return Vec3(x-other.x,y-other.y,z-other.z);} Vec3 operator*(const double other) const{return Vec3(x*other,y*other,z*other);} double norm(void) const{return sqrt(x*x+y*y+z*z);} double dot(const Vec3 &other) const{ return x*other.x+y*other.y+z*other.z; } Vec3 cross(const Vec3 &other) const{ return Vec3(y*other.z-z*other.y,z*other.x-x*other.z,x*other.y-y*other.x); } bool hasnan(void) const{return isnan(x)||isnan(y)||isnan(z);} Vec3 normalised(void) const{return *this*(1/norm());} void normalise(void){ double n=norm(); x/=n; y/=n; z/=n; } /*The Vec3::rotated[XYZ] functions rotate around that axis, anti-clockwise if looking at the rotation when said axis is pointer towards the observer. Matrices from en.wikipedia.org/wiki/Rotation_matrix#In_three_dimensions */ Vec3 rotatedX(double theta) const{ return Vec3(x,y*cos(theta)-z*sin(theta),y*sin(theta)+z*cos(theta)); } Vec3 rotatedY(double theta) const{ return Vec3(x*cos(theta)+z*sin(theta),y,-x*sin(theta)+z*cos(theta)); } Vec3 rotatedZ(double theta) const{ return Vec3(x*cos(theta)-y*sin(theta),x*sin(theta)+y*cos(theta),z); } string str(void) const{ stringstream ss; ss<<'['<isLight){ //if intersection was found double cross=(camera.pos-intersection).normalised().cross(objs[minatidx]->normalat(intersection)).norm(); //cross==sin(angle between those vectors) return 1-cross/6; //this looks reasonable } //cout<isLight){light=(Light*)objs[i];break;} if(light==NULL)return 0.1; Vec3 DlightToInter=minatinter-light->pos; double distLightToInter=DlightToInter.norm(); for(i=0;iisLight)continue; intersection=objs[i]->lineIntersect(light->pos,DlightToInter); dist=abs((intersection-light->pos).norm()); if(!intersection.hasnan()&&abs((intersection-minatinter).norm())>FLOAT_SMALL_NUM&&distpos-minatinter).normalised().cross((camera.pos-minatinter).normalised()).norm()); Vec3 cam=(camera.pos-minatinter).normalised(),nor=objs[minatidx]->normalat(minatinter),lig=(light->pos-minatinter).normalised(); /*double diff=asin(cam.cross(nor).norm())-asin(nor.cross(lig).norm()); //ANCIENT if(diff<0)return 0.1; else return 0.1+diff*0.9;*/ //if(abs(factor)>M_PI/2||!samesign(angleBetween(cam,lig)-angleBetween(cam,nor),angleBetween(nor,lig)))return 0.1; //else return 0.1+(1-abs(factor))*0.9; /*double ligCamAngle=angleBetween(cam,lig); double ligNorAngle=angleBetween(nor,lig); double camNorAngle=angleBetween(cam,nor); angle=abs(ligCamAngle-2*camNorAngle); //how far, in radians, from the perfect reflection angle if(angle>M_PI/2)return 0.1; else return 0.1+(1-angle/M_PI)*0.9;*/ /*double factor=angleBetween(cam,nor)-angleBetween(nor,lig); //for spheres if(factor>M_PI/2)return 0.5+(double)rand()/RAND_MAX*0.5; if(factor<0)return 0.1; return 0.1+factor/(M_PI/2)*0.9;*/ /*double factor=angleBetween(cam,lig)-2*angleBetween(cam,nor); //for cubes if(abs(factor)>M_PI)return 0.1; return 0.1+(1-abs(factor)/M_PI)*0.9;*/ Vec3 reflected=nor*cam.dot(nor)*2-cam; // paulbourke.net/geometry/reflected/ double diff=angleBetween(lig,reflected); //always >=0 if(diff>M_PI)return 0.1; //else return 0.1+0.9*(pow(M_E,-diff)-diff*0.01375541740409698); //y=e^(-x)-x*e^(-pi)/pi gives an exponential thing through (0,1) and (pi,0) //else return 0.1+0.9*cos(diff/2); //else return 0.1+0.9*sin(0.5*M_PI*nor.dot(lig))*(1-diff/M_PI); else return 0.1+0.9*0.5*(sin(M_PI*(nor.dot(lig)-0.5))+1)*(1-diff/M_PI); } else { //cout< &image,Camera &camera,vector objs,int N){ double x,y; //double minclr=10000,maxclr=-10000; //cerr<<"camera.pos="<maxclr)maxclr=image[4*(SCREEN_WIDTH*y+x)+0]/255.0; //cout< objs; in>>camera.pos.x>>camera.pos.y>>camera.pos.z>>camera.lookat.x>>camera.lookat.y>>camera.lookat.z>>camera.rot; if(camera.rot!=0){ cout<<"No camera rotation is currently supported; the given value of "<>((Light*)objs[0])->pos.x>>((Light*)objs[0])->pos.y>>((Light*)objs[0])->pos.z>>((Light*)objs[0])->intensity; objs[0]->isLight=true; N=1; for(i=1;;i++){ in>>type; if(!in.good())break; if(type=="sphere"){ objs.push_back(new Sphere); in>>((Sphere*)objs[i])->pos.x>>((Sphere*)objs[i])->pos.y>>((Sphere*)objs[i])->pos.z>>((Sphere*)objs[i])->size; //((Sphere*)objs[i])->printName(); N++; } else if(type=="triangle"){ objs.push_back(new Triangle); in>>((Triangle*)objs[i])->pos0.x>>((Triangle*)objs[i])->pos0.y>>((Triangle*)objs[i])->pos0.z >>((Triangle*)objs[i])->pos1.x>>((Triangle*)objs[i])->pos1.y>>((Triangle*)objs[i])->pos1.z >>((Triangle*)objs[i])->pos2.x>>((Triangle*)objs[i])->pos2.y>>((Triangle*)objs[i])->pos2.z; //((Triangle*)objs[i])->printName(); N++; } else if(type=="cuboid"){ Vec3 p1,p2; in>>p1.x>>p1.y>>p1.z>>p2.x>>p2.y>>p2.z; objs.push_back(new Triangle); ((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p1.z; ((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p1.y; ((Triangle*)objs[i])->pos1.z=p1.z; ((Triangle*)objs[i])->pos2.x=p2.x; ((Triangle*)objs[i])->pos2.y=p1.y; ((Triangle*)objs[i])->pos2.z=p2.z; i++; N++; objs.push_back(new Triangle); ((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p1.z; ((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p1.y; ((Triangle*)objs[i])->pos1.z=p2.z; ((Triangle*)objs[i])->pos2.x=p1.x; ((Triangle*)objs[i])->pos2.y=p1.y; ((Triangle*)objs[i])->pos2.z=p2.z; i++; N++; objs.push_back(new Triangle); ((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p2.z; ((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p1.y; ((Triangle*)objs[i])->pos1.z=p2.z; ((Triangle*)objs[i])->pos2.x=p2.x; ((Triangle*)objs[i])->pos2.y=p2.y; ((Triangle*)objs[i])->pos2.z=p2.z; i++; N++; objs.push_back(new Triangle); ((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p2.z; ((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p2.y; ((Triangle*)objs[i])->pos1.z=p2.z; ((Triangle*)objs[i])->pos2.x=p1.x; ((Triangle*)objs[i])->pos2.y=p2.y; ((Triangle*)objs[i])->pos2.z=p2.z; i++; N++; objs.push_back(new Triangle); ((Triangle*)objs[i])->pos0.x=p2.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p1.z; ((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p2.y; ((Triangle*)objs[i])->pos1.z=p1.z; ((Triangle*)objs[i])->pos2.x=p2.x; ((Triangle*)objs[i])->pos2.y=p2.y; ((Triangle*)objs[i])->pos2.z=p2.z; i++; N++; objs.push_back(new Triangle); ((Triangle*)objs[i])->pos0.x=p2.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p1.z; ((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p2.y; ((Triangle*)objs[i])->pos1.z=p2.z; ((Triangle*)objs[i])->pos2.x=p2.x; ((Triangle*)objs[i])->pos2.y=p1.y; ((Triangle*)objs[i])->pos2.z=p2.z; i++; N++; objs.push_back(new Triangle); ((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p2.y; ((Triangle*)objs[i])->pos0.z=p1.z; ((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p2.y; ((Triangle*)objs[i])->pos1.z=p1.z; ((Triangle*)objs[i])->pos2.x=p2.x; ((Triangle*)objs[i])->pos2.y=p2.y; ((Triangle*)objs[i])->pos2.z=p2.z; i++; N++; objs.push_back(new Triangle); ((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p2.y; ((Triangle*)objs[i])->pos0.z=p1.z; ((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p2.y; ((Triangle*)objs[i])->pos1.z=p2.z; ((Triangle*)objs[i])->pos2.x=p1.x; ((Triangle*)objs[i])->pos2.y=p2.y; ((Triangle*)objs[i])->pos2.z=p2.z; i++; N++; objs.push_back(new Triangle); ((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p1.z; ((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p1.y; ((Triangle*)objs[i])->pos1.z=p1.z; ((Triangle*)objs[i])->pos2.x=p2.x; ((Triangle*)objs[i])->pos2.y=p2.y; ((Triangle*)objs[i])->pos2.z=p1.z; i++; N++; objs.push_back(new Triangle); ((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p1.z; ((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p2.y; ((Triangle*)objs[i])->pos1.z=p1.z; ((Triangle*)objs[i])->pos2.x=p1.x; ((Triangle*)objs[i])->pos2.y=p2.y; ((Triangle*)objs[i])->pos2.z=p1.z; i++; N++; objs.push_back(new Triangle); ((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p1.z; ((Triangle*)objs[i])->pos1.x=p1.x; ((Triangle*)objs[i])->pos1.y=p2.y; ((Triangle*)objs[i])->pos1.z=p1.z; ((Triangle*)objs[i])->pos2.x=p1.x; ((Triangle*)objs[i])->pos2.y=p2.y; ((Triangle*)objs[i])->pos2.z=p2.z; i++; N++; objs.push_back(new Triangle); ((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p1.z; ((Triangle*)objs[i])->pos1.x=p1.x; ((Triangle*)objs[i])->pos1.y=p2.y; ((Triangle*)objs[i])->pos1.z=p2.z; ((Triangle*)objs[i])->pos2.x=p1.x; ((Triangle*)objs[i])->pos2.y=p1.y; ((Triangle*)objs[i])->pos2.z=p2.z; //((Triangle*)objs[i])->printName(); N++; } else if(type=="plane"){ objs.push_back(new Plane); in>>((Plane*)objs[i])->pos.x>>((Plane*)objs[i])->pos.y>>((Plane*)objs[i])->pos.z >>((Plane*)objs[i])->normal.x>>((Plane*)objs[i])->normal.y>>((Plane*)objs[i])->normal.z; ((Plane*)objs[i])->normal.normalise(); N++; } else { cout<<"Unknown object type '"< image; image.resize(4*SCREEN_WIDTH*SCREEN_HEIGHT); int error; #if 0 char fname[fnamebase.length()+8]; cout<<"Rendered frames: "<