Hacker Newsnew | comments | ask | jobs | submitlogin
Recursive raytracer in 35 lines of JavaScript (jsfiddle.net)
266 points by ggambetta 19 hours ago | 94 comments




Taylorious 18 hours ago | link

This is very cool. Interestingly it was generated by Google's Closure compiler. The author has the full source with excellent comments on his site.

link: http://www.gabrielgambetta.com/tiny_raytracer.html

reply

10098 18 hours ago | link

from his site:

> Their combination of a simple algorithm and stunning results are hard to beat.

that's exactly what fascinates me about raytracing. It's pretty straightforward, you literally emulate the light bouncing around, but given enough resources the results can be surprisingly good-looking.

reply

maggit 16 hours ago | link

For interest, the method of literally emulating light bouncing around seems to be called Photon tracing (http://en.wikipedia.org/wiki/Photon_tracing). It creates realistic renderings of just about anything if you can afford the time to render it. Rendering times are prohibitively high, though, because this rendering method emulates lots of photons that never hit the sensor.

Ray tracing, although very powerful, has some limitations because it goes the other way: It casts rays from the sensor into the scene.

reply

ohwp 16 hours ago | link

This is where path tracing steps in. Bi-directional path tracing combines both photon tracing and ray tracing. http://en.wikipedia.org/wiki/Path_tracing

reply

logicallee 6 hours ago | link

could you elaborate on where the symmetry breaks down?

From your comment and another one here, it seems to be the case that actually some of the photons that don't hit the sensor still affect the image (either that, or you can't get back to the source starting at the sensor for some of the photons). In other words, if a light source emits a trillion photons everywhere in the room, and your sensor (the idealized camera) catches ten million photons, then it's not strictly equivalent to trace back the ten million maths to the light source, and ignore the ones that didn't make it to the idealized camera.

If it were equivalent, you wouldn't need "photon tracing and ray tracing" or bidirectionality.

But I'm struggling at where the symmetry breaks down, since it seems that tracing a path back from the sensor along the same angles should produce the same result as tracing it forward from the light source - for the photons that directly or indirectly (after a certain number of bounces or passing through the materials) make it to the idealized camera.

But the ones that don't make it to the idealized camera - how can they still affect the frame? Or (equivalently), when is it the case that you can trace it forward to the camera but not backward from the camera?

Why do you need bidirectionality? Where does the symmetry break down?

reply

zeidrich 4 hours ago | link

When you do photon tracing, you begin with beams of known intensity, wavelength, direction because you are aware of the light source. That combines with everything else that hits the sensor to give the image.

When you do ray tracing, you don't immediately know if 10 million photons were captured. You know how many rays you are going to send based on the resolution of the image. This also means there's issues with say light coming from narrow apertures because you limit yourself to a finite number of rays.

If you use photon tracing and a light source sends 10 million photons and 70,000 are absorbed that's 70,000 data points to define the image which may be plotted on a 200x200 canvas. If you use ray tracing with a 200x200 canvas you will have the same size of image, but only get 40,000 samples. Even if you expand the size of the canvas, there may be some photons which can reach the camera but whose path the ray tracer can't reach.

For instance, say some photons hit the camera at pixel x-coordinates 10.0003 to 10.0005 through a fine aperture.

This will illuminate the camera in a photon tracing simulation. The ray tracer will not capture that photon unless its resolution were 10,000 times higher. The ray tracer will trace back from 10, 11. It can't do every intermediary step. The photon tracer can account for those circumstances.

reply

jheriko 8 hours ago | link

ray tracing is conceptually the same as following the reverse path an idealised 'photon' takes - that photon being the classical 'ray of light' idea.

photon tracing is quite different - instead of starting from the pixel you accumulate your results.

as such i consider the original comment not only accurate, but insightful. (if ambiguous)

reply

tunnuz 14 hours ago | link

