[Gabriel Gambetta] knows a few things about ray tracers, being the author of Tiny Raytracer, a raytracer written in just 912 bytes of JavaScript. As a long-time fellow sufferer of the UK-designed ZX Spectrum, could these two love affairs be merged? Could the Tiny Raytracer fit on the ZX Spectrum? In BASIC? The answer is an affirmative, albeit with our beloved speccy’s many limitations.
The story starts with [Gabriel]’s Computer Graphics From Scratch (CGFS) raytracer algorithms and an existing code base that was ported to the ZX Spectrum’s very limited BASIC dialect, using VSCode for editing, BAS2TAP to generate a tape image file (essentially an audio track) and executed with FUSE. With the toolchain sorted, [Gabriel] adds just enough code to deal with the ray intersection equations of a sphere, and renders a three-sphere scene to a 32×22 pixel colour image, taking a mere 15 minutes of runtime. Fellow sufferers will remember the spectrum had a 32×22 block attribute array (or colour array) with two colour values for foreground and background pixels. Each attribute block contains 8×8 pixels, each of which could be foreground (on) or background (off.) The next stage was then to expand the code to handle pixels as well as blocks, by simply expanding the raytracing to the full 256×176 resolution, and for each block simply determine the two most common colours, and run with those for the whole block. It sort of works, in a very spectrum-esq ‘attribute clash’ kind of fashion.
But now the runtime is 17 hours! Next, a spot of performance tweaking, using quite a few spectrum BASIC hacks, and some graphical approximations such as casting rays for each corner pixel of the block, and if they’re identical, colouring all the remaining 60 pixels the same and moving on. This effort reduced runtime to two hours.
Next [Gabriel] bravely ditches the flat lighting model, models a single light source and pulls out the only remaining trick in the monochrome spectrum world, that of dithering intensity values for each block, using a simple 8×8 ordered dither pattern, that doesn’t look too bad, all things considered. A quick stop on the way to completion, to add shadows and the run time is back to 17 hours, but it’s worth it. Clearly, this is optimised for a single scene type, one where spheres feature predominantly, but the principles are there, and cubes are just a few more lines of code away. Any takers?
Raytracing is one of those fun, but complex tasks that people just love to wedge into inappropriate hardware, like this TI-84Plus CE graphing calculator, and if that’s a bit hard to access, here’s something equally mad running in plain old Excel.
That’s cool. The ZX Spectrum isn’t exactly my favorite platform, but I must admit it has a fine community.
Another outstanding 3D routine was being used in the game ‘Sentinel’ , I believe.
It’s not exactly raytracing, though, perhaps.
True raytracing is very demanding and was making IBM PCs sweat, even.
https://www.youtube.com/watch?v=EMIQ6yPPNW4
Maybe raycasting.
Oh Wow!, CAn’t wait to play with this tomorrow on my Spectrum Next at 28Mhz!!
Very impressive! After all these years, I didn’t know that bright black was the same as not bright black!
Reminded me of VU-3D, https://www.youtube.com/watch?v=6Em-CWYZhG8 .
(And kids these days, just running the emulation speed up and down. I remember my Amiga with 68000@28MHz struggling to emulate Spectrum48 at normal speed.)
Oh wow, I never expected to see my own stuff in Hackaday! This feels like some kind of rite of passage :)
:)
(But don’t be shy to send in tips!)
Is ray-tracing similar to the vector graphics used in Psion’s VU-3D for the Spectrum?
Why BASIC though?
Wow, nice! I ported it to C from BASIC to get a fine 10x speed boost, less than 2 minutes for the low resolution image. Pretty impressive
Here is my C port: https://github.com/ghidosoft/zx-raytracer
16 minutes for the hi-res version :)
Z80-Assembler (aka machine-language) can be a booster for this demanding application.