git.fiddlerwoaroof.com
Browse code

chore(raytracer): split up the system a bit

Edward authored on 23/03/2021 06:11:43
Showing 7 changed files
... ...
@@ -1,147 +1,43 @@
1
-(defpackage :fwoar.lisp-sandbox.1
2
-  (:use :cl
3
-        )
4
-  (:export ))
5 1
 (in-package :fwoar.lisp-sandbox.1)
6 2
 
7
-(define-symbol-macro infinity
8
-  #.sb-ext:double-float-positive-infinity)
9
-(defun deg2rad (deg)
10
-  (/ (* deg pi)
11
-     180.0d0))
3
+(defclass hittable ()
4
+  ())
12 5
 
13
-(defun rand-min-max (min max)
14
-  (+ min
15
-     (* (- max min)
16
-        (random 1.0d0))))
6
+(fw.lu:defclass+ sphere (hittable)
7
+  ((center :initarg :center)
8
+   (radius :initarg :radius)
9
+   (material-color :initarg :color
10
+                   :reader material-color
11
+                   :initform (vec3 (random 1.0d0)
12
+                                   (random 1.0d0)
13
+                                   (random 1.0d0)))
14
+   (material :initarg :material
15
+             :reader .material
16
+             :initform (lambertian-material (random 0.8)))))
17
+
18
+(fw.lu:defclass+ ray ()
19
+  ((origin :initarg :origin)
20
+   (direction :initarg :direction)))
21
+
22
+(fw.lu:defclass+ hit-record ()
23
+  ((p :initarg :p :reader .p)
24
+   (time :initarg :time :reader .time)
25
+   (thing :initarg :thing :accessor .thing)
26
+   (material :initarg :material :accessor .material)
27
+   (normal :initarg :normal :accessor .normal :initform ())
28
+   (front-face :initarg :front-face :accessor .front-face :initform ())))
17 29
 
30
+(defclass camera ()
31
+  ((origin :initarg :origin :reader origin)
32
+   (lower-left-corner :initarg :lower-left-corner :reader lower-left-corner)
33
+   (horizontal :initarg :horizontal :reader horizontal)
34
+   (vertical :initarg :vertical :reader vertical)))
18 35
 
19
-(defstruct (size (:type vector))
20
-  width height)
21
-(defstruct (color (:type vector))
22
-  r g b)
23 36
 (defstruct (vec3 (:type vector)
24 37
                  (:constructor vec3 (x y z))
25 38
                  (:conc-name v3-))
26 39
   x y z)
27 40
 
28
-(defun rand-vec3 ()
29
-  (vec3 (random 1.0d0)
30
-        (random 1.0d0)
31
-        (random 1.0d0)))
32
-
33
-(defun rand-vec3-min-max (min max)
34
-  (vec3 (rand-min-max min max)
35
-        (rand-min-max min max)
36
-        (rand-min-max min max)))
37
-
38
-(declaim (inline vec+ vec* vec- vec/ random-in-unit-sphere negate))
39
-(defun random-in-unit-sphere ()
40
-  (loop for p = (rand-vec3-min-max -1.0d0 1.0d0)
41
-        while (>= (length-squared p)
42
-                  1)
43
-        finally (return p)))
44
-(defun random-unit-vector ()
45
-  (unit-vector (random-in-unit-sphere)))
46
-
47
-(defun vec+ (vec1 vec2)
48
-  (declare (optimize (speed 3)))
49
-  (fw.lu:vector-destructuring-bind (a b c) vec1
50
-    (fw.lu:vector-destructuring-bind (a1 b1 c1) vec2
51
-      (vec3 (+ a a1)
52
-            (+ b b1)
53
-            (+ c c1)))))
54
-(define-compiler-macro vec+ (&whole whole vec1 vec2)
55
-  (cond ((and (vectorp vec1)
56
-              (vectorp vec2))
57
-         (vec+ vec1 vec2))
58
-        ((vectorp vec1)
59
-         (alexandria:once-only (vec2)
60
-           `(fw.lu:vector-destructuring-bind (a b c) ,vec1
61
-              (vec3
62
-               (+ a (aref ,vec2 0))
63
-               (+ b (aref ,vec2 1))
64
-               (+ c (aref ,vec2 2))))))
65
-        ((vectorp vec2)
66
-         (alexandria:once-only (vec1)
67
-           `(fw.lu:vector-destructuring-bind (a b c) ,vec2
68
-              (vec3
69
-               (+ a (aref ,vec1 0))
70
-               (+ b (aref ,vec1 1))
71
-               (+ c (aref ,vec1 2))))))
72
-        (t whole)))
73
-(defun vec- (vec1 vec2)
74
-  (declare (optimize (speed 3)))
75
-  (fw.lu:vector-destructuring-bind (a b c) vec1
76
-    (fw.lu:vector-destructuring-bind (a1 b1 c1) vec2
77
-      (vec3 (- a a1)
78
-            (- b b1)
79
-            (- c c1)))))
80
-(defun vec* (vec1 vec2)
81
-  (declare (optimize (speed 3)))
82
-  (etypecase vec1
83
-    ((array * (3)) (fw.lu:vector-destructuring-bind (a b c) vec1
84
-                     (fw.lu:vector-destructuring-bind (a1 b1 c1) vec2
85
-                       (vec3 (* a a1)
86
-                             (* b b1)
87
-                             (* c c1)))))
88
-    (double-float (fw.lu:vector-destructuring-bind (a1 b1 c1) vec2
89
-                    (vec3 (* vec1 a1)
90
-                          (* vec1 b1)
91
-                          (* vec1 c1))))
92
-    (single-float (fw.lu:vector-destructuring-bind (a1 b1 c1) vec2
93
-                    (vec3 (* vec1 a1)
94
-                          (* vec1 b1)
95
-                          (* vec1 c1))))
96
-    (number (fw.lu:vector-destructuring-bind (a1 b1 c1) vec2
97
-              (vec3 (* vec1 a1)
98
-                    (* vec1 b1)
99
-                    (* vec1 c1))))))
100
-(defun negate (vec)
101
-  (fw.lu:vector-destructuring-bind (x y z) vec
102
-    (vec3 (- x)
103
-          (- y)
104
-          (- z))))
105
-
106
-(defun vec/ (vec it)
107
-  (declare (optimize (speed 3)))
108
-  (vec* (/ 1.0 it)
109
-        vec))
110
-(defun dot (u v)
111
-  (fw.lu:vector-destructuring-bind (a1 b1 c1) u
112
-    (fw.lu:vector-destructuring-bind (a2 b2 c2) v
113
-      (+ (* a1 a2)
114
-         (* b1 b2)
115
-         (* c1 c2)))))
116
-(defun cross (u v)
117
-  (fw.lu:vector-destructuring-bind (a1 b1 c1) u
118
-    (fw.lu:vector-destructuring-bind (a2 b2 c2) v
119
-      (vec3 (- (* b1 c2)
120
-               (* c1 b2))
121
-            (- (* c1 a2)
122
-               (* a1 c2))
123
-            (- (* a1 b2)
124
-               (* b1 a2))))))
125
-
126
-(defun length-squared (v)
127
-  (fw.lu:vector-destructuring-bind (x y z) v
128
-    (+ (* x x)
129
-       (* y y)
130
-       (* z z))))
131
-(defun vec-length (v)
132
-  (sqrt (length-squared v)))
133
-(defun unit-vector (v)
134
-  (vec/ v
135
-        (vec-length v)))
136
-
137
-(declaim (inline near-zero))
138
-(defun near-zero (vec)
139
-  (fw.lu:vector-destructuring-bind (x y z) vec
140
-    (let* ((s 1.0d-8))
141
-      (and (< (abs x) s)
142
-           (< (abs y) s)
143
-           (< (abs z) s)))))
144
-
145 41
 (defun call-with-ppm-header (stream size callback &optional (colors 255))
146 42
   (format stream "P3~%~d ~d~%~d~%"
147 43
           (size-width size)
... ...
@@ -152,27 +48,6 @@
152 48
 #.(progn (defmacro ig (&rest syms) `'(declare (ignore ,@syms)))
153 49
          nil)
154 50
 
155
-(defvar *color-depth* 255)
156
-
157
-(defun clamp (x min max)
158
-  (cond ((< x min) min)
159
-        ((> x max) max)
160
-        (t x)))
161
-
162
-(defvar *samples-per-pixel* 1)
163
-(defun scale-to-8bit (color)
164
-  (let ((scale (/ *samples-per-pixel*)))
165
-    (flet ((scale-to-depth (c)
166
-             (floor
167
-              (* *color-depth*
168
-                 (clamp (sqrt (* c scale))
169
-                        0.0d0 0.999d0)))))
170
-      (fwoar.lisputils:vector-destructuring-bind (r g b) color
171
-        (let ((r (scale-to-depth r))
172
-              (g (scale-to-depth g))
173
-              (b (scale-to-depth b)))
174
-          (vec3 r g b))))))
175
-
176 51
 (defun format-color (s v _ __)
177 52
   #.(ig _ __)
178 53
   (fw.lu:vector-destructuring-bind (r g b) (scale-to-8bit v)
... ...
@@ -197,23 +72,11 @@
197 72
     (when intermediate
198 73
       (format stream "~{~/fwoar.lisp-sandbox.1::format-color/~^  ~}~&" intermediate))))
199 74
 
200
-(fw.lu:defclass+ ray ()
201
-  ((origin :initarg :origin)
202
-   (direction :initarg :direction)))
203
-
204 75
 (defgeneric at (self it)
205 76
   (:method ((ray ray) (it number))
206 77
     (with-slots (origin direction) ray
207 78
       (vec+ origin
208 79
             (vec* it direction)))))
209
-
210
-(fw.lu:defclass+ hit-record ()
211
-  ((p :initarg :p :reader .p)
212
-   (time :initarg :time :reader .time)
213
-   (thing :initarg :thing :accessor .thing)
214
-   (material :initarg :material :accessor .material)
215
-   (normal :initarg :normal :accessor .normal :initform ())
216
-   (front-face :initarg :front-face :accessor .front-face :initform ())))
217 80
 (defun set-face-normal (hit-record r outward-normal)
218 81
   (prog1 hit-record
219 82
     (with-slots (direction) r
... ...
@@ -224,20 +87,6 @@
224 87
                                        outward-normal
225 88
                                        (vec* -1 outward-normal)))))))
