RayTrace Movie (Atari 8bit) by D. Scott Williamson
A downloadable tool
Ray Trace Movie Mode 15 80 Column
by D. Scott Williamson
SCHAU category entry (10 lines less than 80 characters)
Table of contents:
Description
Included files
Startup & Emulator Instructions
Proof of 10 lines less than 80 columns
Program overview
Detailed program description
Description
This program renders a sequence of real ray traced images of two spheres over a checkerboard under a gradient sky where the camera moves forward and up in each frame. Each frame takes hours to render on native hardware and several minutes in an accelerated emulator. It is amazing to me that 10 lines of Atari BASIC less than 80 characters each can achieve such a beautiful technological result on 1978 hardware given the time to render the frames.
The included GIF is composed of 198 images captured over 16 hours played forward and backwards looping.
Included Files
README RayTrace Movie Mode 15 80 Column.txt This file
Ray Tracing movie mode 15 80 column.atr Atari DOS floppy disk including RAYTR80M.LST and RAYTR80M.BAS
RayTrace Movie Mode 15 80 columns.gif Animated gif made from captured frames
RayTrace Movie Mode 15 80 columns.png Static screenshot
RayTrace80M.lst Program listing (included below too)
RayTrace80M line length (80).png PNG of line length proof
RayTrace80M line length (80).lst Listing of line length proof
The program will continually loop rendering ray traced frames of an animated sequence.
Proof of 10 lines less than 80 columns (also see included png)
00000000011111111112222222222333333333344444444445555555555666666666677777777778 12345678901234567890123456789012345678901234567890123456789012345678901234567890 1 GR.31:SE.0,7,2:SE.1,3,8:SE.2,13,15:DI.DI(16):F.I=0TO15:REA.R:DI(I)=R:N.I:A=2 2 F.N=0TO191:F.M=0TO159:POK.77,0:X=0:Y=-A/25:Z=A:I=SGN(M-80.5) 3 U=(M-80.5)/(40*1.3):V=(N-80.5)/(80*1.3):W=1/SQR(U*U+V*V+1):U=U*W:V=V*W:G=1 4 E=X-I:F=Y-I:P=U*E+V*F-W*Z:D=P*P-E*E-F*F-Z*Z+1:G.5+(D<=0)*3 5 T=-P-SQR(D):G.6+(T<=0)*2:D.0,24,6,30,36,12,42,18,9,33,3,27,45,21,39,15 6 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) 7 U=U-P*E:V=V-P*F:W=W+P*G:I=-I:G.4 8 IF V<0THEN P=(Y+2)/V:S=INT(X-U*P)+INT(Z-W*P):S=S-INT(S/2)*2:V=-V*(S/2+.3)+.2 9 C.3-INT(((3*16)*SQR(V)+DI((M-INT(M/4)*4)+(N-INT(N/4)*4)*4)/3)/16):PL.M,191-N 10 N.M:N.N:A=10*(A=-1)+(A-.1)*(A>-1):G.2
Program Overview:
Line 1 sets up graphics mode 15 (4 color 160x192), colors, 4x4 dithering table, and initializes the animation parameter
Line 2 Loop over each screen pixel (M,N) and initialize view position (X,Y,Z)
Line 3 Calculate 2D unit viewport vector (U,V)
Lines 4-7 Handle reflections off the two spheres
Line 8 Handle the checkerboard pattern by a modulus 2 of a function combining X and Z in perspective to modulate the vertical V value that will be used as final intensity
Line 9 Set the color of the pixel based on curved intensity ramp and dithering and plot the pixel
line 10 Loop through pixels, update animation parameter to cycle between 10 and -1 by .1 increments
Detailed command by command program description:
1 GR.31: Graphics mode 15 full screen without text window 4 color 160x192
SE.0,7,2: Set color 1 to dark blue
SE.1,3,8: Set color 2 to purple
SE.2,13,15: Set color 3 to yellow
DI.DI(16): Dimension DI array for dithering constants
F.I=0TO15: Loop 0 to 15 to load DI array from data
REA.R: Read data into temporary variable R because can't read into array
DI(I)=R: Store data in R into array at index I
N.I: Next I
A=2 Set initial frame animation parameter A
A ranges from 10 to -1 and controls Z and Y coordinates of the camera
2 F.N=0TO191: Loop over scan lines
F.M=0TO159: Loop from left to right on each line
POK.77,0: Reset attract mode timer to prevent Atari color cycling CRT screen saver
X=0: Camera X coordinate is 0, centered
Y=-A/25: Camera Y coordinate ranges from -2.5 at A=10 to .25 at A=-1
Z=A: Camera Z coordinate
I=SGN(M-80.5) I is +1 on the left half of the screen and -1 on the right, the .5 guarantees never zero
3 U=(M-80.5)/(40*1.3): U is the viewport coordinate ranging from -1 to 1 horizontally
V=(N-80.5)/(80*1.3): V is the viewport coordinate ranging from -1 to 1 vertically
W=1/SQR(U*U+V*V+1): W is 1/(the length of the vector from the center of the screen to (U,V)
U=U*W: Scale U by the reciprocal length of offset vector to make unit vector (U,V)
V=V*W: Scale U by the reciprocal length of offset vector to make unit vector (U,V)
G=1 Initialize G to 1
4 E=X-I: E is X moved one pixel toward the horizontal center of the screen
F=Y-I: F is Y moved one pixel toward the vertical center of the screen
P=U*E+V*F-W*Z: P is the perspective adjusted point E,F in the viewport
D=P*P-E*E-F*F-Z*Z+1: Subtract the magnitude of (E,F,Z) from P and add 1 used to remove unwanted extra reflections on spheres
G.5+(D<=0)*3 These lines are too long for IF..THEN.. so use goto with conditional line number calculation: if D>0 goto 5 (next line) else 8
5 T=-P-SQR(D): Check to see if the next reflection will bounce off the other sphere
G.6+(T<=0)*2: If T<=0 then we're done bouncing the ray between spheres and UV have the final direction vector
D.0,24,6,30,36,12,42,18,9,33,3,27,45,21,39,15 Dither pattern constants
6 X=X+T*U: At this point there is a reflection, this handles bouncing ray between spheres (It cannot loop infinitely because the camera cannot see infinite reflection ray between spheres) Move the eyepoint Y to the surface of the sphere
Y=Y+T*V: Move the eyepoint Y to the surface of the sphere
Z=Z-T*W: Move the eyepoint Z to the surface of the sphere
E=X-I: Update E based on new X
F=Y-I: Update F based on new Y
G=Z: Update G based on new Z
P=2*(U*E+V*F-W*G) Update perspective parameter based on reflection
7 U=U-P*E: Update U parameter based on new P and E
V=V-P*F: Update V parameter based on new P and F
W=W+P*G: Update W parameter based on new P and G
I=-I: With each reflection negate I, bouncing in different direction
G.4 Loop unil one of the conditional gotos above goes to 8 (fails the if)
8 IF V<0THEN P=(Y+2)/V: Checkerboard calculation is only for pixels where V is negative below the virtical center of the screen
S=INT(X-U*P)+INT(Z-W*P): Calculate checkerboard parameter, X,Y is pixel in screen space, (U,W)*P is the perspective corerection
S=S-INT(S/2)*2: This a modulus 2 - subtract the integer portion of S/2 multiplied by 2
V=-V*(S/2+.3)+.2 Adjust the V (virtical screen space unit vector) value to be always positive and modulated by the checkerboard parameter S which is now 0 or 1 based on X and Z with perspective correction by P
9 C.3-INT(((3*16)*SQR(V)+DI((M-INT(M/4)*4)+(N-INT(N/4)*4)*4)/3)/16): Set color
V ranges from 0 to 1 where 0 at the horizon is bright and 1 toward the top and bottom of the screen are dark. V has been tweaked for the checkerboard.
Square root of V adds curvature to the gradient to represent a gradient on the inside of a sphere
Scaling by 3*16 is done because there are 3 is the maximum value and there are 16 dither parameters
The dithering is done in a 4x4 pixel square so the following calculation selects the dither parameter index based on the horizontal and vertical screen pixel position (M,N)
M-INT(M/4)*4 is the same as M mod 4
N-INT(N/4)*4 is the same as N mod 4
Note the N parameter is multiplied by 4 because dither parameters in DI are arranged in 4 rows of 4 VALUES
The dither parameter is looked up from DI and divided by 3 to get fractional values from integers for historical reasons
The scaled dithered parameter is added to the scaled value, divided by 16 and truncated by the INT instruction
The result is the fractional pixel value has fractional constants added to it at each pixel location such that when cast to an int some values move to neighboring integer values.
The result is subtracted from 3 to match the dark to light color gradient stored in the color registers
PL.M,191-N Plot point at M,191-N in the color set in line 9, the 191-N is to correct for the Atari graphics origin being in the upper left rather than lower left corner.
10 N.M: Next pixel on the LINE
N.N: Next line
A=10*(A=-1)+(A-.1)*(A>-1): Update animation parameter: If A=-1 then set A to 10, if A >-1 then subtract .1
G.2 Loop forever
Download
Install instructions
Startup & Emulator Instructions
1. Run Atari800Win PLus
2. Set Machine Type to XL/XE
3. Set Video System to NTSC (not strictly necessary)
4. Make sure BASIC is enabled ("Disable BASIC when booting" is disabled in settings)
4. Alt-D or drag and drop to attach "Ray Tracing movie mode 15 80 column.atr" to the emulator as D1:
5. Shift-F5 to reset the emulator which will now be in BASIC at the READY prompt with the disk loaded in D1:
6. Type "ENTER"D1:RAYTR80M.LST" and press enter to load the program
7. (optional) type "LIST" to see listing
8. type "RUN" to run the program
It is recommended to press F7 to toggle full speed of the emulator.
Leave a comment
Log in with itch.io to leave a comment.