Jump to content
IGNORED

🕹️ 🟣 REAL RAY TRACING on ATARI 8 BIT in 10 lines of BASIC


Recommended Posts

Very cool, great use of dithering and rich colours.

 

For ease I've just copied the text from your video:

 

 

All the frames of this video and the audio were created by an ATARI 8 bit computer emulator. The program to render this ray traced animation is 10 lines of ATARI BASIC, each line is under 80 characters long. This animation took 16 hours to render running the Atari800win Plus emulator at full (~3200%) speed. Frames were captured by HyperCam2. The sound is also from ATARI 8 bit computers and requires clocking the audio at 1.79MHz, combining audio channels to get 16bit frequency range and creating a deep overtone. I love this sound. This sound was captured from the emulator using Audacity. The dithered four color 160x192 pixel frames were extracted from the window capture and and were combined with the sound in HitFilm Express where the title frame was also created.

Edited by Beeblebrox
  • Like 1
  • Thanks 3
Link to comment
Share on other sites

3 hours ago, Wrathchild said:

Yep, which is based on someone else's program, @coprolite9000 just added the dithering.  I saw it on Y-Combinator news.

 

I've had to make lots of modifications to get it to work in Atari BASIC.

  • The dithering is implemented with a diabolical hack that took a while to unravel
  • Atari BASIC has no modulus operator
  • Atari BASIC has no integer operations (e.g. DIV16)
  • Had to adjust for screen resolution and aspect ratio
  • Had to find suitable colors
  • Disabled attract mode
  • Added animation
  • Fit in in 10 lines less than 80 characters - masochism

I've other adaptations in mode 7+ with sound and color editing, and adapted it to GTIA modes too and added sound and music and color editing. 
I'll post more and eventually source soon.

  • Like 5
Link to comment
Share on other sites

19 hours ago, _The Doctor__ said:

accelerated 3,200% took 16 hours? So we won't be watching this on our real Atari if that's the case. Interesting exercise, how long between frames being captured? Automatic trigger or fully recorded then edited ?

At 3200% it took about 10 minutes to render a frame, some take longer than others based on reflections.  On classic hardware or unaccelerated emulator I guess that would be around 4.5 to 5 hours per frame.
I used Hypercam2 and the lowest framerate I could capture was 1 frame per second, in the edit I playback at 30000% to 60fps video which is about 1 Atari frame every 1/30th of a second I think.  I captured a LOT more frames than I needed but I did what was easy.

Edited by solidcorp
  • Like 3
Link to comment
Share on other sites

3 hours ago, w1k said:

how i can try this on real hw?

You can't. Unless someone compiles each frame and loads it as a dithered image from a suitable capacity/speed storage medium, running it in sequence. 

 

I think the point here is to see a simulated/emulated Atari program having ray traced all the frames, albiet greatly accelerated. Otherwise it would have taken weeks. :)

 

 

  • Like 1
Link to comment
Share on other sites

5 hours ago, Wrathchild said:

I wonder if in Altirra you could use a breakpoint on a access to a byte which triggers a screen save. You could then splice those images into a gif? @phaeron 

or even trigger the .writemem command and in this case dump the screen mem.

I mean, sure, you could do that... or you could rewrite it in asm so it runs faster than 1frame/4h. Even just running it under TBXL would speed things up quite a lot.

 

Link to comment
Share on other sites

This is a job for a fast floating point package.  This would be worth exploring compiled BASIC options.  But I expect if you did some profiling, you would find that the vast majority of the time is in the floating point package, and it's likely really doing floating point except for loop indices, so compiling or even rewriting in assembly wouldn't save that much time.

 

The totally cheating thing to do, which would also be cool in its own way, would be to raytrace the same thing on modern computer, and then convert the frames to Atari with RastaConverter.  Then the ultimate hack would be to find a way to get the Atari to cycle through the frames at a reasonable speed.  (If you manage to get all the frames in 16K, you could bank select a bunch, but probably not enough.)

  • Like 1
Link to comment
Share on other sites

4 hours ago, pcrow said:

This is a job for a fast floating point package.  This would be worth exploring compiled BASIC options.  But I expect if you did some profiling, you would find that the vast majority of the time is in the floating point package, and it's likely really doing floating point except for loop indices, so compiling or even rewriting in assembly wouldn't save that much time.

 

The totally cheating thing to do, which would also be cool in its own way, would be to raytrace the same thing on modern computer, and then convert the frames to Atari with RastaConverter.  Then the ultimate hack would be to find a way to get the Atari to cycle through the frames at a reasonable speed.  (If you manage to get all the frames in 16K, you could bank select a bunch, but probably not enough.)

Check this out:

 

 

Link to comment
Share on other sites

16 hours ago, solidcorp said:

Yep, which is based on someone else's program, @coprolite9000 just added the dithering.  I saw it on Y-Combinator news.

 

