Last active
November 29, 2021 00:51
-
-
Save binarycounter/008804b7da0bb6b1c604603368edb509 to your computer and use it in GitHub Desktop.
A tiny simplistic python raytracer based on a BBC BASIC program https://twitter.com/bbcmicrobot/status/1464585083109707776
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# An attempt to port this https://twitter.com/bbcmicrobot/status/1464585083109707776 from BBC Basic to python | |
# To understand how it works and maybe attempt to write something similar in 65816 assembly (SNES) | |
# License for my part of the code is MIT, cannot speak for the many people that worked on the original BBC BASIC version though. | |
# Requires the python modules PIL or Pillow for image output. Outputs a 8 bit monochrome PNG image. | |
from PIL import Image, ImageOps | |
import math | |
# Set up image | |
img=Image.new("L",(320,256)) | |
# Pixel Plot loops | |
for pix_y in range(img.size[1]): | |
for pix_x in range(img.size[0]): | |
#Camera Position | |
X=0 | |
Y=-0.1 | |
Z=3 | |
#Camera Rotation | |
U=(pix_x-(img.size[0]/2)-0.5)/(img.size[0]/2) # Replaced the hardcoded image dimensions with variables here so that the resolution can easily be changed | |
V=(pix_y-(img.size[1]/2)-0.5)/(img.size[0]/2) | |
W=1/math.sqrt(U*U+V*V+1) | |
#Perspective projection (?) | |
U=U*W | |
V=V*W | |
I = (-1,1)[U > 0] # Ternary operator replacing the "SGN" command | |
while(True): #Infinite loop with break and continue replacing GOTO | |
E=X-I | |
F=Y-I | |
P=U*E+V*F-W*Z | |
# Spheres (?) | |
D=P*P-E*E-F*F-Z*Z+1 | |
if D>0: | |
T=-P-math.sqrt(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 | |
continue | |
break | |
# Ground Checkerboard | |
if V<0: | |
P=(Y+2)/V | |
V=-V*((int(X-U*P)+int(Z-W*P) & 1)/2+.3)+.2 | |
img.putpixel((pix_x,pix_y),int(255-V*255)) # Original has a backwards palette so i am inverting the pixels by subtracting them from the max brightness | |
img=ImageOps.flip(img) #Original plots from bottom, so image should be flipped | |
img.save("output.png") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment