[HN Gopher] ZX Spectrum Raytracer
___________________________________________________________________
ZX Spectrum Raytracer
Inspired by a recent article in HN about raytracing on some ancient
architecture, I realized that I've implemented many a raytracer in
my life, but never one for my first love, the ZX Spectrum. So I
fixed the glitch. Trigger warning: the source code includes GO TO
statements. Because that's how we did it in the 80s! Enter at your
own peril.
Author : ggambetta
Score : 136 points
Date : 2024-01-24 15:20 UTC (7 hours ago)
(HTM) web link (gabrielgambetta.com)
(TXT) w3m dump (gabrielgambetta.com)
| kinard wrote:
| Amazing stuff, love coming back to speccy code.
| fipar wrote:
| Very nice!
|
| This was almost my first computer (almost because it was actually
| a TK-90) so it's nice to see it here, I guess it was a common
| starting point if you were in a family with a computer in the 80s
| in UY :)
|
| While I know it's not the same (plus I'm a backend guy so I know
| nothing about graphics, a fact that may change in the near future
| as my daughter is set to study animation & videogames after she's
| done with high school next year) but your last version made me
| think of Batman for the Spectrum. I remember thinking that game's
| graphics were magical compared with most of the other games for
| that computer at the time.
| ggambetta wrote:
| Batman is a good example of avoiding attribute clashing by
| going monochrome :) But I have the same memories, huge sprites
| and smooth animation, it was pretty great!
| AndrewStephens wrote:
| I loved that isometric Batman game. I spent an enjoyable 3
| weeks of after school hours beating it on the Amstrad. It was
| just so ... weird.
| lowbloodsugar wrote:
| Nutter. Love it.
| foobarian wrote:
| The thing I loved about Spectrum was game loading graphics from
| tape. Spectrum had a very strange video memory layout, so the
| bitmap would load first into different thirds of the screen (but
| still all monochrome). And then at the end the attributes (which
| were much smaller due to the 8x8 size) would load almost
| instantly, "painting" the monochrome image in a final splash! So
| this is very nostalgic for sure.
|
| And the funny thing is, I like the spectrum renders better than
| the "perfect" ones from a modern computer :-)
| praptak wrote:
| I also remember that there existed cool loaders that were able
| to paint the image in arbitrary order. It was pretty impressive
| because it required doing calculations in the tight loop which
| calculated the delay between slopes of the signal which came
| from tape.
| ggambetta wrote:
| I remember a loader where you could _play a game of
| Mastermind_ while the game was loading. Magic. Blew my mind,
| it 's the kind of thing that wasn't supposed to be possible,
| yet it was...
| becurious wrote:
| There is something like a 171 clock cycle delay in the
| regular tape loaded routine between looking for edge
| transitions in the audio signal. You just break your
| program up into pieces that fits into that. I did one that
| did a countdown timer and broke it into exactly the loop
| delay but I suspect the tape loading would be tolerant to a
| little more inexactness.
| stevekemp wrote:
| There _is_ the possibility to define functions, via "DEF FN":
| 10 DEF FN s(x)=x*x: 20 PRINT FN s(3)
|
| Of course it is limited, as ZX Spectrum BASIC is limited, but it
| is an option.
| ggambetta wrote:
| Sure. I meant functions in the modern programming sense of the
| word, not in the mathematical sense.
| cglace wrote:
| My favorite class in college was building a raytracer from
| scratch and slowly adding features and optimizing. I always
| wanted to keep adding on to the raytracer I made but never found
| the time.
| Keyframe wrote:
| Hence Ray Tracing in One Weekend by raytracing royalty prof.
| Shirley himself https://raytracing.github.io/
| cglace wrote:
| Thanks, I think I might try to work through those with my
| son.
| Marazan wrote:
| It's an excellent book which I have worked through twice,
| once in Python/Numpy and once in Pico-8
| roskelld wrote:
| It would be fun to see a set of frames rendered out and stitched
| together to make an animated sequence. 17 hours per frame. It'll
| be like Pixar where you'd need a render farm of Speccy's to knock
| it out.
| MenhirMike wrote:
| One could "cheat" by running this in an emulator of a massively
| overclocked ZX Spectrum to cut down on the render time and
| still get an authentic end result.
| giantrobot wrote:
| Or fan out the frames to a bunch of emulator instances.
| s_gourichon wrote:
| You mean, like this?
| https://www.youtube.com/watch?v=SJ79CdUMfVA
|
| Also, not exactly the same type or rendering, but basically
| word for word what you wrote: the full-screen fully animated
| parts appear to be "a set of frames rendered out and stitched
| together to make an animated sequence"
|
| https://www.youtube.com/watch?v=o59LrpzGUaE
| Anotheroneagain wrote:
| IDK, but it seems super wasteful: Why not compute RDX and RDX*RDX
| outside the inner loop? Why not precompute COX, COY, COZ and EQC
| once per scene?
| ggambetta wrote:
| (COX, COY and COZ) vary per pixel and per sphere, hence so does
| EQC, so can't really compute them once per scene, unless I'm
| missing something?
|
| RDX yes, and I did that (and a lot more) in the later
| iterations where performance started to become an issue.
| Anotheroneagain wrote:
| I don't see why they would vary? They must remain constant
| for each object.
| ggambetta wrote:
| If you're talking about the first iteration, you're right
| (ROX, ROY, ROZ) is hardcoded to (0, 0, 0), but I decided to
| implement a general algorithm anyway, because performance
| wasn't a problem at that point.
|
| If you can find optimizations that don't obliterate code
| readability for the fifth iteration
| (https://gabrielgambetta.com/zx-raytracer-5-src.html), I'm
| all ears :)
| hoc wrote:
| Waiting on the port for HP calculators in RPL...
|
| (did a 2d morphing animator and a simple cad tool back then. also
| straight forward base algs that you can keep adding to, adding
| some more, and some more...)
|
| Great write-up. Thanks. Love the Spectrum and its direct token
| input despite never owning one.
| jng wrote:
| Beautiful, I love it, congratulations! I started my programming
| journey with Basic on a ZX Spectrum +, then Z80 assembly
| language, then 8086 and the rest from there... 40 years of
| programming and my appreciation for my original platform is still
| there. Thank you for the tribute.
| ggambetta wrote:
| Similar story here. The Spectrum holds a very special place in
| my heart :)
| rahimnathwani wrote:
| The penultimate screenshot looks at least as good as the output
| from VU-3D, a commercial raytracer for the ZX Spectrum. Pretty
| impressive!
|
| https://worldofspectrum.org/software?id=0008953
| Joeboy wrote:
| > each 8x8-pixel block can show one or two different colors, but
| never three or more
|
| That's not _entirely_ true. If you modify the colour attributes
| between the drawing of each row, you can get eight separate
| 2-colour palettes in an 8x8 block. I believe I saw somewhere that
| people had managed this horizontally as well somehow.
| varjag wrote:
| Though it is naturally out of realm of Spectrum BASIC the
| author had this exercise with.
| Joeboy wrote:
| Indeed, but they mention the possibility of redoing it in
| assembly.
| shever73 wrote:
| This is glorious, thank you for sharing. I also started coding on
| the ZX Spectrum and can still remember the Z80 assembler opcodes.
|
| You make a good point about both the simplicity and immediacy of
| the environment, which made it so easy to just start coding.
| mbitsnbites wrote:
| > The ZX Spectrum has a 3.5 MHz Z80 processor (1,000 times slower
| than current computers)
|
| Actually, it's much, much slower than that.
|
| The Z80 takes at least one clock cycle to add or subtract an
| 8-bit number (sometimes several clock cycles, depending on
| addressing mode). For a 32-bit number those clock cycles add up
| quickly.
|
| In contrast, a modern 3.5GHz CPU can add or subtract several
| 64-bit numbers every clock cycle
|
| And don't get me started on multiplication or floating-point
| arithmetic. A modern CPU would be thousands times faster, even if
| it was running at the same clock speed.
|
| Thus, I think that the feat is even more impressive than
| presented!
| adamredwoods wrote:
| http://www.andreadrian.de/oldcpu/Z80_number_cruncher.html
| s_gourichon wrote:
| Excellent! A similar program, apparently from 3 years ago, did
| similar things, in Basic also, on the Amstrad CPC, a machine with
| the same processor, a little more RAM and more (27) colors or
| shades of green, depending on the screen it was hooked to.
|
| * colored spheres (like you did)
|
| * (one) checkerboard surface
|
| * self-shadowing (like you did)
|
| * cast shadows (like you did)
|
| * partial or total specular reflection!
|
| See https://www.cpc-power.com/index.php?page=detail&num=19283
|
| The webpage displays the color (left) and green (right) versions
| on hovering your pointer over the ribbon (above). Image 1 and 2
| are okay in both cases, image 3 is clearly tuned for color
| screen, image 4 for green screen.
|
| Or direct links to the relevant variants:
|
| https://www.cpc-power.com/extra_lire_fichier.php?extra=cpcol...
|
| https://www.cpc-power.com/extra_lire_fichier.php?extra=cpcol...
|
| https://www.cpc-power.com/extra_lire_fichier.php?extra=cpcol...
|
| https://www.cpc-power.com/extra_lire_fichier.php?extra=cpcol...
|
| https://www.cpc-power.com/extra_lire_fichier.php?extra=cpcol...
|
| https://www.cpc-power.com/extra_lire_fichier.php?extra=cpcol...
| ggambetta wrote:
| That's pretty impressive. The main difficulty with reflections
| in the ZX Spectrum is not so much the limited color palette,
| which can be dealt with, but the 2-color limit per 8x8 block.
| It's already a big issue with just lights and shadows as it is
| :-/
| s_gourichon wrote:
| > the 2-color limit per 8x8 block. It's already a big issue
| with just lights and shadows as it is :-/
|
| Well, you impressed me (and others) with your simple bet that
| "hey, what if I simply choose the two most popular colors"
| and just code that in simple BASIC. The same could be done
| with the shading. It would probably pick a good compromise
| when bright yellow meets dark red: by choosing to have the
| few should-be-red pixels become yellow, you avoid a bigger
| obviously-square-grid-based clash of colors.
|
| Next step: error diffusion dithering would IMHO be a good
| bet. But maybe that becomes really to much for Basic.
|
| I've been considering doing Raytracing on the Amstrad CPC,
| but in C. Perhaps using integers only, for speed.
|
| Done that instead: https://cpcitor.itch.io/just-get-9
|
| Hey, found this https://bbcmic.ro/?t=9ctpk via "BBC BASIC
| raytracer in 432 characters (mastodon.me.uk)"
| https://news.ycombinator.com/item?id=39023056#39023768
| Angostura wrote:
| I have absolutely no recollection of being able to put multiple
| statements on a line, separated by : - is that just my old brain
| forgetting stuff, or is there something else going on here?
| becurious wrote:
| It's your brain. You could always do that in ZX Basic
| donio wrote:
| Starting with the Spectrum to be precise. The ZX-81 version
| didn't have that yet.
___________________________________________________________________
(page generated 2024-01-24 23:00 UTC)