I've had to make lots of modifications to get it to work in Atari BASIC.

  • The dithering is implemented with a diabolical hack that took a while to unravel
  • Atari BASIC has no modulus operator
  • Atari BASIC has no integer operations (e.g. DIV16)
  • Had to adjust for screen resolution and aspect ratio
  • Had to find suitable colors
  • Disabled attract mode
  • Added animation
  • Fit in in 10 lines less than 80 characters - masochism

I've other adaptations in mode 7+ with sound and color editing, and adapted it to GTIA modes too and added sound and music and color editing. 
I'll post more and eventually source soon.

can you share the code?

  • Like 2
Link to comment
Share on other sites

Hi!

18 hours ago, ilmenit said:

can you share the code?

 

From the original BBC source at https://bbcmic.ro/?t=9ctpk you can translate it to other BASIC.

 

This is a FastBasic version, the ATR includes the Altirra Mathpack for more speed, it starts with Z=2.25 and goes further by 0.25 each frame.

 

image.thumb.png.a47ebeba0b4b7071255d2bf1482a646b.png

 

 

Spoiler

 

DATA DITH() B. = 0,8,2,10,12,4,14,6,3,11,1,9,15,7,13,5

GR.31

SE.0,2,6
SE.1,1,10
SE.2,14,14

Z0%=2

DO
 Z0%=Z0%+0.25

 FOR N=0 TO 191
  POKE 77,0
  COLOR 0: PLOT 159,N
  FOR M=0 TO 159

   X%=0
   Y%=-.1
   Z%=Z0%

   U%=(M-79.5)/80
   V%=(95.5-N)/120

   W%=1 / SQR(U%*U%+V%*V%+1)
   U%=U%*W%
   V%=V%*W%
   I%=SGN U%

   DO
    E%=X%-I%
    F%=Y%-I%

    P%=U%*E%+V%*F%-W%*Z%
    D%=P%*P%-E%*E%-F%*F%-Z%*Z%+1

    IF D%>0
     T%=-P% - SQR D%
     IF T%>0
      X%=X%+T%*U%
      Y%=Y%+T%*V%
      Z%=Z%-T%*W%
      E%=X%-I%
      F%=Y%-I%
      G%=Z%
      P%=2*(U%*E%+V%*F%-W%*G%)
      U%=U%-P%*E%
      V%=V%-P%*F%
      W%=W%+P%*G%
      I%=-I%
     ELSE
      EXIT
     ENDIF
    ELSE
     EXIT
    ENDIF
   LOOP


   IF V%<0
    P%=(Y%+2)/V%
    TMP = (INT(X%-U%*P%)+INT(Z%-W%*P%)) & 1
    V%=-V%*(TMP*.5+.3)+.2
   ENDIF

   COLOR 3 - (INT(48*SQR V%) + DITH((M & 3) + (N & 3) * 4)) / 16
   PLOT M,N

  NEXT
 NEXT

LOOP

 

 

 

 

raytrace.atr

  • Like 6
Link to comment
Share on other sites

It seems to be tolerated, not sure if a nested unclosed FOR loop replaces a previous active one or creates a new stack entry.

But if you put the NEXT outside of the outer loop you get an error same as if the loop was never created.

 

e.g.

10 FOR A=1 TO 10
20 FOR B=A TO 20
80 ? B
90 NEXT A
100 NEXT B

 

Link to comment
Share on other sites

Hi!

2 hours ago, sanny said:

Doesn't this miss a "NEXT"? Two opening "FOR"s and only one "NEXT"?

 

But it seems to work somehow

In BBC Basic, you can specify more than one variable as argument to NEXT, you can write " NEXT M,N ", this is the same as "NEXT M : NEXT N".

 

Also, you can omit the variable names so the "NEXT , " is the same as "NEXT : NEXT".

 

I could add this syntax to FastBasic, it is a simple addition to the parser.

 

Have Fun!

 

  • Like 3
Link to comment
Share on other sites

Really great piece of programming .. I love it. I ported it to VB6 and experimented a bit with fixed decimal point to eventually do something like this in assembler .. but the quadratic equation doesn't go too well with that approach. So I also experimented a bit with ray marching, where the math is easier. Still nothing to show up, and it might never be, but it's certainly interesting topic.

Link to comment
Share on other sites

Reversed the math in the BBC version... I'm guessing that in assembly this would probably best be implemented with 16 or 24-bit fixed point, even with the square roots.

 

40 -- set view position
   X=0:Y=-.1:Z=3:

   -- compute view vector
   U=(M-159.5)/160:V=(N-127.5)/160
   
   -- normalize view vector
   W=1/SQR(U*U+V*V+1):U=U*W:V=V*W
   
   -- choose first sphere to hit test based on left/right side
   I=SGNU
   
   -- unused?
   G=1
   
