From 52dadbd4cf618bada9042c3bb2a4bc3803c5f417 Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Sun, 4 May 2014 11:53:29 +0200 Subject: Initial commit --- graytrace.cpp | 493 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 493 insertions(+) create mode 100644 graytrace.cpp (limited to 'graytrace.cpp') diff --git a/graytrace.cpp b/graytrace.cpp new file mode 100644 index 0000000..b74d387 --- /dev/null +++ b/graytrace.cpp @@ -0,0 +1,493 @@ +#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: "<