git.fiddlerwoaroof.com
raytracing_in_one_weekend/scenes.lisp
96842cff
 (in-package :fwoar.lisp-sandbox.1)
 
 (defun raytrace (out &optional (*samples-per-pixel* 10) (image-width 400) (max-depth 50))
   (let* ((world (append (list (sphere #(0 0 -1) .5
                                       #(0.5 0.5 0.0)
                                       (dielectric-material 0.4)
                                       #+(or)
                                       (lambda (rec ray world depth)
                                         (declare (ignore rec world depth))
                                         (with-slots (direction) ray
                                           (fw.lu:vector-destructuring-bind
                                               (x y z) (unit-vector direction)
                                             (vector (abs x)
                                                     (abs y)
                                                     (abs z)))))))
                         (loop repeat 30
                               collect (sphere (vector (rand-min-max -3 3)
                                                       (rand-min-max -0.5 2)
                                                       (rand-min-max -1.5d0 -0.5d0))
                                               (rand-min-max 0.2 0.5)
                                               (vector (random 1.0d0)
                                                       (random 1.0d0)
                                                       (random 1.0d0))
                                               (case (random 5)
                                                 (0 (lambertian-material
                                                     (rand-min-max 0.25 0.75)))
                                                 (1 (metal-material
                                                     (rand-min-max 0.25 0.75)))
                                                 (2 (fuzzy-metal-material
                                                     (rand-min-max 0.25 0.75)
                                                     (rand-min-max 0.01 0.75)))
                                                 (3 (dielectric-material
                                                     (rand-min-max 0.1 2.4)))
                                                 (4 #'original-material)
                                                 (5
                                                  (lambda (rec ray world depth)
                                                    (declare (ignore rec world depth))
                                                    (vector 1d0 1d0 1d0)
                                                    #+(or)
                                                    (with-slots (direction) ray
                                                      (fw.lu:vector-destructuring-bind
                                                          (x y z) (unit-vector direction)
                                                        (vector (abs x)
                                                                (abs y)
                                                                (abs z)))))))))
                         ;; #+(or)
                         (list (sphere #(0 -100.5 -1) 100
                                       #(0.5 0.5 0.5)
                                       (lambertian-material 0.2)))))
          (aspect-ratio 4/3)
          (image-height (* (floor (/ image-width aspect-ratio))))
 
          (camera (camera :focal-length 1.0d0)))
     (let ((mailbox (sb-concurrency:make-mailbox)))
       (loop for j in (shuffle (loop for x from 0 to image-height collect x))
             do
                (sb-concurrency:send-message
                 (aref *thread-queues*
                       (mod j
                            (length *thread-queues*)))
                 (list *samples-per-pixel*
                       j image-width
                       image-height camera
                       world max-depth
                       (lambda (a b)
                         (sb-concurrency:send-message
                          mailbox
                          (list a b))))))
       (write-colors nil
                     (lambda (c)
                       (loop with messages = 0
                             for it = (sb-concurrency:receive-message mailbox :timeout 2)
                             while it
                             do (destructuring-bind (color pos) it
                                  (funcall c color pos))))
                     image-width))))
 
 (defun refraction-scene
     (out &optional (*samples-per-pixel* 10) (image-width 400) (max-depth 50))
   (let* ((world (list (sphere #(0 0 -1) .5
                               #(0.5 0.5 0.0)
                               (lambertian-material #(0.7 0.3 0.3)))
                       (sphere #(-1 0 -1) 0.5
                               #(0 0 0)
                               (dielectric-material 1.5))
                       (sphere #(-1 0 -1) -0.4
                               #(0 0 0)
                               (dielectric-material 1.5))
                       (sphere #(-1 0 -1) -0.2
                               #(0 0 0)
                               (lambertian-material
                                #(0.8 0.6 0.2)))
                       #+(or)
                       (sphere #(1 0 -1) 0.5
                               #(0 0 0)
                               (dielectric-material 2.4))
                       #+(or)
                       (sphere #(-2 0 -1) 0.5
                               #(0 0 0)
                               (metal-material #(0.8 0.8 0.8)))
                       (sphere #(1 0 -1) 0.5
                               #(0 0 0)
                               (metal-material #(0.8 0.6 0.2)))
                       (sphere #(0 -100.5 -1) 100
                               #(0.5 0.5 0.5)
                               (lambertian-material #(0.8 0.8 0.0)))))
          (aspect-ratio 16/9)
          (image-height (* (floor (/ image-width aspect-ratio))))
 
          (camera (camera)))
     (let ((mailbox (sb-concurrency:make-mailbox)))
       (loop for j in (shuffle (loop for x from 0 to image-height collect x))
             do
                (sb-concurrency:send-message
                 (aref *thread-queues*
                       (mod j
                            (length *thread-queues*)))
                 (list *samples-per-pixel*
                       j image-width
                       image-height camera
                       world max-depth
                       (lambda (a b)
                         (sb-concurrency:send-message
                          mailbox
                          (list a b))))))
       (write-colors nil
                     (lambda (c)
                       (loop with messages = 0
                             for it = (sb-concurrency:receive-message mailbox :timeout 2)
                             while it
                             do (destructuring-bind (color pos) it
                                  (funcall c color pos))))
                     image-width))))
 
 (defun refraction-scene1
     (out &optional (*samples-per-pixel* 10) (image-width 400) (max-depth 50))
   (let* ((world (list (sphere #(0 0 -1) 1
                               #(0.5 0.5 0.0)
                               (dielectric-material 2.4))
                       (sphere #(-0.5 0 -1) 0.5
                               #(0 0 0)
                               (dielectric-material 1.5 0.2))
                       (sphere #(-0.5 0 -1) -0.4
                               #(0 0 0)
                               (dielectric-material 1.5 0.2))
                       (sphere #(-0.5 0 -1) -0.2
                               #(0 0 0)
                               (metal-material
                                #(0.8 0.6 0.2)))
                       #+(or)
                       (sphere #(1 0 -1) 0.5
                               #(0 0 0)
                               (dielectric-material 2.4))
                       #+(or)
                       (sphere #(-2 0 -1) 0.5
                               #(0 0 0)
                               (metal-material #(0.8 0.8 0.8)))
                       (sphere #(0.5 0 -1) 0.5
                               #(0 0 0)
                               (metal-material #(0.8 0.6 0.2)))
                       (sphere #(0 -100.5 -1) 100
                               #(0.5 0.5 0.5)
                               (lambertian-material #(0.8 0.8 0.0)))))
          (aspect-ratio 16/9)
          (image-height (* (floor (/ image-width aspect-ratio))))
 
          (camera (camera)))
     (let ((mailbox (sb-concurrency:make-mailbox)))
       (loop for j in (shuffle (loop for x from 0 to image-height collect x))
             do
                (sb-concurrency:send-message
                 (aref *thread-queues*
                       (mod j
                            (length *thread-queues*)))
                 (list *samples-per-pixel*
                       j image-width
                       image-height camera
                       world max-depth
                       (lambda (a b)
                         (sb-concurrency:send-message
                          mailbox
                          (list a b))))))
       (write-colors nil
                     (lambda (c)
                       (loop with messages = 0
                             for it = (sb-concurrency:receive-message mailbox :timeout 2)
                             while it
                             do (destructuring-bind (color pos) it
                                  (funcall c color pos))))
                     image-width))))
 
6b17e8ac
 (defun refraction-scene2
     (&optional (*samples-per-pixel* 10) (image-width 400) (max-depth 50) (rows nil rows-p))
   (let* ((world (list (sphere #( 0.0 0 -1.0) 0.1 #(0.5 0.5 0.0) (dielectric-material 1.5))
                       (sphere #( 0.0 0 -1.4) 0.2 #(0.5 0.5 0.0) (dielectric-material 1.7))
                       (sphere #( 0.0 0 -2.4) 0.8 #(0.5 0.5 0.0) (dielectric-material 1.9))
                       (sphere #(-0.0 0 -3.6) 1.0 #(0.5 0.5 0.0) (dielectric-material 2.1))
                       (sphere #(-0.0 0 -5.0) 1.2 #(0.5 0.5 0.0) (dielectric-material 2.3))
                       (sphere #(-0.0 0 -6.6) 1.4 #(0.5 0.5 0.0) (dielectric-material 2.5))
                       #+foo (sphere #(-0.0 0 -1) -0.2
                                     #(0 0 0)
                                     (metal-material #(0.859375d0 0.859375d0 0.796875d0)))
                       #+foo (sphere #(0.6 0.0 -1) 0.2
                                     #(0 0 0)
                                     (metal-material #(0.859375d0 0.859375d0 0.796875d0)))
                       #+foo (sphere #(0 1 -1) 0.2
                                     nil
                                     (lambda (rec ray world depth)
                                       (declare (ignore rec ray world depth))
                                       #(1.0d0 1.0d0 1.0d0)))
                       (sphere #(0 -1000.5 -1.5) 1000
                               #(0.5 0.5 0.5)
                               (lambertian-material #(0.8 0.0 0.0))))
                 #+(or)
                 (list
                  (sphere #(-0.0 0 -1) 0.2
                          #(0 0 0)
                          (metal-material
                           #(0.8 0.6 0.2)))
                  (sphere #(0 -100.5 -1.5) 100
                          #(0.5 0.5 0.5)
                          (lambertian-material #(0.8 0.8 0.0)))))
          (aspect-ratio 16/9)
          (image-height (* (floor (/ image-width aspect-ratio))))
 
          (camera (camera)))
     (let ((mailbox (sb-concurrency:make-mailbox)))
       (loop for j in (if rows-p
                          rows
                          (shuffle (loop for x from 0 to image-height collect x)))
             do
                (sb-concurrency:send-message
                 (aref *thread-queues*
                       (mod j
                            (length *thread-queues*)))
                 (list *samples-per-pixel*
                       j image-width
                       image-height camera
                       world max-depth
                       (lambda (a b)
                         (sb-concurrency:send-message
                          mailbox
                          (list a b))))))
       (write-colors nil
                     (lambda (c)
                       (loop with messages = 0
                             for it = (sb-concurrency:receive-message mailbox :timeout 2)
                             while it
                             do (destructuring-bind (color pos) it
                                  (funcall c color pos))))
                     image-width))))
 
 (defvar *planets*
   '(:mercury 3031/7917
     :venus   7520/7917
     :earth   7917/7917
     :mars    4212/7917))
 
 (defun scene-3
     (&optional (*samples-per-pixel* 10) (image-width 400) (max-depth 50) (rows nil rows-p))
   (let* ((world (list (sphere #(-2.25 0 -2)
                               (* 0.5 (getf *planets* :mercury))
                               nil
                               (metal-material #(0.8 0.8 0)))
                       (sphere #(-0.75 0 -2)
                               (* 0.5 (getf *planets* :venus))
                               nil
                               (metal-material #(0.0 0.8 0)))
                       (sphere #(0.75 0 -2)
                               (* 0.5 (getf *planets* :earth))
                               nil
                               (metal-material #(0.0 0.0 0.8)))
                       (sphere #(2.25 -0 -2)
                               (* 0.5 (getf *planets* :mars))
                               nil
                               (metal-material #(0.8 0.0 0.0)))))
 
          (aspect-ratio 16/9)
          (image-height (* (floor (/ image-width aspect-ratio))))
 
          (camera (camera)))
     (let ((mailbox (sb-concurrency:make-mailbox)))
       (loop for j in (if rows-p
                          rows
                          (shuffle (loop for x from 0 to image-height collect x)))
             do
                (sb-concurrency:send-message
                 (aref *thread-queues*
                       (mod j
                            (length *thread-queues*)))
                 (list *samples-per-pixel*
                       j image-width
                       image-height camera
                       world max-depth
                       (lambda (a b)
                         (sb-concurrency:send-message
                          mailbox
                          (list a b))))))
       (write-colors nil
                     (lambda (c)
                       (loop with messages = 0
                             for it = (sb-concurrency:receive-message mailbox :timeout 2)
                             while it
                             do (destructuring-bind (color pos) it
                                  (funcall c color pos))))
                     image-width))))
 
 (defun scene-4
     (&optional (*samples-per-pixel* 10) (image-width 400) (max-depth 50) (rows nil rows-p))
   (let* ((world (append (loop for ti from 0 by (/ pi 7)
                               for x from 0
                               repeat 20
                               collect
                               (sphere
                                (vector (- (* 2 (sin ti)) 1)
                                        (- (* 2 (cos ti)) 1)
                                        (+ -0.5 (* -0.3 x)))
                                0.25
                                nil
                                (case (random 3)
                                  (0 (metal-material (vector (/ (mod (* 20 x)
                                                                     256)
                                                                256d0)
                                                             (/ (mod (* 20 x)
                                                                     256)
                                                                256d0)
                                                             (/ (mod (* 20 x)
                                                                     256)
                                                                256d0))))
                                  (1 (lambertian-material (vector (/ (mod (* 20 x)
                                                                          256)
                                                                     256d0)
                                                                  (/ (mod (* 20 x)
                                                                          256)
                                                                     256d0)
                                                                  (/ (mod (* 20 x)
                                                                          256)
                                                                     256d0))))
                                  (2 (dielectric-material (rand-min-max 1.4 2.5)
                                                          (rand-min-max 0 0.2))))))
                         (loop for ti from 0 by (/ pi 7)
                               for x from 0
                               repeat 20
                               collect
                               (sphere
                                (vector (- (sin (+ ti (/ pi 14))) 0.5)
                                        (- (cos (+ ti (/ pi 14))) 0.5)
                                        (+ -0.5 (* -0.3 x)))
                                0.25
                                nil
                                (case (random 3)
                                  (0 (metal-material (vector (/ (mod (* 20 x)
                                                                     256)
                                                                256d0)
                                                             (/ (mod (* 20 x)
                                                                     256)
                                                                256d0)
                                                             (/ (mod (* 20 x)
                                                                     256)
                                                                256d0))))
                                  (1 (lambertian-material (vector (/ (mod (* 20 x)
                                                                          256)
                                                                     256d0)
                                                                  (/ (mod (* 20 x)
                                                                          256)
                                                                     256d0)
                                                                  (/ (mod (* 20 x)
                                                                          256)
                                                                     256d0))))
                                  (2 (dielectric-material (rand-min-max 1.4 2.5)
                                                          (rand-min-max 0 0.2)))))))
                 #+(or)
                 (list
                  (sphere #(-0.0 0 -1) 0.2
                          #(0 0 0)
                          (metal-material
                           #(0.8 0.6 0.2)))
                  (sphere #(0 -100.5 -1.5) 100
                          #(0.5 0.5 0.5)
                          (lambertian-material #(0.8 0.8 0.0)))))
          (aspect-ratio 16/9)
          (image-height (* (floor (/ image-width aspect-ratio))))
 
          (camera (camera)))
     (let ((mailbox (sb-concurrency:make-mailbox)))
       (loop for j in (if rows-p
                          rows
                          (shuffle (loop for x from 0 to image-height collect x)))
             do
                (sb-concurrency:send-message
                 (aref *thread-queues*
                       (mod j
                            (length *thread-queues*)))
                 (list *samples-per-pixel*
                       j image-width
                       image-height camera
                       world max-depth
                       (lambda (a b)
                         (sb-concurrency:send-message
                          mailbox
                          (list a b))))))
       (write-colors nil
                     (lambda (c)
                       (loop with messages = 0
                             for it = (sb-concurrency:receive-message mailbox :timeout 2)
                             while it
                             do (destructuring-bind (color pos) it
                                  (funcall c color pos))))
                     image-width))))
 
96842cff
 (defun sample-image (out)
   (let ((image-width 256)
         (image-height 256))
     (alexandria:with-output-to-file (s out :if-exists :supersede)
       (call-with-ppm-header
        s (make-size :width image-width :height image-height)
        (lambda (s)
          (write-colors
           s (lambda (c)
               (loop for j from (1- image-height) downto 0
                     do (format *trace-output*
                                "~&Scanlines remaining: ~d ~s~%"
                                j
                                (local-time:now))
                     do
                        (loop for i from 0 below image-width
                              collect
                              (let* ((r (/ (* i 1.0d0)
                                           (1- image-width)))
                                     (g (/ (* j 1.0d0)
                                           (1- image-height)))
                                     (b 0.15d0))
                                (funcall c (make-color :r r
                                                       :g g
                                                       :b b))))))
           image-width))
        (1- #.(expt 2 8))))))
6b17e8ac
 
 #+(or)
 ((list 'quote
        (loop for ti from 0 by (/ pi 7)
              for x from 0
              repeat 20
              collect (list (vector (- (* 2 (sin ti)) 1)
                                    (- (* 2 (cos ti)) 1)
                                    (+ -0.2 (* -0.3 x)))
                            0.25
                            nil
                            (list (vector (/ (mod (* 20 x)
                                                  256)
                                             256d0)
                                          (/ (mod (* 20 x)
                                                  256)
                                             256d0)
                                          (/ (mod (* 20 x)
                                                  256)
                                             256d0))))))
 
  '((#(-1.0 1.0 -0.2) 0.25 NIL)
    (#(-0.13223252176488376d0 0.8019377358048383d0 -0.5) 0.25 NIL)
    (#(0.5636629649360596d0 0.2469796037174672d0 -0.8) 0.25 NIL)
    (#(0.9498558243636472d0 -0.5549581320873711d0 -1.1) 0.25 NIL)
    (#(0.9498558243636472d0 -1.4450418679126287d0 -1.4000001) 0.25 NIL)
    (#(0.5636629649360598d0 -2.2469796037174667d0 -1.7) 0.25 NIL)
    (#(-0.13223252176488354d0 -2.801937735804838d0 -2.0) 0.25 NIL)
    (#(-0.9999999999999998d0 -3.0d0 -2.3000002) 0.25 NIL)
    (#(-1.8677674782351161d0 -2.801937735804838d0 -2.6000001) 0.25 NIL)
    (#(-2.5636629649360594d0 -2.246979603717467d0 -2.9) 0.25 NIL)
    (#(-2.949855824363647d0 -1.4450418679126291d0 -3.2) 0.25 NIL)
    (#(-2.949855824363647d0 -0.5549581320873715d0 -3.5000002) 0.25 NIL)
    (#(-2.56366296493606d0 0.24697960371746674d0 -3.8000002) 0.25 NIL)
    (#(-1.8677674782351166d0 0.8019377358048381d0 -4.1) 0.25 NIL)
    (#(-1.0000000000000004d0 1.0d0 -4.4) 0.25 NIL)
    (#(-0.1322325217648842d0 0.8019377358048385d0 -4.7) 0.25 NIL)
    (#(0.5636629649360592d0 0.2469796037174674d0 -5.0) 0.25 NIL)
    (#(0.949855824363647d0 -0.5549581320873707d0 -5.3) 0.25 NIL)
    (#(0.9498558243636475d0 -1.4450418679126282d0 -5.6) 0.25 NIL)
    (#(0.56366296493606d0 -2.2469796037174667d0 -5.9) 0.25 NIL))
 
  (/ 1960 60.0)
  )