Ray-trace a shiny sphere

15

5

I downloaded POV-ray and rendered this shiny metal sphere 90s style:

enter image description here

Your task is to do the same thing, but to do it by implementing the rendering engine yourself in as few bytes as possible. You don't have to replicate this exact image - any image of a reflective sphere above an infinite checkerboard will do, as long as it meets the criteria below.

Rules:

  • The image must depict a reflective sphere hovering above an infinite checkerboard. Both the checkerboard itself and its reflection in the sphere must be shown in the image. It must be visually clear that this is what we're seeing. Beyond this, the details of the geometry, colours, material properties etc. are up to you.

  • There must be some lighting in the scene: parts of the sphere should be darker than other parts, and visually it should be possible to tell roughly where the light is coming from. Beyond that, the details of the lighting model are up to you. (You can invent your own simplified lighting model if you like.) The sphere doesn't have to cast a shadow.

  • The above two criteria - whether it really looks like a shiny sphere above a checkerboard illuminated by a light source - will be judged by the community using voting. Therefore, an answer must have a positive score in order to be eligible to win.

  • The output must be at least 300x300 pixels. It can be displayed on the screen or written to a file, either is fine.

  • Your code should run in less than an hour on a reasonable modern computer. (This is generous - POV-ray renders the above scene practically instantaneously.)

  • No built-in ray tracing functionality may be used - you must implement the renderer yourself.

  • This is , so the positive-scoring entry with the shortest code (in bytes) wins. However, you're also welcome to play the meta-game of getting the most votes by drawing a pretty picture (while keeping the code short of course).

This challenge might seem ridiculously hard, but since the geometry is fixed, the algorithm for rendering such a scene by ray tracing is pretty straightforward. It's really just a case of iterating over each pixel in the output image and evaluating a mathematical expression to see what colour it should be, so I'm optimistic that we'll see some good answers.

Nathaniel

Posted 2014-10-08T12:12:35.663

Reputation: 6 641

I personally dislike the lighting requirement. I think it adds a lot of extra complexity, for very little gain. Just my opinion, though. – stokastic – 2014-10-08T13:16:24.717

You say colours are up to us. Does that include greyscale images? – Martin Ender – 2014-10-08T13:17:56.547

@MartinBüttner yes, greyscale images are fine. – Nathaniel – 2014-10-08T13:26:23.523

@stokastic my hope is that it will be a source of creativity, as people come up with radically simplified but just about convincing lighting models that can be specified in a small amount of code. I've added a note in the question that simplified lighting models are OK. – Nathaniel – 2014-10-08T13:30:23.493

It has already been done: http://fabiensanglard.net/rayTracing_back_of_business_card/index.php Of course this can be made a bit shorter by reducing it to one sphere, removing antialiasing etc.

– Shujal – 2014-10-08T19:26:19.507

@Shugal that's great! But answers to this question can be a lot shorter, as they don't need multiple reflections out any of the other features that program manages to include – Nathaniel – 2014-10-09T00:23:43.643

@stokastic though having played around with my POV-ray scene a bit more, I really wish I'd asked for a sky gradient instead. It makes much more difference than the lighting, and would be a lot less extra complexity. But never mind, it would be unfair to change it now. – Nathaniel – 2014-10-09T07:36:01.813

Related: http://codegolf.stackexchange.com/a/36025/21348

– edc65 – 2014-10-09T22:50:52.847

Answers

28

Python 2, 484 468 467 bytes

enter image description here

i=int;u=249.3
def Q(A,B):
 a=A*A+B*B+9e4;b=B*u+36e4;I=b*b-a*128e4
 if I>0:
    t=(-b+I**.5)/(5e2*a);F,G,H=A*t,B*t,u*t;J,K,M=F,G+.6,H+2.4;L=a**-.5;k=2*(A*J+B*K+u*M)*L;C,D,E=A*L-k*J,B*L-k*K,u*L-k*M;L=(C*C+D*D+E*E)**-.5;t=(-4e2-G)/D;return(D*D*L*L*u,((i(F+t*C)/200+i(H+t*E)/200)&1)*(u*D*L))[D>0]
 else:return(u*B*B/a,((i(-2e2/B*A)/200+i(-6e4/B)/100)&1)*u*B/a**.5)[B>0]
open("s.pgm","wb").write("P5 800 600 255 "+"".join(chr(i(Q(j%800-4e2,j/800-u)))for j in range(480000)))

Note: after if I>0: there is a newline followed by a single tab char before t=...

Running the program will create an 800x600 image named s.pgm

Started from a "real" ray tracer formulas (tweaked a bit for golfing).

Rendering takes about 3s on my dead old PC (0.7s with pypy).

6502

Posted 2014-10-08T12:12:35.663

Reputation: 456

4Beautiful image! – Nathaniel – 2014-10-12T14:03:27.123

You can save a few bytes without doing the zlib trick by replacing 0000 with e4 throughout. – Nathaniel – 2014-10-13T01:18:54.073

@Nathaniel:Doh... very big mistake for a code golf :-) Fixed. I've also removed the zlib packing trick because I've to investigate on its legality (the latest version for example when zipped works with standard python but doesn't work with pypy, and that's very strange). – 6502 – 2014-10-13T12:53:56.223

Another code golf trick, you can replace a if b else c with (c,a)[b] so long as you don't rely on short-circuiting to avoid e.g. division by zero errors. Also if A:code;return B\nelse:return C you can replace with code;return(C,B)[A]. – Claudiu – 2014-10-13T17:11:20.913

@Claudiu: Thanks for the suggestion. I had to change the parameters a bit to avoid a division by zero. I also used a single loop over the image and that saved a lot. – 6502 – 2014-10-13T20:02:44.393

Wow, this is very impressive. I assume you've done assembly programming before? (judging by your username) – qwr – 2014-10-13T20:14:18.837

qwr: ah... you caught me. Indeed I started programming in asm on an Apple 2, back in 1981 :-D – 6502 – 2014-10-13T20:42:07.407