50 -- compute relative vector X/Y between camera and sphere (Z implicit)
   E=X-I:F=Y-I
   
   -- compute negated distance from eye along ray to perpendicular center plane of sphere
   P=U*E+V*F-W*Z
   
   -- compute squared distance along ray between sphere center plane and intersection point
   -- P*P = squared distance from eye to sphere center plane
   -- E*E+F*F+Z*Z = squared distance from eye to sphere position
   -- (E*E+F*F+Z*Z)-P*P = squared horizontal distance between sphere and plane intersection, by Pythagorean theorem
   -- 1 = squared radius of sphere
   -- 1-((E*E+F*F+Z*Z)-P*P) = squared distance between plane and ray-sphere interaction, by Pythagorean theorem
   D=P*P-E*E-F*F-Z*Z+1
   IF D>0   
	  -- compute ray collision time, picking nearer (entry) intersection
	  T=-P-SQRD
	  
	  -- reject collision if it's behind ray origin (ray starts inside or past sphere)
	  IF T>0
	     -- advance ray to intersection point
	     X=X+T*U:Y=Y+T*V:Z=Z-T*W
	     
	     -- compute sphere normal at intersection point
	     E=X-I:F=Y-I:G=Z
	     
	     -- reflect ray direction across normal plane
	     P=2*(U*E+V*F-W*G)
	     U=U-P*E:V=V-P*F:W=W+P*G
	     
	     -- flip to testing against other sphere
	     I=-I
	     GOTO50

60 -- check if ray pointing down for floor intersection
   IFV<0

   -- compute negated distance to floor
   P=(Y+2)/V
   
   -- compute X/Z of floor intersection and texture
   V=-V*((INT(X-U*P)+INT(Z-W*P)AND1)/2+.3)+.2

-- tone mapping and ordered dithering based on either floor texture or sky gradient from view vector Y
70 GCOL0,3-(48*SQRV+?(PAGE+5+M MOD4+N MOD4*4)/3)DIV16

 

  • Like 4
Link to comment
Share on other sites

Hi!

2 hours ago, phaeron said:

 

   -- unused?
   G=1
   
50 -- compute relative vector X/Y between camera and sphere (Z implicit)
   E=X-I:F=Y-I

 

I suspected the original was  EFG = XYZ - (I,I,0) , so EFG is the full relative vector, and crept from and old version with Z=1 and finally left unused.  I removed that from my FastBasic version.

 

The ray-tracing code is straightforward, the clever thing was testing only one sphere at a time, as after a reflection in one sphere you can only hit the other one - this makes rendering the two spheres as fast as rendering only one.

 

Have Fun!

  • Like 1
Link to comment
Share on other sites

Well,

... a little more than 10 lines...   ;-)    (12K of TB XL code)

 

- Christbaum Kugel Editor (XMAS bulb editor), KugelEdi.ATR

- listing from C't magazine, Germany 1/1986

- Raytracing editor and demo, in german language

- works with TB XL

- uses Gr. 8 and only one sphere

- one can choose between 4 backgrounds

  (squares/chessboard, triangles, etc.)

- one can set various viewpoints and angles (light, camera, etc.)

- with Atari 800 Win and 2000x speed, calculations for one picture take approx. 1-2 minutes

- comes with a ready-made demo on the disk

  (includes 8 calculated raytracing pictures, the animation requires 128K then)

 

=> three more (simple) 128K raytracing demos in Gr. 8 available by K. Pelzer, based on the C't program

     RayAni1.ATR, RayAni2.ATR, RayAni3.ATR

=> K. Pelzer later created a similar raytracing demo in Gr. 9+11 (most likely based on or inspired by the C't program)

      Ray128K.ATR (original name: Landscape)

 

 

KUGELEDI.ATR RAYANI1.ATR RAYANI2.ATR RAYANI3.ATR RAY128K.ATR

  • Like 2
Link to comment
Share on other sites

Hi!

 

I made a disk based animation, uncompressed from disk to screen. All 100 frames were rendered with my code above, in FastBasic, then saved to disk and compressed.

 

Decompression code:

Spoiler
' Decompresses video frames from file to screen
GR.31

SE.0,2,6
SE.1,1,10
SE.2,14,14

BUF=DPEEK(88)
BUF1=DPEEK(88)-8192

' Loop forever
DO
 ' Open video file, read initial frame
 OPEN #1,4,0,"D:VIDEO.BIN"
 BGET #1,BUF1,7680

 WHILE ERR() < 128
  PAUSE 0
  POKE 77,0
  MOVE BUF1,BUF,7680

  ' For first read, check error
  GET #1,N
  IF ERR() > 1 THEN EXIT

  MOVE BUF,BUF1,N
  P=BUF1+N
  E=BUF1+7679
  Q=0

  WHILE P<E
    GET #1,N
    IF Q
      ' Copy from last frame
      MOVE P+8192,P,N
      P=P+N
      Q=0
    ELSE
      ' Read data from file
      IF N THEN BGET #1,P,N
      P=P+N
      Q=1
    ENDIF
  WEND

 WEND
 CLOSE #1

LOOP

 

 

Have Fun!

 

 

video.atr

  • Like 4
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...