226 89
 
227
-(defclass hittable ()
228
-  ())
229
-(fw.lu:defclass+ sphere (hittable)
230
-  ((center :initarg :center)
231
-   (radius :initarg :radius)
232
-   (material-color :initarg :color
233
-                   :reader material-color
234
-                   :initform (vec3 (random 1.0d0)
235
-                                   (random 1.0d0)
236
-                                   (random 1.0d0)))
237
-   (material :initarg :material
238
-             :reader .material
239
-             :initform (lambertian-material (random 0.8)))))
240
-
241 90
 (defgeneric hit (thing ray t-min t-max)
242 91
   (:method ((things list) (r ray) (t-min real) (t-max real))
243 92
     (let (temp-rec
... ...
@@ -304,26 +153,6 @@
304 153
 
305 154
 (defgeneric scatter (material ray-in rec))
306 155
 
307
-(defun original-material (rec ray world depth)
308
-  (declare (ignore ray world depth))
309
-  (vec* 0.5
310
-        (vec+ #(1 1 1)
311
-              (.normal rec))))
312
-
313
-(defun lambertian-material (albedo)
314
-  (lambda (rec ray world depth)
315
-    (declare (ignore ray))
316
-    (let ((scatter-direction (vec+ (.normal rec)
317
-                                   (random-unit-vector))))
318
-      (when (near-zero scatter-direction)
319
-        (setf scatter-direction (.normal rec)))
320
-
321
-      (vec* albedo
322
-            (ray-color (ray (.p rec)
323
-                            scatter-direction)
324
-                       world
325
-                       (1- depth))))))
326
-
327 156
 (defun reflect (v n)
328 157
   (vec- v
329 158
         (vec* 2.0d0
... ...
@@ -343,31 +172,6 @@
343 172
                              n)))
344 173
     (vec+ out-perp out-parallel)))
345 174
 
346
-(defun metal-material (albedo)
347
-  (lambda (rec ray world depth)
348
-    (with-slots (direction) ray
349
-      (let* ((reflected (reflect (unit-vector direction)
350
-                                 (.normal rec)))
351
-             (scattered (ray (.p rec) reflected)))
352
-        (vec* albedo
353
-              (ray-color scattered
354
-                         world
355
-                         (1- depth)))))))
356
-
357
-(defun fuzzy-metal-material (albedo fuzz)
358
-  (lambda (rec ray world depth)
359
-    (with-slots (direction) ray
360
-      (let* ((reflected (reflect (unit-vector direction)
361
-                                 (.normal rec)))
362
-             (scattered (ray (.p rec)
363
-                             (vec+ reflected
364
-                                   (vec* fuzz
365
-                                         (random-in-unit-sphere))))))
366
-        (vec* albedo
367
-              (ray-color scattered
368
-                         world
369
-                         (1- depth)))))))
370
-
371 175
 (defun reflectance (cosine ref-idx)
372 176
   (let* ((r0 (/ (- 1 ref-idx)
373 177
                 (+ 1 ref-idx)))
... ...
@@ -377,41 +181,8 @@
377 181
           (expt (- 1 cosine)
378 182
                 5)))))
379 183
 
380
-(defun dielectric-material (ir &optional (fuzz 0))
381
-  (lambda (rec ray world depth)
382
-    (with-slots (direction) ray
383
-      (let* ((attenuation (vec3 1.0d0 1.0d0 1.0d0))
384
-             (refraction-ratio (if (.front-face rec)
385
-                                   (/ 1.0d0 ir)
386
-                                   ir))
387
-             (unit-direction (unit-vector direction))
388
-             (normal (.normal rec))
389
-             (cos-theta (min 1.0d0
390
-                             (dot (negate unit-direction)
391
-                                  normal)))
392
-             (sin-theta (sqrt (- 1
393
-                                 (* cos-theta cos-theta))))
394
-             (cannot-refract (> (* refraction-ratio
395
-                                   sin-theta)
396
-                                1.0d0))
397
-             (direction (if (or cannot-refract
398
-                                (> (reflectance cos-theta
399
-                                                refraction-ratio)
400
-                                   (random 1.0d0)))
401
-                            (reflect unit-direction
402
-                                     normal)
403
-                            (refract unit-direction
404
-                                     normal
405
-                                     refraction-ratio)))
406
-             (scattered (ray (.p rec)
407
-                             (vec+ direction
408
-                                   (vec* fuzz
409
-                                         (random-in-unit-sphere))))))
410
-        (vec* attenuation
411
-              (ray-color scattered
412
-                         world
413
-                         (1- depth)))))))
414
-
184
+(define-symbol-macro infinity
185
+  #.sb-ext:double-float-positive-infinity)
415 186
 (defgeneric ray-color (ray world depth)
416 187
   (:method :around (r w (depth integer))
417 188
     (if (<= depth 0)
... ...
@@ -432,13 +203,6 @@
432 203
                 (vec* it
433 204
                       #(0.5d0 0.7d0 1.0d0))))))))
434 205
 
435
-
436
-(defclass camera ()
437
-  ((origin :initarg :origin :reader origin)
438
-   (lower-left-corner :initarg :lower-left-corner :reader lower-left-corner)
439
-   (horizontal :initarg :horizontal :reader horizontal)
440
-   (vertical :initarg :vertical :reader vertical)))
441
-
442 206
 (defun camera (&key
443 207
                  (aspect-ratio 16/9)
444 208
                  (viewport-height 2.0d0)
... ...
@@ -523,220 +287,3 @@
523 287
           do (rotatef (aref arr i)
524 288
                       (aref arr j))
525 289
           finally (return (coerce arr (type-of seq))))))
526
-
527
-(defun raytrace (out &optional (*samples-per-pixel* 10) (image-width 400) (max-depth 50))
528
-  (let* ((world (append (list (sphere #(0 0 -1) .5
529
-                                      #(0.5 0.5 0.0)
530
-                                      (dielectric-material 0.4)
531
-                                      #+(or)
532
-                                      (lambda (rec ray world depth)
533
-                                        (declare (ignore rec world depth))
534
-                                        (with-slots (direction) ray
535
-                                          (fw.lu:vector-destructuring-bind
536
-                                              (x y z) (unit-vector direction)
537
-                                            (vector (abs x)
538
-                                                    (abs y)
539
-                                                    (abs z)))))))
540
-                        (loop repeat 30
541
-                              collect (sphere (vector (rand-min-max -3 3)
542
-                                                      (rand-min-max -0.5 2)
543
-                                                      (rand-min-max -1.5d0 -0.5d0))
544
-                                              (rand-min-max 0.2 0.5)
545
-                                              (vector (random 1.0d0)
546
-                                                      (random 1.0d0)
547
-                                                      (random 1.0d0))
548
-                                              (case (random 5)
549
-                                                (0 (lambertian-material
550
-                                                    (rand-min-max 0.25 0.75)))
551
-                                                (1 (metal-material
552
-                                                    (rand-min-max 0.25 0.75)))
553
-                                                (2 (fuzzy-metal-material
554
-                                                    (rand-min-max 0.25 0.75)
555
-                                                    (rand-min-max 0.01 0.75)))
556
-                                                (3 (dielectric-material
557
-                                                    (rand-min-max 0.1 2.4)))
558
-                                                (4 #'original-material)
559
-                                                (5
560
-                                                 (lambda (rec ray world depth)
561
-                                                   (declare (ignore rec world depth))
562
-                                                   (vector 1d0 1d0 1d0)
563
-                                                   #+(or)
564
-                                                   (with-slots (direction) ray
565
-                                                     (fw.lu:vector-destructuring-bind
566
-                                                         (x y z) (unit-vector direction)
567
-                                                       (vector (abs x)
568
-                                                               (abs y)
569
-                                                               (abs z)))))))))
570
-                        ;; #+(or)
571
-                        (list (sphere #(0 -100.5 -1) 100
572
-                                      #(0.5 0.5 0.5)
573
-                                      (lambertian-material 0.2)))))
574
-         (aspect-ratio 4/3)
575
-         (image-height (* (floor (/ image-width aspect-ratio))))
576
-
577
-         (camera (camera :focal-length 1.0d0)))
578
-    (let ((mailbox (sb-concurrency:make-mailbox)))
579
-      (loop for j in (shuffle (loop for x from 0 to image-height collect x))
580
-            do
581
-               (sb-concurrency:send-message
582
-                (aref *thread-queues*
583
-                      (mod j
584
-                           (length *thread-queues*)))
585
-                (list *samples-per-pixel*
586
-                      j image-width
587
-                      image-height camera
588
-                      world max-depth
589
-                      (lambda (a b)
590
-                        (sb-concurrency:send-message
591
-                         mailbox
592
-                         (list a b))))))
593
-      (write-colors nil
594
-                    (lambda (c)
595
-                      (loop with messages = 0
596
-                            for it = (sb-concurrency:receive-message mailbox :timeout 2)
597
-                            while it
598
-                            do (destructuring-bind (color pos) it
599
-                                 (funcall c color pos))))
600
-                    image-width))))
601
-
602
-(defun refraction-scene
603
-    (out &optional (*samples-per-pixel* 10) (image-width 400) (max-depth 50))
604
-  (let* ((world (list (sphere #(0 0 -1) .5
605
-                              #(0.5 0.5 0.0)
606
-                              (lambertian-material #(0.7 0.3 0.3)))
607
-                      (sphere #(-1 0 -1) 0.5
608
-                              #(0 0 0)
609
-                              (dielectric-material 1.5))
610
-                      (sphere #(-1 0 -1) -0.4
611
-                              #(0 0 0)
612
-                              (dielectric-material 1.5))
613
-                      (sphere #(-1 0 -1) -0.2
614
-                              #(0 0 0)
615
-                              (lambertian-material
616
-                               #(0.8 0.6 0.2)))
617
-                      #+(or)
618
-                      (sphere #(1 0 -1) 0.5
619
-                              #(0 0 0)
620
-                              (dielectric-material 2.4))
621
-                      #+(or)
622
-                      (sphere #(-2 0 -1) 0.5
623
-                              #(0 0 0)
624
-                              (metal-material #(0.8 0.8 0.8)))
625
-                      (sphere #(1 0 -1) 0.5
626
-                              #(0 0 0)
627
-                              (metal-material #(0.8 0.6 0.2)))
628
-                      (sphere #(0 -100.5 -1) 100
629
-                              #(0.5 0.5 0.5)
630
-                              (lambertian-material #(0.8 0.8 0.0)))))
631
-         (aspect-ratio 16/9)
632
-         (image-height (* (floor (/ image-width aspect-ratio))))
633
-
634
-         (camera (camera)))
635
-    (let ((mailbox (sb-concurrency:make-mailbox)))
636
-      (loop for j in (shuffle (loop for x from 0 to image-height collect x))
637
-            do
638
-               (sb-concurrency:send-message
639
-                (aref *thread-queues*
640
-                      (mod j
641
-                           (length *thread-queues*)))
642
-                (list *samples-per-pixel*
643
-                      j image-width
644
-                      image-height camera
645
-                      world max-depth
646
-                      (lambda (a b)
647
-                        (sb-concurrency:send-message
648
-                         mailbox
649
-                         (list a b))))))
650
-      (write-colors nil
651
-                    (lambda (c)
652
-                      (loop with messages = 0
653
-                            for it = (sb-concurrency:receive-message mailbox :timeout 2)
654
-                            while it
655
-                            do (destructuring-bind (color pos) it
656
-                                 (funcall c color pos))))
657
-                    image-width))))
658
-
659
-(defun refraction-scene1
660
-    (out &optional (*samples-per-pixel* 10) (image-width 400) (max-depth 50))
661
-  (let* ((world (list (sphere #(0 0 -1) 1
662
-                              #(0.5 0.5 0.0)
663
-                              (dielectric-material 2.4))
664
-                      (sphere #(-0.5 0 -1) 0.5
665
-                              #(0 0 0)
666
-                              (dielectric-material 1.5 0.2))
667
-                      (sphere #(-0.5 0 -1) -0.4
668
-                              #(0 0 0)
669
-                              (dielectric-material 1.5 0.2))
670
-                      (sphere #(-0.5 0 -1) -0.2
671
-                              #(0 0 0)
672
-                              (metal-material
673
-                               #(0.8 0.6 0.2)))
674
-                      #+(or)
675
-                      (sphere #(1 0 -1) 0.5
676
-                              #(0 0 0)
677
-                              (dielectric-material 2.4))
678
-                      #+(or)
679
-                      (sphere #(-2 0 -1) 0.5
680
-                              #(0 0 0)
681
-                              (metal-material #(0.8 0.8 0.8)))
682
-                      (sphere #(0.5 0 -1) 0.5
683
-                              #(0 0 0)
684
-                              (metal-material #(0.8 0.6 0.2)))
685
-                      (sphere #(0 -100.5 -1) 100
686
-                              #(0.5 0.5 0.5)
687
-                              (lambertian-material #(0.8 0.8 0.0)))))
688
-         (aspect-ratio 16/9)
689
-         (image-height (* (floor (/ image-width aspect-ratio))))
690
-
691
-         (camera (camera)))
692
-    (let ((mailbox (sb-concurrency:make-mailbox)))
693
-      (loop for j in (shuffle (loop for x from 0 to image-height collect x))
694
-            do
695
-               (sb-concurrency:send-message
696
-                (aref *thread-queues*
697
-                      (mod j
698
-                           (length *thread-queues*)))
699
-                (list *samples-per-pixel*
700
-                      j image-width
701
-                      image-height camera
702
-                      world max-depth
703
-                      (lambda (a b)
704
-                        (sb-concurrency:send-message
705
-                         mailbox
706
-                         (list a b))))))
707
-      (write-colors nil
708
-                    (lambda (c)
709
-                      (loop with messages = 0
710
-                            for it = (sb-concurrency:receive-message mailbox :timeout 2)
711
-                            while it
712
-                            do (destructuring-bind (color pos) it
713
-                                 (funcall c color pos))))
714
-                    image-width))))
715
-
716
-(defun sample-image (out)
717
-  (let ((image-width 256)
718
-        (image-height 256))
719
-    (alexandria:with-output-to-file (s out :if-exists :supersede)
720
-      (call-with-ppm-header
721
-       s (make-size :width image-width :height image-height)
722
-       (lambda (s)
723
-         (write-colors
724
-          s (lambda (c)
725
-              (loop for j from (1- image-height) downto 0
726
-                    do (format *trace-output*
727
-                               "~&Scanlines remaining: ~d ~s~%"
728
-                               j
729
-                               (local-time:now))
730
-                    do
731
-                       (loop for i from 0 below image-width
732
-                             collect
733
-                             (let* ((r (/ (* i 1.0d0)
734
-                                          (1- image-width)))
735
-                                    (g (/ (* j 1.0d0)
736
-                                          (1- image-height)))
737
-                                    (b 0.15d0))
738
-                               (funcall c (make-color :r r
739
-                                                      :g g
740
-                                                      :b b))))))
741
-          image-width))
742
-       (1- #.(expt 2 8))))))
... ...
@@ -1,7 +1,3 @@
1
-(defpackage :fwoar.lisp-sandbox.canvas-server
2
-  (:use :cl )
3
-  (:export
4
-   #:send-update))
5 1
 (in-package :fwoar.lisp-sandbox.canvas-server)
6 2
 
7 3
 (defvar *ws-servers* (make-array 10 :fill-pointer 0 :adjustable t))
8 4
new file mode 100644
... ...
@@ -0,0 +1,82 @@
1
+(in-package :fwoar.lisp-sandbox.material)
2
+
3
+(defun original-material (rec ray world depth)
4
+  (declare (ignore ray world depth))
5
+  (vec* 0.5
6
+        (vec+ #(1 1 1)
7
+              (.normal rec))))
8
+
9
+(defun lambertian-material (albedo)
10
+  (lambda (rec ray world depth)
11
+    (declare (ignore ray))
12
+    (let ((scatter-direction (vec+ (.normal rec)
13
+                                   (random-unit-vector))))
14
+      (when (near-zero scatter-direction)
15
+        (setf scatter-direction (.normal rec)))
16
+
17
+      (vec* albedo
18
+            (ray-color (ray (.p rec)
19
+                            scatter-direction)
20
+                       world
21
+                       (1- depth))))))
22
+
23
+(defun metal-material (albedo)
24
+  (lambda (rec ray world depth)
25
+    (with-slots (direction) ray
26
+      (let* ((reflected (reflect (unit-vector direction)
27
+                                 (.normal rec)))
28
+             (scattered (ray (.p rec) reflected)))
29
+        (vec* albedo
30
+              (ray-color scattered
31
+                         world
32
+                         (1- depth)))))))
33
+
34
+(defun fuzzy-metal-material (albedo fuzz)
35
+  (lambda (rec ray world depth)
36
+    (with-slots (direction) ray
37
+      (let* ((reflected (reflect (unit-vector direction)
38
+                                 (.normal rec)))
39
+             (scattered (ray (.p rec)
40
+                             (vec+ reflected
41
+                                   (vec* fuzz
42
+                                         (random-in-unit-sphere))))))
43
+        (vec* albedo
44
+              (ray-color scattered
45
+                         world
46
+                         (1- depth)))))))
47
+
48
+
49
+(defun dielectric-material (ir &optional (fuzz 0))
50
+  (lambda (rec ray world depth)
51
+    (with-slots (direction) ray
52
+      (let* ((attenuation (vec3 1.0d0 1.0d0 1.0d0))
53
+             (refraction-ratio (if (.front-face rec)
54
+                                   (/ 1.0d0 ir)
55
+                                   ir))
56
+             (unit-direction (unit-vector direction))
57
+             (normal (.normal rec))
58
+             (cos-theta (min 1.0d0
59
+                             (dot (negate unit-direction)
60
+                                  normal)))
61
+             (sin-theta (sqrt (- 1
62
+                                 (* cos-theta cos-theta))))
63
+             (cannot-refract (> (* refraction-ratio
64
+                                   sin-theta)
65
+                                1.0d0))
66
+             (direction (if (or cannot-refract
67
+                                (> (reflectance cos-theta
68
+                                                refraction-ratio)
69
+                                   (random 1.0d0)))
70
+                            (reflect unit-direction
71
+                                     normal)
72
+                            (refract unit-direction
73
+                                     normal
74
+                                     refraction-ratio)))
75
+             (scattered (ray (.p rec)
76
+                             (vec+ direction
77
+                                   (vec* fuzz
78
+                                         (random-in-unit-sphere))))))
79
+        (vec* attenuation
80
+              (ray-color scattered
81
+                         world
82
+                         (1- depth)))))))
0 83
new file mode 100644
... ...
@@ -0,0 +1,28 @@
1
+(defpackage :fwoar.lisp-sandbox.package
2
+  (:use :cl )
3
+  (:export ))
4
+
5
+(in-package :fwoar.lisp-sandbox.package)
6
+
7
+(defpackage :fwoar.lisp-sandbox.canvas-server
8
+  (:use :cl )
9
+  (:export
10
+   #:send-update))
11
+
12
+(defpackage :fwoar.lisp-sandbox.material
13
+  (:use :cl)
14
+  (:export #:original-material
15
+           #:lambertian-material
16
+           #:metal-material
17
+           #:fuzzy-metal-material
18
+           #:dielectric-material))
19
+
20
+(defpackage :fwoar.lisp-sandbox.1
21
+  (:use :cl)
22
+  (:import :fwoar.lisp-sandbox.material
23
+           #:original-material
24
+           #:lambertian-material
25
+           #:metal-material
26
+           #:fuzzy-metal-material
27
+           #:dielectric-material)
28
+  (:export ))
... ...
@@ -17,6 +17,9 @@
17 17
                #:yason
18 18
                (:require :sb-concurrency))
19 19
   :serial t
20
-  :components ((:file "canvas-server")
20
+  :components ((:file "package")
21
+               (:file "canvas-server")
22
+               (:file "material")
23
+               (:file "vector-utils")
21 24
                (:file "1")
22
-               ))
25
+               (:file "scenes")))
23 26
new file mode 100644
... ...
@@ -0,0 +1,218 @@
1
+(in-package :fwoar.lisp-sandbox.1)
2
+
3
+(defun raytrace (out &optional (*samples-per-pixel* 10) (image-width 400) (max-depth 50))
4
+  (let* ((world (append (list (sphere #(0 0 -1) .5
5
+                                      #(0.5 0.5 0.0)
6
+                                      (dielectric-material 0.4)
7
+                                      #+(or)
8
+                                      (lambda (rec ray world depth)
9
+                                        (declare (ignore rec world depth))
10
+                                        (with-slots (direction) ray
11
+                                          (fw.lu:vector-destructuring-bind
12
+                                              (x y z) (unit-vector direction)
13
+                                            (vector (abs x)
14
+                                                    (abs y)
15
+                                                    (abs z)))))))
16
+                        (loop repeat 30
17
+                              collect (sphere (vector (rand-min-max -3 3)
18
+                                                      (rand-min-max -0.5 2)
19
+                                                      (rand-min-max -1.5d0 -0.5d0))
20
+                                              (rand-min-max 0.2 0.5)
21
+                                              (vector (random 1.0d0)
22
+                                                      (random 1.0d0)
23
+                                                      (random 1.0d0))
24
+                                              (case (random 5)
25
+                                                (0 (lambertian-material
26
+                                                    (rand-min-max 0.25 0.75)))
27
+                                                (1 (metal-material
28
+                                                    (rand-min-max 0.25 0.75)))
29
+                                                (2 (fuzzy-metal-material
30
+                                                    (rand-min-max 0.25 0.75)
31
+                                                    (rand-min-max 0.01 0.75)))
32
+                                                (3 (dielectric-material
33
+                                                    (rand-min-max 0.1 2.4)))
34
+                                                (4 #'original-material)
35
+                                                (5
36
+                                                 (lambda (rec ray world depth)
37
+                                                   (declare (ignore rec world depth))
38
+                                                   (vector 1d0 1d0 1d0)
39
+                                                   #+(or)
40
+                                                   (with-slots (direction) ray
41
+                                                     (fw.lu:vector-destructuring-bind
42
+                                                         (x y z) (unit-vector direction)
43
+                                                       (vector (abs x)
44
+                                                               (abs y)
45
+                                                               (abs z)))))))))
46
+                        ;; #+(or)
47
+                        (list (sphere #(0 -100.5 -1) 100
48
+                                      #(0.5 0.5 0.5)
49
+                                      (lambertian-material 0.2)))))
50
+         (aspect-ratio 4/3)
51
+         (image-height (* (floor (/ image-width aspect-ratio))))
52
+
53
+         (camera (camera :focal-length 1.0d0)))
54
+    (let ((mailbox (sb-concurrency:make-mailbox)))
55
+      (loop for j in (shuffle (loop for x from 0 to image-height collect x))
56
+            do
57
+               (sb-concurrency:send-message
58
+                (aref *thread-queues*
59
+                      (mod j
60
+                           (length *thread-queues*)))
61
+                (list *samples-per-pixel*
62
+                      j image-width
63
+                      image-height camera
64
+                      world max-depth
65
+                      (lambda (a b)
66
+                        (sb-concurrency:send-message
67
+                         mailbox
68
+                         (list a b))))))
69
+      (write-colors nil
70
+                    (lambda (c)
71
+                      (loop with messages = 0
72
+                            for it = (sb-concurrency:receive-message mailbox :timeout 2)
73
+                            while it
74
+                            do (destructuring-bind (color pos) it
75
+                                 (funcall c color pos))))
76
+                    image-width))))
77
+
78
+(defun refraction-scene
79
+    (out &optional (*samples-per-pixel* 10) (image-width 400) (max-depth 50))
80
+  (let* ((world (list (sphere #(0 0 -1) .5
81
+                              #(0.5 0.5 0.0)
82
+                              (lambertian-material #(0.7 0.3 0.3)))
83
+                      (sphere #(-1 0 -1) 0.5
84
+                              #(0 0 0)
85
+                              (dielectric-material 1.5))
86
+                      (sphere #(-1 0 -1) -0.4
87
+                              #(0 0 0)
88
+                              (dielectric-material 1.5))
89
+                      (sphere #(-1 0 -1) -0.2
90
+                              #(0 0 0)
91
+                              (lambertian-material
92
+                               #(0.8 0.6 0.2)))
93
+                      #+(or)
94
+                      (sphere #(1 0 -1) 0.5
95
+                              #(0 0 0)
96
+                              (dielectric-material 2.4))
97
+                      #+(or)
98
+                      (sphere #(-2 0 -1) 0.5
99
+                              #(0 0 0)
100
+                              (metal-material #(0.8 0.8 0.8)))
101
+                      (sphere #(1 0 -1) 0.5
102
+                              #(0 0 0)
103
+                              (metal-material #(0.8 0.6 0.2)))
104
+                      (sphere #(0 -100.5 -1) 100
105
+                              #(0.5 0.5 0.5)
106
+                              (lambertian-material #(0.8 0.8 0.0)))))
107
+         (aspect-ratio 16/9)
108
+         (image-height (* (floor (/ image-width aspect-ratio))))
109
+
110
+         (camera (camera)))
111
+    (let ((mailbox (sb-concurrency:make-mailbox)))
112
+      (loop for j in (shuffle (loop for x from 0 to image-height collect x))
113
+            do
114
+               (sb-concurrency:send-message
115
+                (aref *thread-queues*
116
+                      (mod j
117
+                           (length *thread-queues*)))
118
+                (list *samples-per-pixel*
119
+                      j image-width
120
+                      image-height camera
121
+                      world max-depth
122
+                      (lambda (a b)
123
+                        (sb-concurrency:send-message
124
+                         mailbox
125
+                         (list a b))))))
126
+      (write-colors nil
127
+                    (lambda (c)
128
+                      (loop with messages = 0
129
+                            for it = (sb-concurrency:receive-message mailbox :timeout 2)
130
+                            while it
131
+                            do (destructuring-bind (color pos) it
132
+                                 (funcall c color pos))))
133
+                    image-width))))
134
+
135
+(defun refraction-scene1
136
+    (out &optional (*samples-per-pixel* 10) (image-width 400) (max-depth 50))
137
+  (let* ((world (list (sphere #(0 0 -1) 1
138
+                              #(0.5 0.5 0.0)
139
+                              (dielectric-material 2.4))
140
+                      (sphere #(-0.5 0 -1) 0.5
141
+                              #(0 0 0)
142
+                              (dielectric-material 1.5 0.2))
143
+                      (sphere #(-0.5 0 -1) -0.4
144
+                              #(0 0 0)
145
+                              (dielectric-material 1.5 0.2))
146
+                      (sphere #(-0.5 0 -1) -0.2
147
+                              #(0 0 0)
148
+                              (metal-material
149
+                               #(0.8 0.6 0.2)))
150
+                      #+(or)
151
+                      (sphere #(1 0 -1) 0.5
152
+                              #(0 0 0)
153
+                              (dielectric-material 2.4))
154
+                      #+(or)
155
+                      (sphere #(-2 0 -1) 0.5
156
+                              #(0 0 0)
157
+                              (metal-material #(0.8 0.8 0.8)))
158
+                      (sphere #(0.5 0 -1) 0.5
159
+                              #(0 0 0)
160
+                              (metal-material #(0.8 0.6 0.2)))
161
+                      (sphere #(0 -100.5 -1) 100
162
+                              #(0.5 0.5 0.5)
163
+                              (lambertian-material #(0.8 0.8 0.0)))))
164
+         (aspect-ratio 16/9)
165
+         (image-height (* (floor (/ image-width aspect-ratio))))
166
+
167
+         (camera (camera)))
168
+    (let ((mailbox (sb-concurrency:make-mailbox)))
169
+      (loop for j in (shuffle (loop for x from 0 to image-height collect x))
170
+            do
171
+               (sb-concurrency:send-message
172
+                (aref *thread-queues*
173
+                      (mod j
174
+                           (length *thread-queues*)))
175
+                (list *samples-per-pixel*
176
+                      j image-width
177
+                      image-height camera
178
+                      world max-depth
179
+                      (lambda (a b)
180
+                        (sb-concurrency:send-message
181
+                         mailbox
182
+                         (list a b))))))
183
+      (write-colors nil
184
+                    (lambda (c)
185
+                      (loop with messages = 0
186
+                            for it = (sb-concurrency:receive-message mailbox :timeout 2)
187
+                            while it
188
+                            do (destructuring-bind (color pos) it
189
+                                 (funcall c color pos))))
190
+                    image-width))))
191
+
192
+(defun sample-image (out)
193
+  (let ((image-width 256)
194
+        (image-height 256))
195
+    (alexandria:with-output-to-file (s out :if-exists :supersede)
196
+      (call-with-ppm-header
197
+       s (make-size :width image-width :height image-height)
198
+       (lambda (s)
199
+         (write-colors
200
+          s (lambda (c)
201
+              (loop for j from (1- image-height) downto 0
202
+                    do (format *trace-output*
203
+                               "~&Scanlines remaining: ~d ~s~%"
204
+                               j
205
+                               (local-time:now))
206
+                    do
207
+                       (loop for i from 0 below image-width
208
+                             collect
209
+                             (let* ((r (/ (* i 1.0d0)
210
+                                          (1- image-width)))
211
+                                    (g (/ (* j 1.0d0)
212
+                                          (1- image-height)))
213
+                                    (b 0.15d0))
214
+                               (funcall c (make-color :r r
215
+                                                      :g g
216
+                                                      :b b))))))
217
+          image-width))
218
+       (1- #.(expt 2 8))))))
0 219
new file mode 100644
... ...
@@ -0,0 +1,149 @@
1
+(in-package :fwoar.lisp-sandbox.1)
2
+
3
+(defun deg2rad (deg)
4
+  (/ (* deg pi)
5
+     180.0d0))
6
+
7
+(defun rand-min-max (min max)
8
+  (+ min
9
+     (* (- max min)
10
+        (random 1.0d0))))
11
+
12
+(defun rand-vec3 ()
13
+  (vec3 (random 1.0d0)
14
+        (random 1.0d0)
15
+        (random 1.0d0)))
16
+
17
+(defun rand-vec3-min-max (min max)
18
+  (vec3 (rand-min-max min max)
19
+        (rand-min-max min max)
20
+        (rand-min-max min max)))
21
+
22
+(declaim (inline vec+ vec* vec- vec/ random-in-unit-sphere negate))
23
+(defun random-in-unit-sphere ()
24
+  (loop for p = (rand-vec3-min-max -1.0d0 1.0d0)
25
+        while (>= (length-squared p)
26
+                  1)
27
+        finally (return p)))
28
+
29
+(defun random-unit-vector ()
30
+  (unit-vector (random-in-unit-sphere)))
31
+
32
+(defun vec+ (vec1 vec2)
33
+  (declare (optimize (speed 3)))
34
+  (fw.lu:vector-destructuring-bind (a b c) vec1
35
+    (fw.lu:vector-destructuring-bind (a1 b1 c1) vec2
36
+      (vec3 (+ a a1)
37
+            (+ b b1)
38
+            (+ c c1)))))
39
+(define-compiler-macro vec+ (&whole whole vec1 vec2)
40
+  (cond ((and (vectorp vec1)
41
+              (vectorp vec2))
42
+         (vec+ vec1 vec2))
43
+        ((vectorp vec1)
44
+         (alexandria:once-only (vec2)
45
+           `(fw.lu:vector-destructuring-bind (a b c) ,vec1
46
+              (vec3
47
+               (+ a (aref ,vec2 0))
48
+               (+ b (aref ,vec2 1))
49
+               (+ c (aref ,vec2 2))))))
50
+        ((vectorp vec2)
51
+         (alexandria:once-only (vec1)
52
+           `(fw.lu:vector-destructuring-bind (a b c) ,vec2
53
+              (vec3
54
+               (+ a (aref ,vec1 0))
55
+               (+ b (aref ,vec1 1))
56
+               (+ c (aref ,vec1 2))))))
57
+        (t whole)))
58
+(defun vec- (vec1 vec2)
59
+  (declare (optimize (speed 3)))
60
+  (fw.lu:vector-destructuring-bind (a b c) vec1
61
+    (fw.lu:vector-destructuring-bind (a1 b1 c1) vec2
62
+      (vec3 (- a a1)
63
+            (- b b1)
64
+            (- c c1)))))
65
+(defun vec* (vec1 vec2)
66
+  (declare (optimize (speed 3)))
67
+  (etypecase vec1
68
+    ((array * (3)) (fw.lu:vector-destructuring-bind (a b c) vec1
69
+                     (fw.lu:vector-destructuring-bind (a1 b1 c1) vec2
70
+                       (vec3 (* a a1)
71
+                             (* b b1)
72
+                             (* c c1)))))
73
+    (double-float (fw.lu:vector-destructuring-bind (a1 b1 c1) vec2
74
+                    (vec3 (* vec1 a1)
75
+                          (* vec1 b1)
76
+                          (* vec1 c1))))
77
+    (single-float (fw.lu:vector-destructuring-bind (a1 b1 c1) vec2
78
+                    (vec3 (* vec1 a1)
79
+                          (* vec1 b1)
80
+                          (* vec1 c1))))
81
+    (number (fw.lu:vector-destructuring-bind (a1 b1 c1) vec2
82
+              (vec3 (* vec1 a1)
83
+                    (* vec1 b1)
84
+                    (* vec1 c1))))))
85
+(defun negate (vec)
86
+  (fw.lu:vector-destructuring-bind (x y z) vec
87
+    (vec3 (- x)
88
+          (- y)
89
+          (- z))))
90
+
91
+(defun vec/ (vec it)
92
+  (declare (optimize (speed 3)))
93
+  (vec* (/ 1.0 it)
94
+        vec))
95
+(defun dot (u v)
96
+  (fw.lu:vector-destructuring-bind (a1 b1 c1) u
97
+    (fw.lu:vector-destructuring-bind (a2 b2 c2) v
98
+      (+ (* a1 a2)
99
+         (* b1 b2)
100
+         (* c1 c2)))))
101
+(defun cross (u v)
102
+  (fw.lu:vector-destructuring-bind (a1 b1 c1) u
103
+    (fw.lu:vector-destructuring-bind (a2 b2 c2) v
104
+      (vec3 (- (* b1 c2)
105
+               (* c1 b2))
106
+            (- (* c1 a2)
107
+               (* a1 c2))
108
+            (- (* a1 b2)
109
+               (* b1 a2))))))
110
+
111
+(defun length-squared (v)
112
+  (fw.lu:vector-destructuring-bind (x y z) v
113
+    (+ (* x x)
114
+       (* y y)
115
+       (* z z))))
116
+(defun vec-length (v)
117
+  (sqrt (length-squared v)))
118
+(defun unit-vector (v)
119
+  (vec/ v
120
+        (vec-length v)))
121
+
122
+(declaim (inline near-zero))
123
+(defun near-zero (vec)
124
+  (fw.lu:vector-destructuring-bind (x y z) vec
125
+    (let* ((s 1.0d-8))
126
+      (and (< (abs x) s)
127
+           (< (abs y) s)
128
+           (< (abs z) s)))))
129
+
130
+(defvar *color-depth* 255)
131
+
132
+(defun clamp (x min max)
133
+  (cond ((< x min) min)
134
+        ((> x max) max)
135
+        (t x)))
136
+
137
+(defvar *samples-per-pixel* 1)
138
+(defun scale-to-8bit (color)
139
+  (let ((scale (/ *samples-per-pixel*)))
140
+    (flet ((scale-to-depth (c)
141
+             (floor
142
+              (* *color-depth*
143
+                 (clamp (sqrt (* c scale))
144
+                        0.0d0 0.999d0)))))
145
+      (fwoar.lisputils:vector-destructuring-bind (r g b) color
146
+        (let ((r (scale-to-depth r))
147
+              (g (scale-to-depth g))
148
+              (b (scale-to-depth b)))
149
+          (vec3 r g b))))))