rendered paste body/* SRAY 0.0.12 - A simple raytracer Copyright (C) 2007 Martin 'nooga' Gasperowicz This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */#include <stdlib.h>#include <stdio.h>#include <math.h>#define PI 13.141592653f#define SIGMA 0.000001f#define EPSILON 999999999.0f#define MAXTD 5#define N 10#define AA 1#define W (120*N)#define H (90*N)#define PW 12.0f#define PH 9.0f#define Eye v(0,0,-12.0f)#define BKG v(0,0,0);typedef struct _Vec { double x,y,z;} Vec;Vec v(double x, double y, double z) { Vec r; r.x = x; r.y = y; r.z = z; return r;}Vec add(Vec a, Vec b) { return v(a.x+b.x, a.y+b.y, a.z+b.z);}Vec sub(Vec a, Vec b) { return v(a.x-b.x, a.y-b.y, a.z-b.z);}Vec mul(Vec a, Vec b) { return v(a.x*b.x, a.y*b.y, a.z*b.z);}Vec muls(Vec a, double b) { return v(a.x*b, a.y*b, a.z*b);}Vec divv(Vec a, double b) { return v(a.x/b, a.y/b, a.z/b);}double dot(Vec a, Vec b) { return a.x*b.x+a.y*b.y+a.z*b.z;}Vec cross(Vec a, Vec b) { return v(a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.z );}double len(Vec v) { return sqrtf(dot(v,v));}Vec norm(Vec ve) { double m = len(ve); return v(ve.x/m,ve.y/m,ve.z/m);}void printv(Vec v) { printf("(%f, %f, %f)", v.x, v.y, v.z);}Vec mirror(Vec q, Vec n) { Vec r = sub(q, muls(n,2.0f*dot(q, n))); return r;}Vec* scr;typedef struct { Vec o,d;} Ray;Ray r(Vec o, Vec d) { Ray re; re.o = o; re.d = norm(d); return re;}typedef struct { Vec color; double diffuse; double reflect;} Mat;Mat material(Vec c, double dif) { Mat m; m.color = c; m.diffuse = dif; m.reflect = 0.0f; return m;}typedef enum _ObjType {OT_LIGHT, OT_BALL} ObjType;typedef struct { ObjType typ; Vec center; double radius; Mat* mat;} Obj;int obc;Obj scene[360];void addObj(ObjType t, Vec c, double r, Mat* m) { Obj obj; obj.typ = t; obj.center = c; obj.radius = r; obj.mat = m; scene[obc] = obj; obc+=1;}Vec proj(int x, int y) { double xx = ((double)x/W)*PW-PW/2; double yy = ((double)y/H)*PH-PH/2; Vec q = v(xx, -yy, 0); return q;}Vec subproj(Vec v, int x, int y) { Vec ret; ret.x = v.x+x*(PW/(float)(4*W)); ret.y = v.y+y*(PH/(float)(4*H)); return ret;}double collide(Ray ray, Obj ob) { if(ob.typ == OT_BALL) { Vec o = sub(ray.o, ob.center); double a = 2*dot(ray.d, ray.d); double b = 2*dot(ray.d, o); double c = dot(o,o)-ob.radius*ob.radius; double d = b*b-2*a*c; if(d<0) return -1; d = sqrt(d); double t = (-b-d)/a; if(t>=0) return t; t = (-b+d)/a; if(t>=0) return t; } else return -1;}Vec shade(Vec pt, Obj ob) { Vec a = ob.mat->color; Vec normal = sub(pt, ob.center); int i; for(i = 0; i<obc; i++) { Obj c = scene[i]; if(c.typ == OT_LIGHT) { Vec dist = sub(c.center, pt); Vec fo = norm(dist); Ray tr = r(pt, fo); Vec n = norm(normal); int j; double t; for(j=0; j<obc; j++) { if(scene[j].typ == OT_BALL) { t = collide(tr, scene[j]); if(t>SIGMA) break; } } if(ob.mat->diffuse > 0 && t<=SIGMA) { double d = dot(fo, n); if(d>0) { double diff = d * ob.mat->diffuse; a = add(a, mul(ob.mat->color, muls(c.mat->color, diff))); } } } } return a;}Vec trace(Ray ray, int td) { if(td>MAXTD) return BKG; double last = EPSILON; int i; Vec re; for(i = 0; i<obc; i++) { if(scene[i].typ == OT_BALL) { double t = collide(ray, scene[i]); if(t>=0 && t < last) { last = t; Vec point = add(ray.o, muls(ray.d, t)); re = shade(point, scene[i]); if(scene[i].mat->reflect > 0) { Vec n = norm(sub(point, scene[i].center)); Vec m = mirror(ray.d, n); re = add(re, muls(trace(r(add(point, muls(m, SIGMA)), m), td+1), scene[i].mat->reflect)); } } } } if(last == EPSILON) return BKG; return re;}void raytrace() { scr = (Vec*)malloc(sizeof(Vec)*W*H); int x,y; Vec pp; for(y = 0; y<H; y++) for(x = 0; x<W; x++) { pp = proj(x,y); //printv(pp); Ray fe = r(Eye, sub(pp, Eye)); Vec pixel = trace(fe, 0); if(AA) { pixel = add(pixel, trace(r(Eye, sub(subproj(pp,1,1), Eye)),0)); pixel = add(pixel, trace(r(Eye, sub(subproj(pp,-1,1), Eye)),0)); pixel = add(pixel, trace(r(Eye, sub(subproj(pp,1,-1), Eye)),0)); pixel = add(pixel, trace(r(Eye, sub(subproj(pp,-1,-1), Eye)),0)); pixel = divv(pixel, 5); } scr[x+y*W] = pixel; } printf("P6\n%d %d\n255\n", W, H); for(y = 0; y<W*H; y++) { int r = round(((scr[y].x>1.0f)?1:scr[y].x)*255); int g = round(((scr[y].y>1.0f)?1:scr[y].y)*255); int b = round(((scr[y].z>1.0f)?1:scr[y].z)*255); r = (r>255)?255:r; g = (g>255)?255:g; b = (r>255)?255:b; printf("%c%c%c", r, g, b); }}double frac(double a) { return a - floor(a);}Vec hsb2rgb(double h, double s, double b) { double tH = frac(h)*6; double tF = frac(tH); double tP = b*(1.0f-s); double tQ = b*(1.0f-s*tF); double tT = b*(1.0-(s*(1.0-tF))); Vec ret; switch ((int)round(tH)) { case 0: ret = v(b,tT,tP); break; case 1: ret = v(tQ,b,tP); break; case 2: ret = v(tP,b,tT); break; case 3: ret = v(tP,tQ,b); break; case 4: ret = v(tT,tP,b); break; default: ret = v(b,tP,tQ); break; } return ret;}Mat red, light;void populate(int n) { int i; double a,x,y,z; Vec c; Mat* m = (Mat*)malloc(n*sizeof(Mat)); for(i = 0; i<n; i++) { a = PI/((double)n/2.0f); x = 5*sin(a*i); y = 5*cos(a*i)+7; z = (double)i/7.0f - 5.0f; c = hsb2rgb((double)i/(double)n,1,0.6f); m[i] = material(c, 1.0f); addObj(OT_BALL, v(x,z,y), 0.5f, &m[i]); }}int main(int argc, char* argv[]) { red = material(v(0.6f,0,0), 1.0f); light = material(v(1,1,1), 1.0f); populate(72); //addObj(OT_BALL, v(0,0,6.0f), 1.0f, &red); Mat mirr = material(v(0.1,0.1,0.1),1.0f); mirr.reflect = 0.5f; addObj(OT_BALL, v(0,-5.0f,7.0f), 3.0f, &mirr); addObj(OT_BALL, v(0,5.0f,7.0f), 3.0f, &mirr); addObj(OT_LIGHT, v(0,0,7.0f), 1.0f, &light); addObj(OT_LIGHT, v(6.0f,0,0), 1.0f, &red); addObj(OT_LIGHT, v(-6.0f,0,0), 1.0f, &light); raytrace(); return 0;}