
Deciphering the Business Card Raytracer - cremno
http://fabiensanglard.net/rayTracing_back_of_business_card/index.php
======
a_e_k
Hi there, code author here. I've been lurking here for years, but couldn't
resist an invitation like this.

I've always enjoyed Fabien's analyses so it's great fun to see what he makes
of my own code. Anyway, a few clarifications from what I remember of this. (I
wrote this '09, and I don't have my old notes in front of me right now):

* The `n` value returned by the trace function, `T()`, is the surface normal. It returns this whether it hit the plane or a sphere.

* The `r` vector in `S()` is the reflection vector off whatever was hit.

* The mystery `c` point in the `main()` function is the offset from the eye point (ignoring the lens perturbation `t`) to the corner of the focal plane. Note below that we're nominally tracing rays for pixel (x,y) in the direction of a _x+b_ y+c. At the image midpoint, this should be `g`.

* "although I suspect this to be a side effect: This is not how soft-shadows are done." True. There are true soft shadows in this, but this isn't where they're computed. That's the job of the randomization where `l` is computed in `S()`.

Anyway, please feel free to ask any questions about it.

~~~
raminf
#define op operator

#define rt return

Then replacing the corresponding inline tokens shaves off another 25 bytes
from the source without affecting the output or (arguably) the readability.

Sorry, my inner obfuscator couldn't resist :-)

Beautiful bit of coding, btw.

~~~
fabien_sanglard
Can you pastebin.com it so we can see what it looks like ?

