diff --git a/README.org b/README.org index 7a6d628..b37555c 100644 --- a/README.org +++ b/README.org @@ -607,6 +607,19 @@ This can be used, for example, to draw a static sketch and then disable the draw Example: [[https://github.com/vydd/sketch/blob/master/examples/control-flow.lisp][control-flow.lisp]]. +*** Noise +=(noise &rest coords)= generates a correlated random value in the range 0-1. Similar inputs give similar outputs, hence the term "correlated". This can be useful for producing natural-looking textures and terrain, among other things. See [[https://en.wikipedia.org/wiki/Gradient_noise][Gradient noise]]. + +=(noise-seed seed)= seeds the noise so that its output is reproducible, where `seed` is an integer. + +=(noise-detail &key lod falloff)= determines the 'character' of the noise, based on the =noiseDetail()= function from p5js. + +- =lod= stands for Level Of Detail. It should be a positive integer value (default is 4), and determines how many noise values are generated and summed together to produce the final value. Lower values -> smoother and more efficient, higher values -> greater level of detail. +- =falloff= should be between 0 and 1; its default value is 0.5. Each successive noise value in the sum is weighted by increasing powers of the falloff. A falloff of greater than 0.5 will possibly result in noise outputs of greater than 1. +- Another way to change the appearance of noise is to scale the inputs. Making the inputs smaller and closer together will make the output smoother. Scaling them up will have the opposite effect. The output value can also be scaled, obviously so that it goes outside the range 0-1. + +Example: [[https://github.com/vydd/sketch/blob/master/examples/noise.lisp][noise.lisp]]. + ** Made with Sketch - [[https://vydd.itch.io/qelt][QELT]] - [[https://github.com/sjl/coding-math][sjl's implementation of coding math videos]] diff --git a/examples/noise.lisp b/examples/noise.lisp new file mode 100644 index 0000000..2dd17f3 --- /dev/null +++ b/examples/noise.lisp @@ -0,0 +1,17 @@ +(in-package #:sketch-examples) + +(defsketch noise-sketch + ((title "Noise") + (width 400) + (height 400) + (pixel-size 2) + (pixel-width (floor width pixel-size)) + (pixel-height (floor height pixel-size)) + (coord-scale 0.02)) + (noise-seed 5) + (noise-detail :lod 1 :falloff 0.5) + (dotimes (i pixel-width) + (dotimes (j pixel-height) + (with-pen (make-pen :fill (gray (noise (* coord-scale i) (* coord-scale j)))) + (rect (* i pixel-size) (* j pixel-size) pixel-size pixel-size)))) + (stop-loop)) diff --git a/examples/package.lisp b/examples/package.lisp index 8dfced3..b2c1b39 100644 --- a/examples/package.lisp +++ b/examples/package.lisp @@ -9,4 +9,5 @@ :stars :indigo :control-flow + :noise-sketch )) diff --git a/sketch-examples.asd b/sketch-examples.asd index 2249f9b..18bd2d8 100644 --- a/sketch-examples.asd +++ b/sketch-examples.asd @@ -15,4 +15,6 @@ (:file "hello-world") (:file "stars") (:file "indigo") + (:file "control-flow") + (:file "noise") )) diff --git a/sketch.asd b/sketch.asd index 970405a..77da186 100644 --- a/sketch.asd +++ b/sketch.asd @@ -10,6 +10,7 @@ #:glu-tessellate #:mathkit #:md5 + #:noisy #:sdl2 #:cl-plus-c #:sdl2-image @@ -42,4 +43,5 @@ (:file "entities") (:file "figures") (:file "controllers") - (:file "canvas"))) + (:file "canvas") + (:file "noise"))) diff --git a/src/noise.lisp b/src/noise.lisp new file mode 100644 index 0000000..4b06d38 --- /dev/null +++ b/src/noise.lisp @@ -0,0 +1,43 @@ +;;;; noise.lisp + +(in-package #:sketch) + +;;; _ _ ____ _____ _____ ______ +;;; | \ | |/ __ \_ _|/ ____| ____| +;;; | \| | | | || | | (___ | |__ +;;; | . ` | | | || | \___ \| __| +;;; | |\ | |__| || |_ ____) | |____ +;;; |_| \_|\____/_____|_____/|______| + +(defun noise (&rest coordinates) + (when *sketch* + (if (null coordinates) + 0 + (let* ((noise-map (sketch-%noise-map *sketch*)) + (d (length coordinates)) + (state (gethash d noise-map))) + (when (not state) + (setf state (noisy:make-noise d + :seed (sketch-%noise-seed *sketch*) + :lod (sketch-%noise-lod *sketch*) + :falloff (sketch-%noise-falloff *sketch*))) + (setf (gethash d noise-map) state)) + (apply #'noisy:noise-gen state coordinates))))) + +(defun noise-seed (seed) + (when *sketch* + (setf (sketch-%noise-seed *sketch*) seed) + ;; So that the noise state for each number of dimensions is reinitialised + ;; with the new seed. + (reset-noise-map *sketch*))) + +(defun noise-detail (&key lod falloff) + (when *sketch* + (when lod + (setf (sketch-%noise-lod *sketch*) lod)) + (when falloff + (setf (sketch-%noise-falloff *sketch*) falloff)) + (reset-noise-map *sketch*))) + +(defun reset-noise-map (sketch) + (clrhash (sketch-%noise-map sketch))) diff --git a/src/package.lisp b/src/package.lisp index 8b10f07..5756f14 100644 --- a/src/package.lisp +++ b/src/package.lisp @@ -207,4 +207,9 @@ ;; Control flow :start-loop :stop-loop + + ;; Noise + :noise + :noise-seed + :noise-detail )) diff --git a/src/sketch.lisp b/src/sketch.lisp index da10b4d..4ff2c94 100644 --- a/src/sketch.lisp +++ b/src/sketch.lisp @@ -34,6 +34,10 @@ (%window :initform nil :accessor sketch-%window :initarg :window) (%delayed-init-funs :initform (make-array 0 :adjustable t :fill-pointer t) :accessor sketch-%delayed-init-funs) + (%noise-seed :initform 7 :accessor sketch-%noise-seed) + (%noise-map :initform (make-hash-table) :accessor sketch-%noise-map) + (%noise-lod :initform 4 :accessor sketch-%noise-lod) + (%noise-falloff :initform 0.5 :accessor sketch-%noise-falloff) (title :initform "Sketch" :accessor sketch-title :initarg :title) (width :initform *default-width* :accessor sketch-width :initarg :width) (height :initform *default-height* :accessor sketch-height :initarg :height)