raytrace.py

Created by andreanx

Created on April 15, 2020

6.58 KB

A raytracing demo. Requires version 13 or above. Just adapted and optimized it for the NumWorks Kandinsky and 32K heap from a Casio version by Lightmare : https://www.planet-casio.com/Fr/programmes/programme4056-4-raytracing-lightmare-jeux-divers.html


class polyscr:
  w, h = 0, 0
  has_show_screen = False
  # color mode :
  # 0: (R8, G8, B8)
  # 1: int RGB-565
  color_mode = 0

  show_screen = lambda self: None

  def color(self, r, g=0, b=0):
    if not self.color_mode:
      return (isinstance(r, tuple) or isinstance(r,list)) and r or (r,g,b)
    else:
      if isinstance(r, tuple) or isinstance(r,list):
        r, g, b = r[0], r[1], r[2]
      return r<<11 | g<<5 | b

  def __init__(self):
    try:
      from nsp import Texture as scr
      self.w, self.h = 320, 240
      scr = scr(self.w, self.h, None)
      self.getPixel = scr.getPx
      self.setPixel = scr.setPx
      self.show_screen = scr.display
      self.has_show_screen = True
      self.color_mode = 1
    except:
      try:
        import ti_graphics as scr
        self.getPixel = scr.getPixel
        self.setPixel = scr.setPixel
      except ImportError:
        try:
          import casioplot as scr
          self.show_screen = scr.show_screen
          self.has_show_screen = True
        except ImportError:
          import kandinsky as scr
        self.getPixel = scr.get_pixel
        self.setPixel = scr.set_pixel

    self.get_pixel = self.getPixel
    self.set_pixel = self.setPixel
    self.getPx = self.getPixel
    self.setPx = self.setPixel
    self.display = self.show_screen

    if self.w <= 0:
      def isRealPixel(x, y):
        c = self.get_pixel(x, y)
        if c == self.color(0,0,0):
          self.set_pixel(x, y, self.color(255,0,0))
          c = self.get_pixel(x, y)
        return c is not None and c != self.color(0, 0, 0)

      self.w,self.h,dw,dh = 0,0,1,1
      while dw or dh:
        if not isRealPixel(self.w-(dw==0),self.h-(dh==0)):
          if isRealPixel(self.w,self.h-1): dh = 0
          elif isRealPixel(self.w-1,self.h): dw = 0
          else: dw,dh=0, 0
        self.w+=dw
        self.h+=dh

plt = polyscr()

import math

def inputintminmax(s, v_min, v_max, show=False):
  if show:
    s+="? ("+str(v_min)+"-"+str(v_max)+")\n"
  v = v_min - 1
  while v<v_min or v>v_max:
    v = int(input(s))
  return v

l = inputintminmax("Language / langue:\n0: english\n1: francais\nChoix / choice? ", 0, 1)
lang=[
  ["Rendering size h*w:\nh=", "w=", "Marble type:\n0: blue\n1: transparent\nChoice? ", "Refresh display:\n0: at the end\n1: each new line\n2: each new pixel\nChoice? "],
  ["Taille rendu h*L:\nh=", "L=", "Type bille:\n0: bleue\n1: transparente\nChoix? ", "Rafraichissement:\n0: a la fin\n1: chaque ligne\n2: chaque pixel\nChoix? "]]

h = inputintminmax(lang[l][0], 1, plt.h, True)
w = inputintminmax(lang[l][1], 1, plt.w, True)
sphere_status = inputintminmax(lang[l][2], 0, 1)
progress = plt.has_show_screen and inputintminmax(lang[l][3], 0, 2) or 0

sphere = (0,7,1,2, sphere_status)

plane = (0,0,-0.25,-1)

light = (2,2,10)

inter_sph = [0,0,0]

diam_vec = [0, 0, 0]

ray = [0,0,0]
light_ray = [0,0,0]

a = 0
b = 0
c = 0
cam_vec = [0,1,0,math.pi / 4,math.pi / 4]

cam_vec[3] += math.acos(cam_vec[0] / math.sqrt(2))
cam_vec[4] += math.asin(cam_vec[1] / math.sqrt(2))

cor_x = math.cos(cam_vec[3]) * math.sqrt(2)
cor_y = math.cos(cam_vec[4]) * math.sqrt(2)
cor_z = math.cos(cam_vec[2] / math.sqrt(2) + math.pi / 4) * math.sqrt(2)

for i in range(3):
    ray[i] = cam_vec[i] + (cor_x,cor_y,cor_z)[i]

def calc_r(n):
    return (-2*sum([inter_sph[i]*light_ray[i] - light_ray[i]*sphere[i] for i in range(3)]) + ((n==2) - (n==1)) * math.sqrt(delta_2)) / 2*sum([light_ray[i]**2 for i in range(3)])                    