A nice and thorough book about raytracing-like techniques (including photon tracing), and their capabilities is "Advanced Global Illumination" (http://sites.edm.uhasselt.be/agibook). It is very interesting.

reply

huskyr 17 hours ago | link

Very nice indeed! I especially like the fact that the source is so well annotated, which makes me wonder: why bother with minifying it at all and not simply use the unminified source on Jsfiddle?

reply

biot 16 hours ago | link

From the jsfiddle source:

  // Non-minified source in 35 lines for HN, because it's the latest fad :)
https://www.hnsearch.com/search#request/submissions&q=%2235+...

reply

beaker52 15 hours ago | link

It was 30 lines, but artistic license accepted I guess.

https://www.hnsearch.com/search#request/submissions&q=%2230+...

reply

shimonamit 17 hours ago | link

The author writes in the link:

> Note that the goal here was to make the source code as small as possible, not clarity; so even the original code before minification is a horrible mess. This doesn’t do justice to the elegance and simplicity of proper raytracer code; I’m writing a book to right this wrong.

reply

mangotree 16 hours ago | link

The live demo on his site works on the ipad. Amazing.

reply

themstheones 12 hours ago | link

It's just done with a 2d canvas element. It's been supported in most browsers for a very long time.

reply

CmonDev 14 hours ago | link

Why?

reply

nkoren 10 hours ago | link

Sigh. Kids these days...

Raytracing is not exactly a lightweight calculation. My first raytracer was TurboSilver 3D on the Amiga, in 1990 (actually one of the first commercial raytracers ever produced). "Photorealistic" images at 7.5 Mhz. For an image like this, you'd set up the scene, hit the render button, and grab a quick lunch. When you came back, the scene would be about 2/3rds rendered, and you'd watch it for a while, thrilled by every new pixel that pushed itself onto the screen. Then you'd go get coffee and hope the scene was done when you got back.

Now, the same scene (say, 320x200px) renders in an eyeblink on my phone, driven by a high-level universal scripting language I can tweak at will. This is beyond amazing. It's fucking transcendent.

(Oy vey, I feel old. Where'd I put my dentures? BTW: get off my lawn, etc.)

reply

gorrillamcd 9 hours ago | link

"Old people are the greatest. They're full of knowledge and wisdom." Is it ok to quote Spongebob here? In this case, I say yes.

reply

ohwp 16 hours ago | link

If you like this, maybe you also like this Path Tracer written in 99 lines of C++:

http://www.kevinbeason.com/smallpt/ (+ source code and explanation)

reply

reirob 14 hours ago | link

Thanks for sharing this. Especially on the page there is a presentation as well as several ports of this same program to other languages like OCaml, Haskell and JavaScript. Interesting to see that the OCaml version is on par with the C++ version performance wise, but is 47% shorter. However the Haskell version is not shorter and 4.5 times slower?

reply

thenomad 14 hours ago | link

And here's a comparison between that (smallpt) and the equivalent (smallptGPU) using a GPU:

http://davibu.interfree.it/opencl/smallptgpu/smallptGPU.html

All VERY interesting stuff.

reply

hxa7241 12 hours ago | link

And if you like that (spheres only), you might also like this (general triangles-based), in 444 lines of Scala (and OCaml, Python, Ruby, Lua, Scheme, C++, and C):

http://www.hxa.name/minilight/

reply

1gn1t10n 11 hours ago | link

All this reminds me of Paul Heckbert's ray tracer written on the back of his business card: http://www.cs.cmu.edu/~ph/src/minray/minray.card.c

reply

eonil 16 hours ago | link

Even more interesting!

reply

ggambetta 16 hours ago | link

Now that is impressive.

reply

onion2k 18 hours ago | link

Impressive not only from a "ooo-that's-clever" perspective, but it's also readable, tweakable code. Many of these tiny JS toys aren't things you can really do anything with; this example is a great basis for learning.

reply

ggambetta 17 hours ago | link

Glad you liked it. It should be far more readable, though; the constraint here was code size in bytes, so even the non-minified code (http://gabrielgambetta.com/tiny_raytracer_full.js) is quite hacky (especially with the global vars, the horrible "tImageData" hack, the assignments within if conditions, putting all the sphere data in a flat array and playing with the indices,...)

reply

cocoflunchy 12 hours ago | link

I'm currently trying to write a raytracer in Python (I know, I know) but I'm already at like 200 lines and no reflections, refraction, shadows or light sources :(

But I won't quit! If you're interested, I'm already proud of what I have :) http://i.imgur.com/8wwSsab.png

reply

bemmu 18 hours ago | link

Replace first line with this to get rid of jaggies with "supersampling" :)

var w = 1000;c.style.width = '500px';

reply

d55 16 hours ago | link

Also, increase the last int in line 34 to get deeper reflections.

reply

ggambetta 17 hours ago | link

Wow, awesome! I'll definitely add that :)

reply

thenomad 14 hours ago | link

Along similar lines and (arguably) even cooler: full-on path tracing in WebGL using a GLSL shader:

http://madebyevan.com/webgl-path-tracing/

reply

hrjet 12 hours ago | link

That has been optimised further by this guy here: http://mmmovania.blogspot.in/2011/11/snapshot-from-my-latest...

reply

chii 12 hours ago | link

his other stuff is also really amazing: http://madebyevan.com/webgl-water/

reply

cobrausn 11 hours ago | link

Impressive, especially since it is still fairly readable. On the other end of the spectrum, I give you raytracing on the back of a business card, in C++.

http://fabiensanglard.net/rayTracing_back_of_business_card/

reply

ggambetta 6 hours ago | link

Not quite "the other end" - the code I posted can be reduced to 960 bytes: http://gabrielgambetta.com/tiny_raytracer.html

reply

lignuist 18 hours ago | link

Those [anything] in [n] lines of JavaScript pieces are a great way to dive into the code in order to learn. It is usually much easier to read through 30 lines than through 3000 lines. So it probably not very important that these projects are not finished products.

reply

CmonDev 17 hours ago | link

You should try Perl - it's even less readable.

reply

lignuist 17 hours ago | link

I'm not looking for a language that is hard to read.

The great thing about such demos is, that everyone is able to read and run it within minutes.

reply

CmonDev 13 hours ago | link

Yeah, readability is definitely an objective when you are trying to cram into ~30 lines.

reply

lignuist 8 hours ago | link

Try to read 30 lines of Brainfuck if you are a fan of unreadable languages. :)

http://en.wikipedia.org/wiki/Brainfuck

reply

kitsune_ 16 hours ago | link

Computers have become fast, I remember rendering a scene like this in PovRay in the mid-90's and it took hours.

reply

vittore 5 hours ago | link

Guys if you have links to other tiny things in js like that, of about 30 lines of code or less, please send me links. http://30lines.info

reply

staunch 7 hours ago | link

If you haven't seen this yet, "The Physics of Light and Rendering | A Talk by John Carmack" is really enjoyable.

http://www.youtube.com/watch?v=MG4QuTe8aUw

reply

albertzeyer 14 hours ago | link

Raytracing works really good when you use the GPU for calculation, e.g. via OpenCL or CUDA.

I just checked, there is already WebCL and an implementation for WebKit (https://github.com/SRA-SiliconValley/webkit-webcl).

Here is a video: http://www.youtube.com/watch?v=9Ttux1A-Nuc

reply

filipedeschamps 17 hours ago | link

Amazing job.

This is one of the coolest points of Javascript IMHO: you can see the result and interact with it directly in your browser. Right here you will find someone tweaking the code for supersampling, and you can apply it yourself and see the result without hassle.

This generates an uncontrollable and very positive propagation effect.

reply

nwh 13 hours ago | link

Change the "w" variable to > 9000 and it completely kills Safari, can't even close the tab or the browser. Sweet demo though, I remember being amazed seeing this sort of thing the first time.

reply

be5invis 15 hours ago | link

I've got an interesting performance measurement:

On Chrome 31, it takes 3307 ms to render the image and on IE11 it takes only 2320 milliseconds.

So am I in the matrix?

reply

fekberg 17 hours ago | link

I think this is awesome, however, I think it would be even more awesome to get a walk through of the code and the thought process behind minifying it in a blog post, the past days with all the jsfiddles are nice so don't get me wrong on that part. I just think it adds more value if the code is somewhat explained (I know ray tracing is explained on tons of places). Just my two cents.

reply

davidpardo 15 hours ago | link

You can find the whole commented source at http://www.gabrielgambetta.com/tiny_raytracer_full.js

reply

fekberg 9 hours ago | link

Thank you for that!

reply

IvanK_net 10 hours ago | link

I have written Path Tracer in JS (http://renderer.ivank.net/) and rendered these images: http://renderer.ivank.net/balls.jpg http://renderer.ivank.net/cornell.jpg

but nobody is talking about it :( Maybe I should render a movie or something.

reply

ggambetta 10 hours ago | link

That's really impressive! Someone did post links to SmallPT somewhere in this discussion, though.

reply

brador 15 hours ago | link

I'm loving this jsfiddle 1-upmanship. Really squeezing out what it's capable of.

reply

snake_plissken 5 hours ago | link

Anyone got some good links to the algebra/geometry behind raytracing?

reply

berkut 5 hours ago | link

Depends how far you want to take it...

There's plenty of links on the web, but if you're really serious (it can be quite addictive writing one), get hold of the "Raytracing/Rendering bible" : Physically Based Rendering by Matt Pharr and Greg Humphreys.

There's also a plethora of research freely available with cutting edge techniques to read.

reply

jcutrell 18 hours ago | link

This is absolutely fantastic. Really impressive work with the material itself.

reply

10098 18 hours ago | link

pretty sure it's using standard blinn-phong shading. however, with the added shadows and reflections it becomes much more interesting, doesn't it? :)

reply

ggambetta 17 hours ago | link

Right, just diffuse + specular with different coefficients. Nothing fancy about the materials.

reply

jcutrell 9 hours ago | link

Makes sense - I'm not super familiar with how to make that happen in JS, so it's all new to me. :)

reply

jheriko 8 hours ago | link

i dont really understand why these things are considered impressive. all of the technically challenging bits are handled by the enormous stack of technology involved.

granted the js is highly size optimised, and that probably required some reasonable effort. i see nothing clever here at all. also, the fact that its 35 lines is a weird measure - i can see ways to reduce that trivially - why isn't everything to do with the render baked into the final loop?.

the byte count is a more useful measure.

4k/64k executable demos are much more impressive - even though there is a stack of technology underneath you have to do things like butcher your C/C++ standard libraries or not use them at all...

reply

PhasmaFelis 5 hours ago | link

> i dont really understand why these things are considered impressive. all of the technically challenging bits are handled by the enormous stack of technology involved.

For one thing, it's a reminder of how awesome the technology stack that we all take for granted is.

reply

DanBC 4 hours ago | link

Feel free to release a bunch of your own Thing in 30 lines, or to code-golf all the existing Things in 30 lines to 5 lines, or whatever.

reply

jebblue 12 hours ago | link

That's impressive to me, don't like JavaScript but doing that is impressive. It's also interesting to see how useful a canvas element is.

reply

gumuz 16 hours ago | link

Awesome! I tried to look into building a simple raytracer many times, but the either math gets me everytime or I just didn't come across the right "raytracer for dummies" tutorials.

Any suggestions?

reply

ohwp 15 hours ago | link

For many year I also tried to build a simple ray tracer. The math got me to, but in the end I was able to write different types of render engines.

What helped me:

  learn about vectors
  learn about (vector) normalization
  learn about camera models http://www.ventrella.com/Ideas/Camera/Arm_Camera.pdf
  learn about pixels (pixels are just dots without size)
  use a 3D coordinate-system that works for you (mine is: x = right, y = forward, z = up)
  start with a simple camera model (always looking forward)
  normalize all direction vectors
  place the screen of pixels 1 unit in front of the camera
  normalize the screen of pixels
  know that the center pixel is on the forward vector of the camera
  try to calculate a vector from the camera position to the left top of the pixel screen in front of the camera

reply

ggambetta 16 hours ago | link

The fully commented (but not entirely clean) code is here: http://www.gabrielgambetta.com/tiny_raytracer_full.js

Also, I'm halfway through writing a Computer Graphics textbook, half of it dedicated to raytracing.

reply

jamiek88 12 hours ago | link

I'd buy it, please post the link once its done, or if you want any proof readers or people to type in the code to check for typos I'd be happy to help.

reply

ttty 17 hours ago | link

Why this?

// Shorten some names. var math = Math;

reply

choult 17 hours ago | link

Capital letters are bigger, and therefore take up more space.

reply

stickupkid 17 hours ago | link

No.

reply

minikomi 17 hours ago | link

Because when it's run through the Google closure compiler it becomes

    E=Math,F=E.sqrt,G=E.max

reply

ggambetta 17 hours ago | link

For minification, as someone else said. I originally wrote this for a JS1K competition some years ago, so it's not geared towards readability, but towards small code size.

I had a really, really ugly trick that saved me a couple of bytes which I removed before posting to HN. I figured out I was using canvas.getImageData() and canvas.putImageData(). So I did this: var tID = "tImageDatA"; canvas["ge"+tID](); canvas["pu"+tID"](); You can see that in the original source: http://gabrielgambetta.com/tiny_raytracer_full.js

Not my proudest hack :D

reply

merkitt 17 hours ago | link

I just looked at this childhood drawing of yours: http://www.gabrielgambetta.com/img/1986-listado.jpg

Is that BASIC CODE mixed in with bugs bunny??! Raytracer or no raytracer, this is exceedingly cool.

reply

ggambetta 16 hours ago | link

Yes, that is (my 5 year old idea of) ZX Spectrum Basic. It follows the format of the listings published in Microhobby (http://microhobby.speccy.cz/mhf/031/MH031_08.jpg - in particular, look at the "NOTAS GRAFICAS" sidebar). I grew up with that :) My programming has improved, my drawing abilities not so much.

reply

davidpardo 15 hours ago | link

I remember typing that listing, almost thirty years ago. I owe a lot of what my life is now to Microhobby.

reply

ggambetta 13 hours ago | link

Microhobby FTW. I have the exact same feeling, but more generally about the Spectrum.

reply

jamiek88 12 hours ago | link

Me too but more about the BBC B and the Amstrad CPC 464!

BBC Basic was amazing in hindsight.

Bugs Boni !

reply

rejschaap 17 hours ago | link

That is before minifying. The variable name "math" was chosen for readibility in the non-minified version. The variable math can be renamed during the minifying process to a short identifier, in this case "E". Since the Math object is used quite a lot, it is worth the assignment to rename it.

reply

jbochi 15 hours ago | link

Closure compiler will rename the math variable.

reply

eonil 16 hours ago | link

This is interesting!

reply

mrcactu5 13 hours ago | link

it is great to see the reflections upon reflections.

reply

ggambetta 13 hours ago | link

<inception>Reflections upon reflections? We need to go deeper.</inception>

reply

ThePhysicist 16 hours ago | link

mind = blown

reply

jasongaya 15 hours ago | link

Great, thanks for share with us.

reply

10098 18 hours ago | link

To be fair, it's not exactly a "raytracer", it's a program capable of rendering that specific scene (i.e. bunch of spheres) using a recursive raytracing algorithm, which isn't awfully complex in itself. Not trying to say it's bad or anything, just want to point out that it's not very surprising for something like this to be under 100 loc in a high-level language.

reply

GuiA 18 hours ago | link

A tiny tip coming from a friendly place, if I may- your comment comes off as slightly pedant and elitist. I'm sure it was not in your intention to bring down the original author of this demo, who is probably very excited about what he worked hard on, but rather to highlight how deep of a field raytracing is and to encourage him to not be content with this first venture into it, and to explore more of it.

A good way to do that is to write your comment from a "Yes and..." perspective, rather than a "Yes but..." perspective. In one case you're showing the author how tall the wall front of him is, in the other you show him how you yourself climbed that wall when you were in his position.

It helps a lot :)

reply

dalek_cannes 16 hours ago | link

I just checked out the author's site. He seems much higher up that wall than grandparent poster :)

- born in uruguay

- worked his way up to google

- learned BASIC at 5 (and made childhood drawings that included handwritten basic code)

- read First Blood at 9

- wrote first short story at 7

Meanwhile I go to grandparent poster's site and find... well. I think I sort of understand where the criticism is coming from.

reply

10098 16 hours ago | link

and you find a blog with 1.5 semi-coherent posts and a shitty sidescroller? :-)

I'm not criticizing the author or his work, I'm just saying that writing a recursive function that does p + kv recursively shouldn't take a lot of code. Do I need to end each comment with a smiley face to prevent it from being taken the wrong way?

reply

GuiA 4 hours ago | link

I don't think it's a matter of adding a smiley at the end of each comment (although I love smileys, so I do that too :-)

I think it's more a matter of saying "Yes, good job on figuring out how to do p + kv recursively! Here are links to {papers|books|lectures|other code} that go further if you want to explore this topic more" rather than saying "Oh, you figured out how to do p + kv recursively, just like millions of other CS freshman. Good for you".

It's the little details that make online communities pleasant :)

reply

ggambetta 15 hours ago | link

I agree with you, it's not a very complicated thing. But that's the beauty of it - raytracers are simple but produce stunning images (it is a raytracer, though - it traces rays! Plus it does ambient + point lights, reflections, shadows... the kind of stuff raytracers do)

It doesn't take a lot of code, sure. But "a cross-platform game framework in 100,000 lines of C++" is not the current fad in HN ;)

reply

antirez 17 hours ago | link

To be fair, you are wrong. It is totally a ray tracer, there is the top variable that is the description of the scene and you can hack the positions and see how the scene changes. Also it is proper ray tracing as far as it goes from the point of view of the algorithm used to cast rays, it finds the closest intersection and so forth. The most obvious limitation is just support for a single kind of geometric primitive: the sphere.

reply

yason 18 hours ago | link

I didn't know there's a required set of features for raytracer besides tracing rays.

If it uses a recursive raytracing algorithm does that not make it a raytracer? It traces rays recursively like all, well, ray tracers.

reply

10098 17 hours ago | link

Well, to answer that question, let me make an analogy. There's no required set of features for calculators either. Technically a tiny box that can only add two numbers can be considered a calculator, since it calculates. I guess we might call it so, but it isn't the same, is it?

It's just that people tend to think about povray and renderman when "raytracers" are mentioned, and thus, fitting a raytracer into 30 lines of javascript may seem impossible, while actually it's entirely possible because the core idea of the algorithm is quite simple - this is what this demo shows and it is exactly the reason it's a good demo.

reply

coldtea 17 hours ago | link

>It's just that people tend to think about povray and renderman when "raytracers" are mentioned, and thus, fitting a raytracer into 30 lines of javascript may seem impossible

Not really. At least neither me, nor (I'd say) the HN crowd, would expect something like povray or renderman given the title of the article.

What we'd expect, an implementation of a ray tracing algorithm, and not a full featured program, we got.

reply




Lists | RSS | Bookmarklet | Guidelines | FAQ | DMCA | News News | Feature Requests | Bugs | Y Combinator | Apply | Library

Search:

::...
免责声明:
当前网页内容, 由 大妈 ZoomQuiet 使用工具: ScrapBook :: Firefox Extension 人工从互联网中收集并分享;
内容版权归原作者所有;
本人对内容的有效性/合法性不承担任何强制性责任.
若有不妥, 欢迎评注提醒:

或是邮件反馈可也:
askdama[AT]googlegroups.com


点击注册~> 获得 100$ 体验券: DigitalOcean Referral Badge

订阅 substack 体验古早写作:


关注公众号, 持续获得相关各种嗯哼:
zoomquiet


自怼圈/年度番新

DU22.4
关于 ~ DebugUself with DAMA ;-)
粤ICP备18025058号-1
公安备案号: 44049002000656 ...::