All pastes #389032 Raw Edit

nooga

public c v1 · immutable
·published 2007-03-10 13:51 UTC
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;}