From 52dadbd4cf618bada9042c3bb2a4bc3803c5f417 Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Sun, 4 May 2014 11:53:29 +0200 Subject: Initial commit --- .gitignore | 5 + README.md | 11 ++ Stuff.rtsc | 31 ++++ box.rtsc | 21 +++ cuboids.rtsc | 20 +++ graytrace | Bin 0 -> 46644 bytes graytrace.cpp | 493 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ room.rtsc | 12 ++ room2.rtsc | 12 ++ simple.rtsc | 4 + spheres.rtsc | 53 +++++++ test.rtsc | 3 + 12 files changed, 665 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 Stuff.rtsc create mode 100644 box.rtsc create mode 100644 cuboids.rtsc create mode 100755 graytrace create mode 100644 graytrace.cpp create mode 100644 room.rtsc create mode 100644 room2.rtsc create mode 100644 simple.rtsc create mode 100644 spheres.rtsc create mode 100644 test.rtsc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6fa4ec2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +b.sh +graytracer +*.png +lodepng.h diff --git a/README.md b/README.md new file mode 100644 index 0000000..f2c2496 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +Graytracer +========== + +A simple, experimental raytracer that doesn't support colours. + +I made this in my spare time and will probably continue to add features. Or not. I don't know. + +It needs lodepng (as found on [lodev.org](http://lodev.org/lodepng/)). +Just compile with `lodepng.cpp` and `lodepng.h` in the same folder as the source and pass both `graytrace.cpp` and `lodepng.cpp` as arguments to the compiler. + +_- Tom Smeding_ diff --git a/Stuff.rtsc b/Stuff.rtsc new file mode 100644 index 0000000..8079ef7 --- /dev/null +++ b/Stuff.rtsc @@ -0,0 +1,31 @@ +1 -16 3 0 0 0 0 +-2 -8 6 1 +sphere -4 -4 -1 1 +sphere -2 -4 -1 1 +sphere 0 -4 -1 1 +sphere 2 -4 -1 1 +sphere 4 -4 -1 1 +sphere -4 -2 -1 1 +sphere -2 -2 -1 1 +sphere 0 -2 -1 1 +sphere 2 -2 -1 1 +sphere 4 -2 -1 1 +sphere -4 0 -1 1 +sphere -2 0 -1 1 +sphere 0 0 -1 1 +sphere 2 0 -1 1 +sphere 4 0 -1 1 +sphere -4 2 -1 1 +sphere -2 2 -1 1 +sphere 0 2 -1 1 +sphere 2 2 -1 1 +sphere 4 2 -1 1 +sphere -4 4 -1 1 +sphere -2 4 -1 1 +sphere 0 4 -1 1 +sphere 2 4 -1 1 +sphere 4 4 -1 1 +sphere -1 -6 3 1 +triangle 0 1 0 1 1 0 1 1.5 2 + +plane 0 0 -1.5 -0.1 0 1 \ No newline at end of file diff --git a/box.rtsc b/box.rtsc new file mode 100644 index 0000000..add669f --- /dev/null +++ b/box.rtsc @@ -0,0 +1,21 @@ +4 -5 2 0 0 0 0 +2.5 .5 2 1 +triangle 0 0 0 1 0 0 1 0 1 +triangle 0 0 0 1 0 1 0 0 1 + +triangle 0 0 1 1 0 1 1 1 1 +triangle 0 0 1 1 1 1 0 1 1 + +triangle 1 0 0 1 1 0 1 1 1 +triangle 1 0 0 1 1 1 1 0 1 + +triangle 0 1 0 1 1 0 1 1 1 +triangle 0 1 0 1 1 1 0 1 1 + +triangle 0 0 0 1 0 0 1 1 0 +triangle 0 0 0 1 1 0 0 1 0 + +triangle 0 0 0 0 1 0 0 1 1 +triangle 0 0 0 0 1 1 0 0 1 + +plane 0 0 -1 0 0 1 \ No newline at end of file diff --git a/cuboids.rtsc b/cuboids.rtsc new file mode 100644 index 0000000..7bc8ef3 --- /dev/null +++ b/cuboids.rtsc @@ -0,0 +1,20 @@ +7.5 -10 6 7.5 0 0 0 +3 -10 15 1 + +cuboid 1 0 4 4 1 5 +cuboid 2 0 0 3 1 4 + +cuboid 5 0 0 10 1 1 +cuboid 5 0 4 10 1 5 +cuboid 5 0 1 6 1 4 +cuboid 9 0 1 10 1 4 + +cuboid 11 0 0 12 1 5 +cuboid 12 0 3 13 1 4 +cuboid 13 0 2 14 1 3 +cuboid 14 0 3 15 1 4 +cuboid 15 0 0 16 1 5 + +sphere 7.5 0.5 2.5 1 + +plane 0 0 -1 0 1 10 \ No newline at end of file diff --git a/graytrace b/graytrace new file mode 100755 index 0000000..aa0a092 Binary files /dev/null and b/graytrace differ 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: "<