diff --git a/notebooks/chapter_0.md b/notebooks/chapter_0.md index 7ca7b2c..ab46314 100644 --- a/notebooks/chapter_0.md +++ b/notebooks/chapter_0.md @@ -225,3 +225,30 @@ Of course in clojure we can't do that [^um-actually], so I took the approach of Click that reset button to see it regenerated! [^um-actually]: Well, technically we can using dynamic vars or an atom, but that's pretty nasty and should only be used as an escape hatch when necessary. + + +## [Exercise 0.8: A Perlin Noise Technicolor](https://natureofcode.com/random/#exercise-08) + +```clojure +^{::clerk/no-cache true ::clerk/viewer clerk/code} +(slurp "src/noc/chapter_0_8e.cljs") +(show-sketch :c0.8e) +``` + + +## [Exercise 0.9: Perlin Noise Animation](https://natureofcode.com/random/#exercise-08) + +```clojure +^{::clerk/no-cache true ::clerk/viewer clerk/code} +(slurp "src/noc/chapter_0_9e.cljs") +(show-sketch :c0.9e) +``` + +Well this one is pretty cool. The sliders control (in order from left to right): + +* Perlin noise `octaves` +* Perlin noise octave `fallof` +* Amount `xoff` is incremented by +* Amount `yoff` is incremented by + +Finally there is a checkbox to enable animation using the 3rd dimension of the perlin noise. diff --git a/src/noc/chapter_0_8e.cljs b/src/noc/chapter_0_8e.cljs new file mode 100644 index 0000000..c8f851a --- /dev/null +++ b/src/noc/chapter_0_8e.cljs @@ -0,0 +1,89 @@ +(ns noc.chapter-0-8e + (:require + [goog.string :as gstring] + [goog.string.format] + [quil.core :as q])) + +(def size [640 240]) + +(defn init-state [_] + {:ui {:octaves {:type :slider + :min 1 :max 20 + :step 1 :value 4} + :falloff {:type :slider + :min 0 :max 0.5 + :step 0.01 + :label "test" + :value 0} + :xoff-incr {:type :slider + :min 0 :max 0.1 + :step 0.01 + :value 0.01} + + :yoff-incr {:type :slider + :min 0 :max 0.1 + :step 0.01 + :value 0.01}}}) + +(defn setup! [{:keys [width height]}] + (q/noise-seed (rand-int (-> js/Number (.-MAX_SAFE_INTEGER)))) + (q/background 255)) + +(defn gen-noise-image [width height xoff-incr yoff-incr] + (let [rand-color (fn [t1 t2] + (Math/floor (q/map-range (q/noise t1 t2) 0 1 0 255))) + img (q/create-image width height) + roff 0 + goff 10000 + boff 100000 + px (q/pixels img) + xoffs (take width (iterate #(+ % xoff-incr) 0.0))] + (doseq [[x xoff] (map-indexed vector xoffs)] + (let [yoffs (take height (iterate #(+ % yoff-incr) 0.0))] + (doseq [[y yoff] (map-indexed vector yoffs)] + (let [idx (* 4 (+ x (* y width))) + r (rand-color (+ roff xoff) (+ roff yoff)) + g (rand-color (+ goff xoff) (+ goff yoff)) + b (rand-color (+ boff xoff) (+ boff yoff))] + (aset px idx r) + (aset px (+ 1 idx) g) + (aset px (+ 2 idx) b) + (aset px (+ 3 idx) 255))))) + (q/update-pixels img) + img)) + +(defn tick [{:keys [old-octaves old-falloff old-yoff-incr old-xoff-incr width height] :as state}] + (let [octaves (-> state :ui :octaves :value) + falloff (-> state :ui :falloff :value) + xoff-incr (-> state :ui :xoff-incr :value) + yoff-incr (-> state :ui :yoff-incr :value)] + (if (or (not= octaves old-octaves) + (not= falloff old-falloff) + (not= yoff-incr old-yoff-incr) + (not= xoff-incr old-xoff-incr)) + (do + (q/noise-detail octaves falloff) + (assoc state + :old-octaves octaves + :old-falloff falloff + :old-xoff-incr xoff-incr + :old-yoff-incr yoff-incr + :img (gen-noise-image width height xoff-incr yoff-incr))) + state))) + +(defn draw! [{:keys [ui img]}] + (let [octaves (-> ui :octaves :value) + falloff (-> ui :falloff :value) + xoff-incr (-> ui :xoff-incr :value) + yoff-incr (-> ui :yoff-incr :value)] + + (when img + (q/image img 0 0)) + (q/no-stroke) + (q/fill 255) + (q/rect 0 0 100 55) + (q/fill 0) + (q/text (gstring/format "octaves: %.2f" octaves) 10 20) + (q/text (gstring/format "falloff: %.2f" falloff) 10 30) + (q/text (gstring/format "xoff-incr: %.2f" xoff-incr) 10 40) + (q/text (gstring/format "yoff-incr: %.2f" yoff-incr) 10 50))) diff --git a/src/noc/chapter_0_9e.cljs b/src/noc/chapter_0_9e.cljs new file mode 100644 index 0000000..2e38d69 --- /dev/null +++ b/src/noc/chapter_0_9e.cljs @@ -0,0 +1,95 @@ +(ns noc.chapter-0-9e + (:require + [goog.string :as gstring] + [goog.string.format] + [quil.core :as q])) + +(def size [640 240]) + +(defn init-state [_] + {:z 0.0 + :ui {:octaves {:type :slider + :min 1 :max 20 + :step 1 :value 4} + :falloff {:type :slider + :min 0 :max 0.5 + :step 0.01 + :label "test" + :value 0} + :xoff-incr {:type :slider + :min 0 :max 0.1 + :step 0.01 + :value 0.01} + + :yoff-incr {:type :slider + :min 0 :max 0.1 + :step 0.01 + :value 0.01} + :animate {:type :checkbox :checked? false}}}) + +(defn setup! [{:keys [width height]}] + (q/noise-seed (rand-int (-> js/Number (.-MAX_SAFE_INTEGER)))) + (q/background 255)) + +(defn gen-noise-image [width height xoff-incr yoff-incr z] + (let [rand-color (fn [t1 t2] + (Math/floor (q/map-range (q/noise t1 t2 z) 0 1 0 255))) + img (q/create-image width height) + roff 0 + goff 10000 + boff 100000 + px (q/pixels img) + xoffs (take width (iterate #(+ % xoff-incr) 0.0))] + (doseq [[x xoff] (map-indexed vector xoffs)] + (let [yoffs (take height (iterate #(+ % yoff-incr) 0.0))] + (doseq [[y yoff] (map-indexed vector yoffs)] + (let [idx (* 4 (+ x (* y width))) + r (rand-color (+ roff xoff) (+ roff yoff)) + g (rand-color (+ goff xoff) (+ goff yoff)) + b (rand-color (+ boff xoff) (+ boff yoff))] + (aset px idx r) + (aset px (+ 1 idx) g) + (aset px (+ 2 idx) b) + (aset px (+ 3 idx) 255))))) + (q/update-pixels img) + img)) + +(defn tick [{:keys [old-octaves old-falloff old-yoff-incr old-xoff-incr width height z] :as state}] + (let [octaves (-> state :ui :octaves :value) + falloff (-> state :ui :falloff :value) + xoff-incr (-> state :ui :xoff-incr :value) + yoff-incr (-> state :ui :yoff-incr :value) + animate? (-> state :ui :animate :checked?) + z (+ 0.1 z)] + (if (or animate? + (not= octaves old-octaves) + (not= falloff old-falloff) + (not= yoff-incr old-yoff-incr) + (not= xoff-incr old-xoff-incr)) + (do + (q/noise-detail octaves falloff) + (assoc state + :z z + :old-octaves octaves + :old-falloff falloff + :old-xoff-incr xoff-incr + :old-yoff-incr yoff-incr + :img (gen-noise-image width height xoff-incr yoff-incr z))) + state))) + +(defn draw! [{:keys [ui img]}] + (let [octaves (-> ui :octaves :value) + falloff (-> ui :falloff :value) + xoff-incr (-> ui :xoff-incr :value) + yoff-incr (-> ui :yoff-incr :value)] + + (when img + (q/image img 0 0)) + (q/no-stroke) + (q/fill 255) + (q/rect 0 0 100 55) + (q/fill 0) + (q/text (gstring/format "octaves: %.2f" octaves) 10 20) + (q/text (gstring/format "falloff: %.2f" falloff) 10 30) + (q/text (gstring/format "xoff-incr: %.2f" xoff-incr) 10 40) + (q/text (gstring/format "yoff-incr: %.2f" yoff-incr) 10 50))) diff --git a/src/noc/sketch.cljs b/src/noc/sketch.cljs index af826ea..31b47d0 100644 --- a/src/noc/sketch.cljs +++ b/src/noc/sketch.cljs @@ -15,7 +15,9 @@ [noc.chapter-0-6e :as c0.6e] [noc.chapter-0-6 :as c0.6] [noc.chapter-0-7e :as c0.7e] - [noc.chapter-0-7 :as c0.7])) + [noc.chapter-0-7 :as c0.7] + [noc.chapter-0-8e :as c0.8e] + [noc.chapter-0-9e :as c0.9e])) (def sketches {:walker (sketch-> c0.1) :rand-dist (sketch-> c0.2) @@ -28,7 +30,9 @@ :c0.6e (sketch-> c0.6e) :c0.6 (sketch-> c0.6) :c0.7e (sketch-> c0.7e) - :c0.7 (sketch-> c0.7)}) + :c0.7 (sketch-> c0.7) + :c0.8e (sketch-> c0.8e) + :c0.9e (sketch-> c0.9e)}) (defn load-sketch [s] (when-let [sk (get sketches s)]