~~~
raminf
[http://pastebin.com/ktukPBHE](http://pastebin.com/ktukPBHE)

I reformatted it so it would justify right like the original but for some
reason Pastebin likes to reflow things.

It turns out the single-character tokens 'u' and 'w' were not being used so
repurposing them for the #defines leads to a saving of 46 characters at the
cost of an extra line. There are a few other recurring tokens but you hit a
point of diminishing return.

One should not, however, lose sight of what an awesomely clever hack the whole
thing is. Reminds me of some of the text-flow layouts in old illuminated
manuscripts, or the more modern variations here (like the one with the light-
bulb): [http://www.smashingmagazine.com/2008/02/11/award-winning-
new...](http://www.smashingmagazine.com/2008/02/11/award-winning-newspaper-
designs/)

------
chrissnell
If you want to make your own, like Fabian Sanglard did, take this block of
binary numbers and draw your initials (left-justified) with 1's:

    
    
      0001110000010001110
      0010000000000010000
      0100000000010010000
      0100000000010001100
      0100000000010000100
      0010000010010000010
      0001110001100011100
    

That's my initials, cjs. If you unfocus your eyes, you can see the letters
pretty clearly.

Take each line, top to bottom, and convert to decimal:

[http://www.mathsisfun.com/binary-decimal-hexadecimal-
convert...](http://www.mathsisfun.com/binary-decimal-hexadecimal-
converter.html)

Edit Paul Heckbert's code (lines 12-13, the "G" array), replacing the numbers
from right to left with the decimal values. In other words, the last number in
the array is the top line of the binary block above.

Clean up the justification and you have your business card raytracer, courtesy
of Mr. Heckbert.

I probably could have coded this in the time that it took me to draw my
initials in binary pixels.

Also, here's a version with the camera moved slightly farther out so that the
letters don't clip:

[https://gist.github.com/chrissnell/6656963](https://gist.github.com/chrissnell/6656963)

~~~
logicallee
thanks.

what exactly were you referring to with "I probably could have coded this in
the time that it took me to draw my initials in binary pixels."?

~~~
chrissnell
I could have coded something to generate customized versions of the original
source, given three ASCII initials.

~~~
logicallee
Come on, Chris. I'm a big fan of the humblebrag, but you would still have to
draw the binary pixel version of each letter (because C doesn't come with
binary pixel array versions of the 26 letters) - so it would be 8 times as
much work at an absolute minimum (26 characters versus the 3 that you did),
even if the code to embed them in the array were a completely obvious 1-liner,
and so was the code to clean up the justification.

Let's not flatter ourselves :)

~~~
chrissnell
Didn't mean to come off as arrogant but there are existing tools that would
make this a lot easier. figlet(1) would make the pixel conversion pretty easy.
Pixels to binary really isn't that hard. You could do it with a regex.

~~~
derekp7
Another way is to use the netpbm toolkit. First, use its ppmdraw command to
rasterize each character to a canvas, then convert that canvas to xpm format
(you have a separate canvas / picture for each character). The xpm format has
the nice property that it is also a valid C structure. Real easy to then
convert to whatever you want.

Oh, and the netpbm toolkit has not only stand alone binaries, but it also has
a C library for each of the conversions that it includes. Seems to be an older
under-rated toolkit.

------
jevinskie
Would the wasted empty space in a #define return <pick a single character>
make up for the several return statements that I see? That is why typedef
statements are nice, you can ; terminate them!

~~~
matthew-wegner
The original is also 1337 bytes, which might explain any padding!

~~~
a_e_k
Guilty as charged!

I stopped trying to minimize it when I noticed that.

------
chii
It looks like his site is taken down due to bandwidth limit reached. Use
[http://webcache.googleusercontent.com/search?q=cache:http://...](http://webcache.googleusercontent.com/search?q=cache:http://fabiensanglard.net/rayTracing_back_of_business_card/index.php)
till it's back up.

------
xioxox
I like this extremely short postscript raytracer I saw quite a few years ago:

[http://www.is.titech.ac.jp/~sadayosi/lab/h-takasi/ops.html](http://www.is.titech.ac.jp/~sadayosi/lab/h-takasi/ops.html)

    
    
      %!IOPSC-1993 %%Creator: HAYAKAWA Takashi <h-takasi@is.titech.ac.jp>
      /C/neg/d/mul/R/rlineto/E/exp/H{{cvx def}repeat}def/T/dup/g/gt/r/roll/J/ifelse 8
      H/A/copy(z&v4QX&93r9AxYQOZomQalxS2w!!O&vMYa43d6r93rMYvx2dca!D&cjSnjSnjjS3o!v&6A
      X&55SAxM1CD7AjYxTTd62rmxCnTdSST0g&12wECST!&!J0g&D1!&xM0!J0g!l&544dC2Ac96ra!m&3A
      F&&vGoGSnCT0g&wDmlvGoS8wpn6wpS2wTCpS1Sd7ov7Uk7o4Qkdw!&Mvlx1S7oZES3w!J!J!Q&7185d
      Z&lx1CS9d9nE4!k&X&MY7!&1!J!x&jdnjdS3odS!N&mmx1C2wEc!G&150Nx4!n&2o!j&43r!U&0777d
      ]&2AY2A776ddT4oS3oSnMVC00VV0RRR45E42063rNz&v7UX&UOzF!F!J![&44ETCnVn!a&1CDN!Y&0M
      V1c&j2AYdjmMdjjd!o&1r!M){( )T 0 4 3 r put T(/)g{T(9)g{cvn}{cvi}J}{($)g{[}{]}J}J
      cvx}forall/moveto/p/floor/w/div/S/add 29 H[{[{]setgray fill}for Y}for showpage

------
szc
There are two other small ray tracers that can be examined. Both are winners
of the International Obfuscated C Code Contest.

Matt Zucker won in 2011 and Anders Gavare won in 2004.

They can be found here, [http://www.ioccc.org/years-
spoiler.html](http://www.ioccc.org/years-spoiler.html)

(The 22nd IOCCC is open for entries until 2013-Oct-03)

------
dinkumthinkum
Very nice article and straight to the point. It's really nice to see a pithy
discussion and impressive demonstration.

------
ggambetta
I love this kind of thing. I've made a similar one (minus texturing) in
Javascript, drawing to a Canvas; my current version is 975 bytes. Output, full
source and live demo here:
[http://gabrielgambetta.com/tiny_raytracer.html](http://gabrielgambetta.com/tiny_raytracer.html)

------
milesf
The output file is .aek but I can't figure out what to do with it. My Google-
fu is failing me this evening.

How do you view the output?

~~~
Pitarou
If you're using Linux or OSX, run it like this:

    
    
      ./aek > aek.ppm
    

That will produce an image in .ppm format. ('The world's second-dumbest
picture format.') You'll probably have to convert it to a more widely
supported format. Make sure you have the netpbm package installed, and then
run, say:

    
    
      pbmtopng aek.ppm > aek.bmp

~~~
ville
What is the worlds dumbest picture format then?

~~~
Sharlin
Raw data without any header, I suppose. You must know or guess the width and
height to properly decode the image.

~~~
evincarofautumn
Guessing the dimensions of an image with _n_ pixels is equivalent to factoring
_n_ , so good luck with that! And only if your luck is really good (prime
width and height) will there be a unique solution—actually you still don’t
know whether to choose portrait or landscape. It gets even more interesting if
you don’t know the number of channels or the pixel format.

~~~
Sharlin
Well, you can check if the image matches common resolutions and aspect ratios
- if there are 307200 pixels, for example, a pretty good guess is that it's
640x480 (or 480x640). You'd need a human to see if the image looks correct -
actually, with a simple GUI, it wouldn't take a human very long at all to
figure out the correct aspect ratio. This could probably be automated easily
enough using some pattern recognition - the "shearing" pattern caused by
guessing the width wrong is pretty linear and well-behaving.

~~~
thibauts
Minimize the gradient ...

------
thenomad
Along the same lines, albeit much less compact - a 99-line Path Tracer (the
next evolution from a straight-up raytracer, performing global illumination
calculations):

[http://www.kevinbeason.com/smallpt/](http://www.kevinbeason.com/smallpt/)

------
kid0m4n
The same thing, implemented in Go:

[https://github.com/kid0m4n/gorays](https://github.com/kid0m4n/gorays)

------
eaxitect
This is really single piece of sh*t I like most for a while... simple and
elegant

