|
35 | 35 | ;; Note that this article is about procedural generation and not about simulating real weather. |
36 | 36 | ;; |
37 | 37 | ;; ## Worley noise |
38 | | - |
| 38 | +;; |
| 39 | +;; [Worley noise](https://en.wikipedia.org/wiki/Worley_noise) is a type of structured noise which is defined for each pixel using the distance to the nearest seed point. |
| 40 | +;; |
| 41 | +;; First we define a function to create parameters of the noise. |
| 42 | +;; |
| 43 | +;; * **size** is the size of each dimension of the noise array |
| 44 | +;; * **divisions** is the number of subdividing cells in each dimension |
| 45 | +;; * **dimensions** is the number of dimensions |
39 | 46 |
|
40 | 47 | (defn make-noise-params |
41 | 48 | [size divisions dimensions] |
|
75 | 82 |
|
76 | 83 | (defn random-points |
77 | 84 | [{:keys [divisions dimensions] :as params}] |
78 | | - (tensor/clone (tensor/compute-tensor (repeat dimensions divisions) (partial random-point-in-cell params)))) |
| 85 | + (tensor/clone |
| 86 | + (tensor/compute-tensor (repeat dimensions divisions) |
| 87 | + (partial random-point-in-cell params)))) |
79 | 88 |
|
80 | 89 |
|
81 | 90 | (facts "Greate grid of random points" |
|
166 | 175 | (defn neighbours |
167 | 176 | [& args] |
168 | 177 | (if (seq args) |
169 | | - (mapcat (fn [v] (map (fn [delta] (into [(+ (first args) delta)] v)) [-1 0 1])) (apply neighbours (rest args)) ) |
| 178 | + (mapcat (fn [v] (map (fn [delta] (into [(+ (first args) delta)] v)) [-1 0 1])) |
| 179 | + (apply neighbours (rest args)) ) |
170 | 180 | [[]])) |
171 | 181 |
|
172 | 182 |
|
|
180 | 190 | [{:keys [size dimensions] :as params}] |
181 | 191 | (let [random-points (random-points params)] |
182 | 192 | (tensor/clone |
183 | | - (tensor/compute-tensor (repeat dimensions size) |
184 | | - (fn [& coords] |
185 | | - (let [center (map #(+ % 0.5) coords) |
186 | | - division (map (partial division-index params) center)] |
187 | | - (apply min |
188 | | - (for [neighbour (apply neighbours division)] |
189 | | - (mod-dist params (apply vec-n (reverse center)) |
190 | | - (apply wrap-get random-points neighbour)))))) |
191 | | - :double)))) |
| 193 | + (tensor/compute-tensor |
| 194 | + (repeat dimensions size) |
| 195 | + (fn [& coords] |
| 196 | + (let [center (map #(+ % 0.5) coords) |
| 197 | + division (map (partial division-index params) center)] |
| 198 | + (apply min |
| 199 | + (for [neighbour (apply neighbours division)] |
| 200 | + (mod-dist params (apply vec-n (reverse center)) |
| 201 | + (apply wrap-get random-points neighbour)))))) |
| 202 | + :double)))) |
192 | 203 |
|
193 | 204 |
|
194 | 205 | (def worley (worley-noise (make-noise-params 256 8 2))) |
195 | 206 |
|
196 | | -(def worley-norm (dfn/* (/ 255 (- (dfn/reduce-max worley) (dfn/reduce-min worley))) (dfn/- (dfn/reduce-max worley) worley))) |
| 207 | +(def worley-norm |
| 208 | + (dfn/* (/ 255 (- (dfn/reduce-max worley) (dfn/reduce-min worley))) |
| 209 | + (dfn/- (dfn/reduce-max worley) worley))) |
197 | 210 |
|
198 | 211 | (bufimg/tensor->image worley-norm) |
199 | 212 |
|
|
218 | 231 |
|
219 | 232 | (facts "Create unit vector with random direction" |
220 | 233 | (with-redefs [rand (constantly 0.5)] |
221 | | - (random-gradient 0 0) => (roughly-vec (vec2 (- (sqrt 0.5)) (- (sqrt 0.5))) 1e-6)) |
| 234 | + (random-gradient 0 0) |
| 235 | + => (roughly-vec (vec2 (- (sqrt 0.5)) (- (sqrt 0.5))) 1e-6)) |
222 | 236 | (with-redefs [rand (constantly 1.5)] |
223 | | - (random-gradient 0 0) => (roughly-vec (vec2 (sqrt 0.5) (sqrt 0.5)) 1e-6))) |
| 237 | + (random-gradient 0 0) |
| 238 | + => (roughly-vec (vec2 (sqrt 0.5) (sqrt 0.5)) 1e-6))) |
224 | 239 |
|
225 | 240 |
|
226 | 241 | (defn random-gradients |
|
230 | 245 |
|
231 | 246 | (facts "Random gradients" |
232 | 247 | (with-redefs [rand (constantly 1.5)] |
233 | | - (dtype/shape (random-gradients {:divisions 8 :dimensions 2})) => [8 8] |
234 | | - ((random-gradients {:divisions 8 :dimensions 2}) 0 0) => (roughly-vec (vec2 (sqrt 0.5) (sqrt 0.5)) 1e-6) |
| 248 | + (dtype/shape (random-gradients {:divisions 8 :dimensions 2})) |
| 249 | + => [8 8] |
| 250 | + ((random-gradients {:divisions 8 :dimensions 2}) 0 0) |
| 251 | + => (roughly-vec (vec2 (sqrt 0.5) (sqrt 0.5)) 1e-6) |
235 | 252 | (dtype/shape (random-gradients {:divisions 8 :dimensions 3})) => [8 8 8] |
236 | | - ((random-gradients {:divisions 8 :dimensions 3}) 0 0 0) => (vec3 (/ 1 (sqrt 3)) (/ 1 (sqrt 3)) (/ 1 (sqrt 3))))) |
| 253 | + ((random-gradients {:divisions 8 :dimensions 3}) 0 0 0) |
| 254 | + => (vec3 (/ 1 (sqrt 3)) (/ 1 (sqrt 3)) (/ 1 (sqrt 3))))) |
237 | 255 |
|
238 | 256 |
|
239 | 257 | (let [gradients (tensor/reshape (random-gradients (make-noise-params 256 8 2)) [(* 8 8)]) |
240 | 258 | points (tensor/reshape (tensor/compute-tensor [8 8] (fn [y x] (vec2 x y))) [(* 8 8)]) |
241 | | - scatter (tc/dataset {:x (mapcat (fn [point gradient] [(point 0) (+ (point 0) (* 0.5 (gradient 0))) nil]) points gradients) |
242 | | - :y (mapcat (fn [point gradient] [(point 1) (+ (point 1) (* 0.5 (gradient 1))) nil]) points gradients)})] |
| 259 | + scatter (tc/dataset {:x (mapcat (fn [point gradient] |
| 260 | + [(point 0) (+ (point 0) (* 0.5 (gradient 0))) nil]) |
| 261 | + points gradients) |
| 262 | + :y (mapcat (fn [point gradient] |
| 263 | + [(point 1) (+ (point 1) (* 0.5 (gradient 1))) nil]) |
| 264 | + points gradients)})] |
243 | 265 | (-> scatter |
244 | 266 | (plotly/base {:=title "Random gradients" :=mode "lines"}) |
245 | 267 | (plotly/layer-point {:=x :x :=y :y}))) |
|
270 | 292 | (defn corner-vectors |
271 | 293 | [{:keys [dimensions] :as params} point] |
272 | 294 | (let [cell-pos (cell-pos params point)] |
273 | | - (tensor/compute-tensor (repeat dimensions 2) (fn [& args] (sub cell-pos (apply vec-n (reverse args))))))) |
| 295 | + (tensor/compute-tensor |
| 296 | + (repeat dimensions 2) |
| 297 | + (fn [& args] (sub cell-pos (apply vec-n (reverse args))))))) |
274 | 298 |
|
275 | 299 |
|
276 | 300 | (facts "Compute relative vectors from cell corners to point in cell" |
|
286 | 310 | (defn corner-gradients |
287 | 311 | [{:keys [dimensions] :as params} gradients point] |
288 | 312 | (let [division (map (partial division-index params) point)] |
289 | | - (tensor/compute-tensor (repeat dimensions 2) (fn [& coords] (apply wrap-get gradients (map + (reverse division) coords)))))) |
| 313 | + (tensor/compute-tensor |
| 314 | + (repeat dimensions 2) |
| 315 | + (fn [& coords] (apply wrap-get gradients (map + (reverse division) coords)))))) |
290 | 316 |
|
291 | 317 |
|
292 | 318 | (facts "Get 2x2 tensor of gradients from a larger tensor using wrap around" |
293 | 319 | (let [gradients2 (tensor/compute-tensor [4 6] (fn [y x] (vec2 x y))) |
294 | 320 | gradients3 (tensor/compute-tensor [4 6 8] (fn [z y x] (vec3 x y z))) ] |
295 | | - ((corner-gradients {:cellsize 4 :dimensions 2} gradients2 (vec2 9 6)) 0 0) => (vec2 2 1) |
296 | | - ((corner-gradients {:cellsize 4 :dimensions 2} gradients2 (vec2 9 6)) 0 1) => (vec2 3 1) |
297 | | - ((corner-gradients {:cellsize 4 :dimensions 2} gradients2 (vec2 9 6)) 1 0) => (vec2 2 2) |
298 | | - ((corner-gradients {:cellsize 4 :dimensions 2} gradients2 (vec2 9 6)) 1 1) => (vec2 3 2) |
299 | | - ((corner-gradients {:cellsize 4 :dimensions 2} gradients2 (vec2 23 15)) 1 1) => (vec2 0 0) |
300 | | - ((corner-gradients {:cellsize 4 :dimensions 3} gradients3 (vec3 9 6 3)) 0 0 0) => (vec3 2 1 0))) |
| 321 | + ((corner-gradients {:cellsize 4 :dimensions 2} gradients2 (vec2 9 6)) 0 0) |
| 322 | + => (vec2 2 1) |
| 323 | + ((corner-gradients {:cellsize 4 :dimensions 2} gradients2 (vec2 9 6)) 0 1) |
| 324 | + => (vec2 3 1) |
| 325 | + ((corner-gradients {:cellsize 4 :dimensions 2} gradients2 (vec2 9 6)) 1 0) |
| 326 | + => (vec2 2 2) |
| 327 | + ((corner-gradients {:cellsize 4 :dimensions 2} gradients2 (vec2 9 6)) 1 1) |
| 328 | + => (vec2 3 2) |
| 329 | + ((corner-gradients {:cellsize 4 :dimensions 2} gradients2 (vec2 23 15)) 1 1) |
| 330 | + => (vec2 0 0) |
| 331 | + ((corner-gradients {:cellsize 4 :dimensions 3} gradients3 (vec3 9 6 3)) 0 0 0) |
| 332 | + => (vec3 2 1 0))) |
301 | 333 |
|
302 | 334 |
|
303 | 335 | (defn influence-values |
304 | 336 | [gradients vectors] |
305 | | - (tensor/compute-tensor (repeat (count (dtype/shape gradients)) 2) |
306 | | - (fn [& args] (dot (apply gradients args) (apply vectors args))) :double)) |
| 337 | + (tensor/compute-tensor |
| 338 | + (repeat (count (dtype/shape gradients)) 2) |
| 339 | + (fn [& args] (dot (apply gradients args) (apply vectors args))) |
| 340 | + :double)) |
307 | 341 |
|
308 | 342 |
|
309 | 343 | (facts "Compute influence values from corner vectors and gradients" |
|
333 | 367 | (ease-curve 1.0) => 1.0) |
334 | 368 |
|
335 | 369 |
|
336 | | -(-> (tc/dataset {:t (range 0.0 1.025 0.025) :ease (map ease-curve (range 0.0 1.025 0.025))}) |
| 370 | +(-> (tc/dataset {:t (range 0.0 1.025 0.025) |
| 371 | + :ease (map ease-curve (range 0.0 1.025 0.025))}) |
337 | 372 | (plotly/base {:=title "Ease Curve"}) |
338 | 373 | (plotly/layer-line {:=x :t :=y :ease})) |
339 | 374 |
|
|
0 commit comments