ZX Spectrum Raytracer
ZX Spectrum Raytracer
Not mine, but I found it interesting. I wonder how much faster it would run in machine code.
https://gabrielgambetta.com/zx-raytracer.html
https://gabrielgambetta.com/zx-raytracer.html
- flatduckrecords
- Manic Miner
- Posts: 933
- Joined: Thu May 07, 2020 11:47 am
- Location: Oban, Scotland
- Contact:
Re: ZX Spectrum Raytracer
The sources are listed in the article but here's a .tap file I made if anyone else wants to try it out:
zxrt.tap
zxrt.tap
Re: ZX Spectrum Raytracer
320x192, 8bpp in SpecBAS:
Re: ZX Spectrum Raytracer
Sure
It's been updated for varying resolutions, and added ORIGIN FLIP to get the graphics upside-down.
Code: Select all
2 origin flip: PAPER 0: INK 7: CLS : let TME=MSECS: LET SW=SCRW/2: LET SH=SCRH/2: GO SUB 8000: GO SUB 7000: DIM C(64): DIM L(64): LET DZ=(ScrW/800)*2: FOR X=0 TO scrw-1 STEP 8: FOR Y=0 TO scrh-1 STEP 8
40 LET DX=(X-SW)/256: LET DY=(Y-SH)/256: GO SUB 1000: LET CTL=PC: LET LTL=PL: LET DX=(X-SW+7)/256: GO SUB 1000: LET CTR=PC: LET LTR=PL: LET DY=(Y-SH+7)/256: GO SUB 1000: LET CBR=PC: LET LBR=PL: LET DX=(X-SW)/256: GO SUB 1000: LET CBL=PC: LET LBL=PL
51 IF CTL=0 AND CTR=0 AND CBR=0 AND CBL=0 THEN GO TO 500
111 LET CI=1: DIM A(8): LET PL=0: FOR U=X TO X+7: LET DX=(U-SW)/256: FOR V=Y TO Y+7: IF CI=1 THEN LET PC=CTL: LET PL=LTL: GO TO 160
141 IF CI=8 THEN LET PC=CBL: LET PL=LBL: GO TO 160
142 IF CI=57 THEN LET PC=CTR: LET PL=LTR: GO TO 160
143 IF CI=64 THEN LET PC=CBR: LET PL=LBR: GO TO 160
150 LET DY=(V-SH)/256: GO SUB 1000
160 LET A(PC+1)=A(PC+1)+1: LET C(CI)=PC: LET L(CI)=PL: LET CI=CI+1: NEXT V: NEXT U: LET MFC=0: FOR C=2 TO 8: IF A(C)>MFC THEN LET MFC=A(C): LET MFI=C
204 NEXT C: LET FC=MFI-1: INK FC
301 LET CI=1: FOR U=X TO X+7: FOR V=Y TO Y+7: IF C(CI)>0 AND H(CI)<=L(CI) THEN PLOT U,V
325 LET CI=CI+1: NEXT V: NEXT U
500 NEXT Y: GO SUB 3000: PRINT AT 0,0; INK 7;(msecs-TME)/1000: NEXT X: STOP
1000 LET MT=1E10: LET A=2*(DX*DX+DY*DY+DZ*DZ): FOR S=1 TO NS: LET B=2*(DX*S(S,1)+DY*S(S,2)+DZ*S(S,3)): LET C=(S(S,1)*S(S,1)+S(S,2)*S(S,2)+S(S,3)*S(S,3))-S(S,4): LET D=B*B-2*A*C: IF D<0 THEN GO TO 1500
1231 LET D=SQR (D): LET T=(B+D)/A: IF T>0 AND T<MT THEN LET PC=S(S,5): LET MT=T: LET CS=S
1250 LET T=(B-D)/A: IF T>0 AND T<MT THEN LET PC=S(S,5): LET MT=T: LET CS=S
1500 NEXT S: IF MT=1E10 THEN LET PC=0: RETURN
1600 LET IX=DX*MT: LET IY=DY*MT: LET IZ=DZ*MT: LET NX=IX-S(CS,1): LET NY=IY-S(CS,2): LET NZ=IZ-S(CS,3): LET PL=AI: GO SUB 2100: IF H=1 THEN RETURN
1615 LET NL=(NX*LX+NY*LY+NZ*LZ): IF NL>0 THEN LET PL=PL+DI*NL/SQR (NX*NX+NY*NY+NZ*NZ)
2000 RETURN
2100 LET A=2*(LX*LX+LY*LY+LZ*LZ): FOR S=1 TO NS: LET CX=IX-S(S,1): LET CY=IY-S(S,2): LET CZ=IZ-S(S,3): LET B=-2*(CX*LX+CY*LY+CZ*LZ): LET C=(CX*CX+CY*CY+CZ*CZ)-S(S,4): LET D=B*B-2*A*C: IF D<0 THEN GO TO 2210
2160 LET D=SQR (D): LET T=(B+D)/A: IF T>0.01 THEN LET H=1: RETURN
2190 LET T=(B-D)/A: IF T>0.01 THEN LET H=1: RETURN
2210 NEXT S: LET H=0: RETURN
3000 RETURN
7000 DIM H(64): RESTORE 7100: FOR I=1 TO 64: READ H(I): LET H(I)=H(I)/64: NEXT I: RETURN
7100 DATA 0,32,8,40,2,34,10,42
7101 DATA 48,16,56,24,50,18,58,26
7102 DATA 12,44,4,36,14,46,6,38
7103 DATA 60,28,52,20,62,30,54,22
7104 DATA 3,35,11,43,1,33,9,41
7105 DATA 51,19,59,27,49,17,57,25
7106 DATA 15,47,7,39,13,45,5,37
7107 DATA 63,31,55,23,61,29,53,21
8000 LET LX=-1/SQR (2): LET LY=1/SQR (2): LET LZ=0: LET AI=0.075: LET DI=1-AI: RESTORE 9000: READ NS: DIM S(NS,5): FOR S=1 TO NS: FOR I=1 TO 5: READ S(S,I): NEXT I: NEXT S: RETURN
9000 DATA 4
9001 DATA 0,-1,4,1,2
9002 DATA 2,0,4,1,1
9003 DATA -2,0,4,1,4
9004 DATA 0,-5001,0,5000^2,6
Re: ZX Spectrum Raytracer
Re: ZX Spectrum Raytracer
Your version of SpecBAS is too old. Grab a new executable from here: https://github.com/ZXDunny/SpecBAS/blob ... pecBAS.exe and replace your exe with that one.
Re: ZX Spectrum Raytracer
Well hello there! I wrote the raytracer, and I'm beyond flattered that you guys found it interesting enough to play around with it
I've been toying with different ways to improve the attribute clash even more, here's as far as I got:
What it does is computing the average intensity of the two most frequent colors in each 8x8 block. If both are "bright", it PLOTs all the pixels, in either color. If one is "dark" and one is "bright", it does ordered dithering of the "bright" one. If both are "dark", it does ordered dithering of the most frequent one.
Works decently well, but the tradeoff is that the dark areas of the image lose some "light intensity resolution" (i.e. areas that should be ordered-dithered look all black instead).
I'd appreciate any ideas
I've been toying with different ways to improve the attribute clash even more, here's as far as I got:
What it does is computing the average intensity of the two most frequent colors in each 8x8 block. If both are "bright", it PLOTs all the pixels, in either color. If one is "dark" and one is "bright", it does ordered dithering of the "bright" one. If both are "dark", it does ordered dithering of the most frequent one.
Works decently well, but the tradeoff is that the dark areas of the image lose some "light intensity resolution" (i.e. areas that should be ordered-dithered look all black instead).
I'd appreciate any ideas
- bluespikey
- Dynamite Dan
- Posts: 1138
- Joined: Tue Jun 30, 2020 3:54 pm
Re: ZX Spectrum Raytracer
It looks very good. Are other shapes available like oblongs, can spheres occupy the same space to create new shapes like egg shapes?
- ParadigmShifter
- Dynamite Dan
- Posts: 1779
- Joined: Sat Sep 09, 2023 4:55 am
Re: ZX Spectrum Raytracer
+1 for oblong, my favourite shape name. I think you mean oblongoids though?
- flatduckrecords
- Manic Miner
- Posts: 933
- Joined: Thu May 07, 2020 11:47 am
- Location: Oban, Scotland
- Contact:
Re: ZX Spectrum Raytracer
@ggambetta’s book Computer Graphics from Scratch explains how it all works but here’s a snippet from section one:
Part 1, Section 1, Basic RaytracingWe could choose any arbitrary geometric primitive as the building block of our scenes; for raytracing, we’ll use spheres because they’re easy to manipulate with equations.
- ParadigmShifter
- Dynamite Dan
- Posts: 1779
- Joined: Sat Sep 09, 2023 4:55 am
Re: ZX Spectrum Raytracer
Well it's all parametric rather than polygons so they could have had more variety.
Oblongoids, Cylinders, Cones and Tori are all popular. Tori are a bit gnarly working out intersections though IIRC.
Oblongoids, Cylinders, Cones and Tori are all popular. Tori are a bit gnarly working out intersections though IIRC.
Re: ZX Spectrum Raytracer
Hi, if the timing is importend you should 0 the TIME by POKE 23672,0: POKE 23673,0: POKE 23674,0 just before you start the real calculationggambetta wrote: ↑Mon Jan 29, 2024 8:46 am Well hello there! I wrote the raytracer, and I'm beyond flattered that you guys found it interesting enough to play around with it
I've been toying with different ways to improve the attribute clash even more, here's as far as I got:
What it does is computing the average intensity of the two most frequent colors in each 8x8 block. If both are "bright", it PLOTs all the pixels, in either color. If one is "dark" and one is "bright", it does ordered dithering of the "bright" one. If both are "dark", it does ordered dithering of the most frequent one.
Works decently well, but the tradeoff is that the dark areas of the image lose some "light intensity resolution" (i.e. areas that should be ordered-dithered look all black instead).
I'd appreciate any ideas
btw, if you set your GO SUBS at the beginning of the whole program they are found quicker. meaning LINE 1000 should be LINE 10
and presetting al variables is best done first indeed, but at the back of the memory meaning the invoking off the variables is best done in LINE 9900 eg with a GO TO 1 to move to the start of the program
do you have a version 4 ?
i look at the rendering of version 3 now
EDIT
he, you have 5 versions already
https://gabrielgambetta.com/zx-raytracer-5-src.html
all above comments still valid,
AND removing all EXTRA S P A C E S will speed up aswell, since ZX Basic is "live decoded" meaning every CHR$ is checked in every loop again !!
Re: ZX Spectrum Raytracer
Hi i modded yr mod a tinybit to make it independent from specbas or basinc.ZXDunny wrote: ↑Fri Jan 26, 2024 1:49 pm Sure
It's been updated for varying resolutions, and added ORIGIN FLIP to get the graphics upside-down.Code: Select all
2 origin flip: PAPER 0: INK 7: CLS : let TME=MSECS: LET SW=SCRW/2: LET SH=SCRH/2: GO SUB 8000: GO SUB 7000: DIM C(64): DIM L(64): LET DZ=(ScrW/800)*2: FOR X=0 TO scrw-1 STEP 8: FOR Y=0 TO scrh-1 STEP 8 40 LET DX=(X-SW)/256: LET DY=(Y-SH)/256: GO SUB 1000: LET CTL=PC: LET LTL=PL: LET DX=(X-SW+7)/256: GO SUB 1000: LET CTR=PC: LET LTR=PL: LET DY=(Y-SH+7)/256: GO SUB 1000: LET CBR=PC: LET LBR=PL: LET DX=(X-SW)/256: GO SUB 1000: LET CBL=PC: LET LBL=PL 51 IF CTL=0 AND CTR=0 AND CBR=0 AND CBL=0 THEN GO TO 500 111 LET CI=1: DIM A(8): LET PL=0: FOR U=X TO X+7: LET DX=(U-SW)/256: FOR V=Y TO Y+7: IF CI=1 THEN LET PC=CTL: LET PL=LTL: GO TO 160 141 IF CI=8 THEN LET PC=CBL: LET PL=LBL: GO TO 160 142 IF CI=57 THEN LET PC=CTR: LET PL=LTR: GO TO 160 143 IF CI=64 THEN LET PC=CBR: LET PL=LBR: GO TO 160 150 LET DY=(V-SH)/256: GO SUB 1000 160 LET A(PC+1)=A(PC+1)+1: LET C(CI)=PC: LET L(CI)=PL: LET CI=CI+1: NEXT V: NEXT U: LET MFC=0: FOR C=2 TO 8: IF A(C)>MFC THEN LET MFC=A(C): LET MFI=C 204 NEXT C: LET FC=MFI-1: INK FC 301 LET CI=1: FOR U=X TO X+7: FOR V=Y TO Y+7: IF C(CI)>0 AND H(CI)<=L(CI) THEN PLOT U,V 325 LET CI=CI+1: NEXT V: NEXT U 500 NEXT Y: GO SUB 3000: PRINT AT 0,0; INK 7;(msecs-TME)/1000: NEXT X: STOP 1000 LET MT=1E10: LET A=2*(DX*DX+DY*DY+DZ*DZ): FOR S=1 TO NS: LET B=2*(DX*S(S,1)+DY*S(S,2)+DZ*S(S,3)): LET C=(S(S,1)*S(S,1)+S(S,2)*S(S,2)+S(S,3)*S(S,3))-S(S,4): LET D=B*B-2*A*C: IF D<0 THEN GO TO 1500 1231 LET D=SQR (D): LET T=(B+D)/A: IF T>0 AND T<MT THEN LET PC=S(S,5): LET MT=T: LET CS=S 1250 LET T=(B-D)/A: IF T>0 AND T<MT THEN LET PC=S(S,5): LET MT=T: LET CS=S 1500 NEXT S: IF MT=1E10 THEN LET PC=0: RETURN 1600 LET IX=DX*MT: LET IY=DY*MT: LET IZ=DZ*MT: LET NX=IX-S(CS,1): LET NY=IY-S(CS,2): LET NZ=IZ-S(CS,3): LET PL=AI: GO SUB 2100: IF H=1 THEN RETURN 1615 LET NL=(NX*LX+NY*LY+NZ*LZ): IF NL>0 THEN LET PL=PL+DI*NL/SQR (NX*NX+NY*NY+NZ*NZ) 2000 RETURN 2100 LET A=2*(LX*LX+LY*LY+LZ*LZ): FOR S=1 TO NS: LET CX=IX-S(S,1): LET CY=IY-S(S,2): LET CZ=IZ-S(S,3): LET B=-2*(CX*LX+CY*LY+CZ*LZ): LET C=(CX*CX+CY*CY+CZ*CZ)-S(S,4): LET D=B*B-2*A*C: IF D<0 THEN GO TO 2210 2160 LET D=SQR (D): LET T=(B+D)/A: IF T>0.01 THEN LET H=1: RETURN 2190 LET T=(B-D)/A: IF T>0.01 THEN LET H=1: RETURN 2210 NEXT S: LET H=0: RETURN 3000 RETURN 7000 DIM H(64): RESTORE 7100: FOR I=1 TO 64: READ H(I): LET H(I)=H(I)/64: NEXT I: RETURN 7100 DATA 0,32,8,40,2,34,10,42 7101 DATA 48,16,56,24,50,18,58,26 7102 DATA 12,44,4,36,14,46,6,38 7103 DATA 60,28,52,20,62,30,54,22 7104 DATA 3,35,11,43,1,33,9,41 7105 DATA 51,19,59,27,49,17,57,25 7106 DATA 15,47,7,39,13,45,5,37 7107 DATA 63,31,55,23,61,29,53,21 8000 LET LX=-1/SQR (2): LET LY=1/SQR (2): LET LZ=0: LET AI=0.075: LET DI=1-AI: RESTORE 9000: READ NS: DIM S(NS,5): FOR S=1 TO NS: FOR I=1 TO 5: READ S(S,I): NEXT I: NEXT S: RETURN 9000 DATA 4 9001 DATA 0,-1,4,1,2 9002 DATA 2,0,4,1,1 9003 DATA -2,0,4,1,4 9004 DATA 0,-5001,0,5000^2,6
i replaced the MSECS to the DEF FN t()=PEEK 23674*65536+PEEK 23673*256+PEEK 23672
and i re-replaced the compiler-variables with the LET statement.
I was thinking about the screenflip , 175-y usualy does the job. maybe i look for it.
and the subroutine at first for speed...
so, nothing new here. just "emulator compiler compatible"
cheers!
Code: Select all
1 RUN 9100
10 LET MT=1E10: LET A=2*(DX*DX+DY*DY+DZ*DZ): FOR S=1 TO NS: LET B=2*(DX*S(S,1)+DY*S(S,2)+DZ*S(S,3)): LET C=(S(S,1)*S(S,1)+S(S,2)*S(S,2)+S(S,3)*S(S,3))-S(S,4): LET D=B*B-2*A*C: IF D<0 THEN GO TO 13
11 LET D=SQR (D): LET T=(B+D)/A: IF T>0 AND T<MT THEN LET PC=S(S,5): LET MT=T: LET CS=S
12 LET T=(B-D)/A: IF T>0 AND T<MT THEN LET PC=S(S,5): LET MT=T: LET CS=S
13 NEXT S: IF MT=1E10 THEN LET PC=0: RETURN
14 LET IX=DX*MT: LET IY=DY*MT: LET IZ=DZ*MT: LET NX=IX-S(CS,1): LET NY=IY-S(CS,2): LET NZ=IZ-S(CS,3): LET PL=AI: GO SUB 17: IF H=1 THEN RETURN
15 LET NL=(NX*LX+NY*LY+NZ*LZ): IF NL>0 THEN LET PL=PL+DI*NL/SQR (NX*NX+NY*NY+NZ*NZ)
16 RETURN
17 LET A=2*(LX*LX+LY*LY+LZ*LZ): FOR S=1 TO NS: LET CX=IX-S(S,1): LET CY=IY-S(S,2): LET CZ=IZ-S(S,3): LET B=-2*(CX*LX+CY*LY+CZ*LZ): LET C=(CX*CX+CY*CY+CZ*CZ)-S(S,4): LET D=B*B-2*A*C: IF D<0 THEN GO TO 21
18 LET D=SQR (D): LET T=(B+D)/A: IF T>0.01 THEN LET H=1: RETURN
19 LET T=(B-D)/A: IF T>0.01 THEN LET H=1: RETURN
21 NEXT S: LET H=0: RETURN
39 FOR X=0 TO scrw-1 STEP 8: FOR Y=0 TO scrh-1 STEP 8
40 LET DX=(X-SW)/256: LET DY=(Y-SH)/256: GO SUB 10: LET CTL=PC: LET LTL=PL: LET DX=(X-SW+7)/256: GO SUB 10: LET CTR=PC: LET LTR=PL: LET DY=(Y-SH+7)/256: GO SUB 10: LET CBR=PC: LET LBR=PL: LET DX=(X-SW)/256: GO SUB 10: LET CBL=PC: LET LBL=PL
51 IF CTL=0 AND CTR=0 AND CBR=0 AND CBL=0 THEN GO TO 500
111 LET CI=1: DIM A(8): LET PL=0: FOR U=X TO X+7: LET DX=(U-SW)/256: FOR V=Y TO Y+7: IF CI=1 THEN LET PC=CTL: LET PL=LTL: GO TO 160
141 IF CI=8 THEN LET PC=CBL: LET PL=LBL: GO TO 160
142 IF CI=57 THEN LET PC=CTR: LET PL=LTR: GO TO 160
143 IF CI=64 THEN LET PC=CBR: LET PL=LBR: GO TO 160
150 LET DY=(V-SH)/256: GO SUB 10
160 LET A(PC+1)=A(PC+1)+1: LET C(CI)=PC: LET L(CI)=PL: LET CI=CI+1: NEXT V: NEXT U: LET MFC=0: FOR C=2 TO 8: IF A(C)>MFC THEN LET MFC=A(C): LET MFI=C
204 NEXT C: LET FC=MFI-1: INK FC
301 LET CI=1: FOR U=X TO X+7: FOR V=Y TO Y+7: IF C(CI)>0 AND H(CI)<=L(CI) THEN PLOT U,V
325 LET CI=CI+1: NEXT V: NEXT U
500 NEXT Y: PRINT AT 0,0; INK 7;(FN t()-TME)/1000: NEXT X: STOP
7000 DIM H(64): RESTORE 7100: FOR I=1 TO 64: READ H(I): LET H(I)=H(I)/64: NEXT I
7100 DATA 0,32,8,40,2,34,10,42
7101 DATA 48,16,56,24,50,18,58,26
7102 DATA 12,44,4,36,14,46,6,38
7103 DATA 60,28,52,20,62,30,54,22
7104 DATA 3,35,11,43,1,33,9,41
7105 DATA 51,19,59,27,49,17,57,25
7106 DATA 15,47,7,39,13,45,5,37
7107 DATA 63,31,55,23,61,29,53,21
8000 LET LX=-1/SQR (2): LET LY=1/SQR (2): LET LZ=0: LET AI=0.075: LET DI=1-AI: RESTORE 9000: READ NS: DIM S(NS,5): FOR S=1 TO NS: FOR I=1 TO 5: READ S(S,I): NEXT I: NEXT S: RETURN
9000 DATA 4
9001 DATA 0,-1,4,1,2
9002 DATA 2,0,4,1,1
9003 DATA -2,0,4,1,4
9004 DATA 0,-5001,0,5000^2,6
9101 LET SCRW=255: LET SCRH=175: DEF FN t()=PEEK 23674*65536+PEEK 23673*256+PEEK 23672
9102 BORDER 0: PAPER 0: INK 7: CLS : LET TME=FN t(): LET SW=SCRW/2: LET SH=SCRH/2: GO SUB 7000: DIM C(64): DIM L(64): LET DZ=(ScrW/800)*2
9110 GO TO 39