def calc_delta_2():
    return 4*sum([inter_sph[i]*light_ray[i] - light_ray[i]*sphere[i] for i in range(3)])**2 - 4*sum([light_ray[i]**2 for i in range(3)])*(sum([(inter_sph[i] - sphere[i])**2 for i in range(3)]) - sphere[3]**2)

def do_1(f):
    global color, delta_2
    for i in range(3):
        inter_sph[i] = (a,b,c)[i]+t*ray[i]
        light_ray[i] = light[i] - inter_sph[i]
    
    if sphere[4] == 0 :
        delta_2 = calc_delta_2()
        color = [0,0,255]
        if delta_2 >= 0 :
            r_1 = calc_r(1)
            r_2 = calc_r(2)
            
            if abs(r_1) <= abs(r_2) :
                color[2] -= int(r_2*255/(abs(r_1)+r_2))
    else :
        for i in range(3):
            diam_vec[i] = inter_sph[i] - sphere[i]

        k = sum([diam_vec[i]*((a,b,c)[i] - sphere[i]) for i in range(3)]) / sum([diam_vec[i]**2 for i in range(3)])
        l = sum([diam_vec[i]**2 * k**2 + 2 * diam_vec[i]*((a,b,c)[i] - sphere[i]) + (sphere[i] - (a,b,c)[i])**2 for i in range(3)])

        proj = [k*diam_vec[i] + sphere[i] for i in range(3)]
        
        refl = [2*(proj[i] - (a,b,c)[i]) + (a,b,c)[i] for i in range(3)]
        reflect = [refl[i] - inter_sph[i] for i in range(3)]

        if sum([plane[i]*reflect[i] for i in range(3)]) != 0 :
            t_2 = -(sum([plane[i]*inter_sph[i] for i in range(3)]) + plane[3]) / sum([plane[i] * reflect[i]])

            if t_2 > 0 :
                color[(inter_sph[f]+t_2*reflect[f])%2<1 and (inter_sph[not f]+t_2*reflect[not f])%2>=1 or (inter_sph[f]+t_2*reflect[f])%2>=1 and (inter_sph[not f]+t_2*reflect[not f])%2<1] = 255
                for i in range(3):
                    inter_sph[i] = inter_sph[i]+t_2*reflect[i]
                    light_ray[i] = light[i] - inter_sph[i]

                if calc_delta_2() >= 0 :
                    color[color != [255, 0, 0]] = 100

def do_2():
    color[(b+t_2*ray[1])%2<1 and (a+t_2*ray[0])%2>=1 or (b+t_2*ray[1])%2>=1 and (a+t_2*ray[0])%2<1] = 255
    for i in range(3):
        inter_sph[i] = (a,b,c)[i]+t_2*ray[i]
        light_ray[i] = light[i] - inter_sph[i]

    if calc_delta_2() >= 0 :
        color[color != [255, 0, 0]] = 100


for y in range(h) :
    for x in range(w) :

        color = [0,0,0]
        ray[0] = x * 2/w + cor_x
        ray[2] = cor_z - y * 2/h

        delta = 4*(sum([(a,b,c)[i]*ray[i] for i in range(3)]) - sum([ray[i]*sphere[i] for i in range(3)]))**2 - 4*sum([ray[i]**2 for i in range(3)])*(sum([((a,b,c)[i] - sphere[i])**2 for i in range(3)]) - sphere[3]**2)
        
        if delta > 0 :
            t = (-2*sum([(a,b,c)[i]*ray[i] - ray[i]*sphere[i] for i in range(3)]) - math.sqrt(delta)) / 2*sum([ray[i]**2 for i in range(3)])

        if sum([plane[i]*ray[i] for i in range(3)]) != 0 :
            t_2 = -(sum([plane[i]*(a,b,c)[i] for i in range(3)]) + plane[3]) / sum([plane[i]*ray[i] for i in range(3)])

        if t_2 > 0 and delta > 0 and t_2 > t or delta >= 0 and t_2 <= 0:
            do_1(1 - (t_2 > 0 and delta > 0 and t_2 > t))
        elif t_2 > 0 and (delta > 0 and t_2 <= t or delta < 0):
            do_2()

        plt.set_pixel(x, y, plt.color(color))
  
        if progress>=2 or x == w-1 and progress>=1 or y == h-1 and x == w-1: plt.show_screen()

During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:

With the exception of Cookies essential to the operation of the site, NumWorks leaves you the choice: you can accept Cookies for audience measurement by clicking on the "Accept and continue" button, or refuse these Cookies by clicking on the "Continue without accepting" button or by continuing your browsing. You can update your choice at any time by clicking on the link "Manage my cookies" at the bottom of the page. For more information, please consult our <a href="https://www.numworks.com/legal/cookies-policy/">cookies policy</a>.