0,140866,141378,143170 ,174450,222784,139386,0,0
September 22, 2013 12:34 PM Subscribe
Ray tracing is a computer graphics technique that produces realistic images of a three-dimensional scene. In 1987, Paul Heckbert (then at Pixar) announced a contest to produce a ray tracer in the minimum amount of code, as he describes in "A Minimal Ray Tracer." In 2009, Andrew Kensler (then at the University of Utah Scientific Computing and Imaging Institute) created a C++ version that can fit on a business card. Fabien Sanglard explicates this amazing piece of code in "Decyphering the Business Card Raytracer."
Sorry, the SO instincts are taking over, but the C++ code is C.
I didn't realize C had operator overloading now.
posted by grouse at 12:43 PM on September 22, 2013 [5 favorites]
I didn't realize C had operator overloading now.
posted by grouse at 12:43 PM on September 22, 2013 [5 favorites]
Hmm, you're right. Never mind.
posted by Blazecock Pileon at 12:48 PM on September 22, 2013
posted by Blazecock Pileon at 12:48 PM on September 22, 2013
The vector class (and the operators it overloads) are the only strong C++ flavor.
The use of "struct v" instead of "class v" is clever - class members are private by default and struct members are public by default. So using "struct" costs him one extra character but he then doesn't have to burn 7 characters by specifying "public:".
posted by We had a deal, Kyle at 12:55 PM on September 22, 2013 [8 favorites]
The use of "struct v" instead of "class v" is clever - class members are private by default and struct members are public by default. So using "struct" costs him one extra character but he then doesn't have to burn 7 characters by specifying "public:".
posted by We had a deal, Kyle at 12:55 PM on September 22, 2013 [8 favorites]
27 seconds? My Ubuntu lappy isn't as fast as I thought.
posted by GallonOfAlan at 1:12 PM on September 22, 2013
posted by GallonOfAlan at 1:12 PM on September 22, 2013
As someone who spent the last 3 years in QA, it's beautiful, and clearly a very clever accomplishment. Anyone writing production code like this deserves to be beaten until they're pissing blood.
posted by Suddenly, elf ass at 1:18 PM on September 22, 2013 [22 favorites]
posted by Suddenly, elf ass at 1:18 PM on September 22, 2013 [22 favorites]
It's stuff like this that means I will never lose the nagging suspicion I have that my boss will one day come in and say something like "Look how good programmers can be at programming! Get out, I want guys like this!".
posted by Jon Mitchell at 1:20 PM on September 22, 2013 [2 favorites]
posted by Jon Mitchell at 1:20 PM on September 22, 2013 [2 favorites]
The business card ray tracer nicely demonstrates the effects of compiler optimizations:
$ for i in 3 2 1 0 s fast ; do make -s CXXFLAGS="-Wall -O$i" card && /usr/bin/time -f "%e sec (-O$i)" ./card >/dev/null && rm -f card ; done 2>&1 | sort -n 8.02 sec (-Ofast) 12.06 sec (-O3) 15.16 sec (-O2) 18.29 sec (-O1) 57.25 sec (-Os) 105.15 sec (-O0)posted by scatter gather at 1:56 PM on September 22, 2013 [8 favorites]
Another easter-egg:
$ wc -c card.cpp
1337 card.cpp
posted by jepler at 1:57 PM on September 22, 2013 [9 favorites]
$ wc -c card.cpp
1337 card.cpp
posted by jepler at 1:57 PM on September 22, 2013 [9 favorites]
The business card ray tracer nicely demonstrates the effects of compiler optimizations
Neat!
posted by grouse at 2:29 PM on September 22, 2013
Neat!
$ for i in 3 fast ; do make -s CXXFLAGS="-Wall -O$i" card && /usr/bin/time -f "%e sec (-O$i)" ./card >/dev/null && rm -f card ; done 2>&1 | sort -n 11.46 sec (-Ofast) 18.55 sec (-O3) $ make -s CXXFLAGS="-Wall -Ofast -fprofile-generate" card && /usr/bin/time -f "%e sec (-Ofast -fprofile-generate)" ./card >/dev/null && rm -f card 26.78 sec (-Ofast -fprofile-generate) $ make -s CXXFLAGS="-Wall -Ofast -fprofile-use" card && /usr/bin/time -f "%e sec (-Ofast -fprofile-use)" ./card >/dev/null && rm -f card 12.31 sec (-Ofast -fprofile-use)It looks like profile-guided optimization doesn't help me.
posted by grouse at 2:29 PM on September 22, 2013
Wow. As someone who knows barely enough C to make an arduino twitch, this is way past "impressive" into "intimidating", verging on "obviously witchcraft".
I think I follow the explanation. The weird mix of intricacy and brutal efficiency actually reminds me of looking at some of the weirder biosynthesis pathways; if there was a mind involved, it was a mad genius.
posted by metaBugs at 2:35 PM on September 22, 2013 [2 favorites]
I think I follow the explanation. The weird mix of intricacy and brutal efficiency actually reminds me of looking at some of the weirder biosynthesis pathways; if there was a mind involved, it was a mad genius.
posted by metaBugs at 2:35 PM on September 22, 2013 [2 favorites]
> [0,140866,141378,143170,174450,222784,139386,0,0].reverse().map(function(n) { return n.toString(2).replace('1','*','g').replace('0',' ','g') + '\n'; }).join('\n); * * **** * ** ** ** * * * * * * *** * * * **** * * * * * * * * * ** * *posted by potch at 2:41 PM on September 22, 2013 [12 favorites]
grouse: the profiling options don't really help on my system either, although maybe a little with -O2. I've never really used PGO in practice. Maybe it needs repeated runs or a larger program or data set to be useful.
posted by scatter gather at 3:02 PM on September 22, 2013
posted by scatter gather at 3:02 PM on September 22, 2013
The ray tracer on a business card that I created in 1987 was written in C. Read the "A Minimal Ray Tracer" article for some explanation of how it works.
typedef struct{double x,y,z}vec;vec U,black,amb={.02,.02,.02};struct sphere{
vec cen,color;double rad,kd,ks,kt,kl,ir}*s,*best,sph[]={0.,6.,.5,1.,1.,1.,.9,
.05,.2,.85,0.,1.7,-1.,8.,-.5,1.,.5,.2,1.,.7,.3,0.,.05,1.2,1.,8.,-.5,.1,.8,.8,
1.,.3,.7,0.,0.,1.2,3.,-6.,15.,1.,.8,1.,7.,0.,0.,0.,.6,1.5,-3.,-3.,12.,.8,1.,
1.,5.,0.,0.,0.,.5,1.5,};yx;double u,b,tmin,sqrt(),tan();double vdot(A,B)vec A
,B;{return A.x*B.x+A.y*B.y+A.z*B.z;}vec vcomb(a,A,B)double a;vec A,B;{B.x+=a*
A.x;B.y+=a*A.y;B.z+=a*A.z;return B;}vec vunit(A)vec A;{return vcomb(1./sqrt(
vdot(A,A)),A,black);}struct sphere*intersect(P,D)vec P,D;{best=0;tmin=1e30;s=
sph+5;while(s-->sph)b=vdot(D,U=vcomb(-1.,P,s->cen)),u=b*b-vdot(U,U)+s->rad*s
->rad,u=u>0?sqrt(u):1e31,u=b-u>1e-7?b-u:b+u,tmin=u>=1e-7&&uir;d= -vdot(D,N=vunit(vcomb(-1.,P=vcomb(tmin,D,P),s->cen
)));if(d<0>sph)if((e=l
->kl*vdot(N,U=vunit(vcomb(-1.,P,l->cen))))>0&&intersect(P,U)==l)color=vcomb(e
,l->color,color);U=s->color;color.x*=U.x;color.y*=U.y;color.z*=U.z;e=1-eta*
eta*(1-d*d);return vcomb(s->kt,e>0?trace(level,P,vcomb(eta,D,vcomb(eta*d-sqrt
(e),N,black))):black,vcomb(s->ks,trace(level,P,vcomb(2*d,N,D)),vcomb(s->kd,
color,vcomb(s->kl,U,black))));}main(){printf("%d %d\n",32,32);while(yx<32*32)
U.x=yx%32-32/2,U.z=32/2-yx++/32,U.y=32/2/tan(25/114.5915590261),U=vcomb(255.,
trace(3,black,vunit(U)),black),printf("%.0f %.0f %.0f\n",U);}/*minray!*/0>
posted by paulheckbert at 6:59 PM on September 22, 2013 [24 favorites]
typedef struct{double x,y,z}vec;vec U,black,amb={.02,.02,.02};struct sphere{
vec cen,color;double rad,kd,ks,kt,kl,ir}*s,*best,sph[]={0.,6.,.5,1.,1.,1.,.9,
.05,.2,.85,0.,1.7,-1.,8.,-.5,1.,.5,.2,1.,.7,.3,0.,.05,1.2,1.,8.,-.5,.1,.8,.8,
1.,.3,.7,0.,0.,1.2,3.,-6.,15.,1.,.8,1.,7.,0.,0.,0.,.6,1.5,-3.,-3.,12.,.8,1.,
1.,5.,0.,0.,0.,.5,1.5,};yx;double u,b,tmin,sqrt(),tan();double vdot(A,B)vec A
,B;{return A.x*B.x+A.y*B.y+A.z*B.z;}vec vcomb(a,A,B)double a;vec A,B;{B.x+=a*
A.x;B.y+=a*A.y;B.z+=a*A.z;return B;}vec vunit(A)vec A;{return vcomb(1./sqrt(
vdot(A,A)),A,black);}struct sphere*intersect(P,D)vec P,D;{best=0;tmin=1e30;s=
sph+5;while(s-->sph)b=vdot(D,U=vcomb(-1.,P,s->cen)),u=b*b-vdot(U,U)+s->rad*s
->rad,u=u>0?sqrt(u):1e31,u=b-u>1e-7?b-u:b+u,tmin=u>=1e-7&&u
)));if(d<0>sph)if((e=l
->kl*vdot(N,U=vunit(vcomb(-1.,P,l->cen))))>0&&intersect(P,U)==l)color=vcomb(e
,l->color,color);U=s->color;color.x*=U.x;color.y*=U.y;color.z*=U.z;e=1-eta*
eta*(1-d*d);return vcomb(s->kt,e>0?trace(level,P,vcomb(eta,D,vcomb(eta*d-sqrt
(e),N,black))):black,vcomb(s->ks,trace(level,P,vcomb(2*d,N,D)),vcomb(s->kd,
color,vcomb(s->kl,U,black))));}main(){printf("%d %d\n",32,32);while(yx<32*32)
U.x=yx%32-32/2,U.z=32/2-yx++/32,U.y=32/2/tan(25/114.5915590261),U=vcomb(255.,
trace(3,black,vunit(U)),black),printf("%.0f %.0f %.0f\n",U);}/*minray!*/0>
posted by paulheckbert at 6:59 PM on September 22, 2013 [24 favorites]
The tutorial for POV-Ray shows how to make a raytracer with a raytracer.
posted by elgilito at 12:47 AM on September 23, 2013
posted by elgilito at 12:47 AM on September 23, 2013
I too lean toward the "beauty is as beauty does" school of thought.
Think that is inscrutable ... imagine it in assembler.
posted by Twang at 6:25 AM on September 23, 2013
Think that is inscrutable ... imagine it in assembler.
posted by Twang at 6:25 AM on September 23, 2013
« Older Happy Hobbit Day! | You weren’t just a paddle, you were an astronaut... Newer »
This thread has been archived and is closed to new comments
posted by Blazecock Pileon at 12:39 PM on September 22, 2013