Blender V5.0
noise.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009-2010 Sony Pictures Imageworks Inc., et al.
2 * All Rights Reserved. (BSD-3-Clause).
3 * SPDX-FileCopyrightText: 2011 Blender Authors (GPL-2.0-or-later).
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later AND BSD-3-Clause */
6
10
11#include <algorithm>
12#include <cfloat>
13#include <cmath>
14#include <cstdint>
15
16#include "BLI_math_base.h"
17#include "BLI_math_base.hh"
19#include "BLI_math_numbers.hh"
20#include "BLI_math_vector.hh"
21#include "BLI_noise.hh"
22#include "BLI_utildefines.h"
23
24/* Some noise functions integer overflow as part of expected operation. */
25#ifdef __SANITIZE_ADDRESS__
26/* CLANG also supports GNU extensions. */
27# if defined(__GNUC__) || defined(__clang__)
28# define ATTR_NO_SIGNED_INT_OVERFLOW [[gnu::no_sanitize("signed-integer-overflow")]]
29# else
30/* TODO: MSVC, others as needed. */
31# define ATTR_NO_SIGNED_INT_OVERFLOW
32# endif
33#else
34# define ATTR_NO_SIGNED_INT_OVERFLOW
35#endif
36
37namespace blender::noise {
38
39/* -------------------------------------------------------------------- */
44
45BLI_INLINE uint32_t hash_bit_rotate(uint32_t x, uint32_t k)
46{
47 return (x << k) | (x >> (32 - k));
48}
49
50BLI_INLINE void hash_bit_mix(uint32_t &a, uint32_t &b, uint32_t &c)
51{
52 a -= c;
53 a ^= hash_bit_rotate(c, 4);
54 c += b;
55 b -= a;
56 b ^= hash_bit_rotate(a, 6);
57 a += c;
58 c -= b;
59 c ^= hash_bit_rotate(b, 8);
60 b += a;
61 a -= c;
62 a ^= hash_bit_rotate(c, 16);
63 c += b;
64 b -= a;
65 b ^= hash_bit_rotate(a, 19);
66 a += c;
67 c -= b;
68 c ^= hash_bit_rotate(b, 4);
69 b += a;
70}
71
72BLI_INLINE void hash_bit_final(uint32_t &a, uint32_t &b, uint32_t &c)
73{
74 c ^= b;
75 c -= hash_bit_rotate(b, 14);
76 a ^= c;
77 a -= hash_bit_rotate(c, 11);
78 b ^= a;
79 b -= hash_bit_rotate(a, 25);
80 c ^= b;
81 c -= hash_bit_rotate(b, 16);
82 a ^= c;
83 a -= hash_bit_rotate(c, 4);
84 b ^= a;
85 b -= hash_bit_rotate(a, 14);
86 c ^= b;
87 c -= hash_bit_rotate(b, 24);
88}
89
90uint32_t hash(uint32_t kx)
91{
92 uint32_t a, b, c;
93 a = b = c = 0xdeadbeef + (1 << 2) + 13;
94
95 a += kx;
96 hash_bit_final(a, b, c);
97
98 return c;
99}
100
101uint32_t hash(uint32_t kx, uint32_t ky)
102{
103 uint32_t a, b, c;
104 a = b = c = 0xdeadbeef + (2 << 2) + 13;
105
106 b += ky;
107 a += kx;
108 hash_bit_final(a, b, c);
109
110 return c;
111}
112
113uint32_t hash(uint32_t kx, uint32_t ky, uint32_t kz)
114{
115 uint32_t a, b, c;
116 a = b = c = 0xdeadbeef + (3 << 2) + 13;
117
118 c += kz;
119 b += ky;
120 a += kx;
121 hash_bit_final(a, b, c);
122
123 return c;
124}
125
126uint32_t hash(uint32_t kx, uint32_t ky, uint32_t kz, uint32_t kw)
127{
128 uint32_t a, b, c;
129 a = b = c = 0xdeadbeef + (4 << 2) + 13;
130
131 a += kx;
132 b += ky;
133 c += kz;
134 hash_bit_mix(a, b, c);
135
136 a += kw;
137 hash_bit_final(a, b, c);
138
139 return c;
140}
141
142BLI_INLINE uint32_t float_as_uint(float f)
143{
144 union {
145 uint32_t i;
146 float f;
147 } u;
148 u.f = f;
149 return u.i;
150}
151
152/* PCG 2D, 3D and 4D hash functions,
153 * from "Hash Functions for GPU Rendering" JCGT 2020
154 * https://jcgt.org/published/0009/03/02/
155 *
156 * Slightly modified to only use signed integers,
157 * so that they can also be implemented in OSL. */
158
160static inline int2 hash_pcg2d_i(int2 v)
161{
162 v = v * int2(1664525) + int2(1013904223);
163 v.x += v.y * 1664525;
164 v.y += v.x * 1664525;
165 v = v ^ (v >> 16);
166 v.x += v.y * 1664525;
167 v.y += v.x * 1664525;
168 return v;
169}
170
172static inline int3 hash_pcg3d_i(int3 v)
173{
174 v = v * int3(1664525) + int3(1013904223);
175 v.x += v.y * v.z;
176 v.y += v.z * v.x;
177 v.z += v.x * v.y;
178 v = v ^ (v >> 16);
179 v.x += v.y * v.z;
180 v.y += v.z * v.x;
181 v.z += v.x * v.y;
182 return v;
183}
184
186static inline int4 hash_pcg4d_i(int4 v)
187{
188 v = v * int4(1664525) + int4(1013904223);
189 v.x += v.y * v.w;
190 v.y += v.z * v.x;
191 v.z += v.x * v.y;
192 v.w += v.y * v.z;
193 v = v ^ (v >> 16);
194 v.x += v.y * v.w;
195 v.y += v.z * v.x;
196 v.z += v.x * v.y;
197 v.w += v.y * v.z;
198 return v;
199}
200
201uint32_t hash_float(float kx)
202{
203 return hash(float_as_uint(kx));
204}
205
207{
208 return hash(float_as_uint(k.x), float_as_uint(k.y));
209}
210
212{
213 return hash(float_as_uint(k.x), float_as_uint(k.y), float_as_uint(k.z));
214}
215
217{
218 return hash(float_as_uint(k.x), float_as_uint(k.y), float_as_uint(k.z), float_as_uint(k.w));
219}
220
221uint32_t hash_float(const float4x4 &k)
222{
223 return hash(hash_float(k.x), hash_float(k.y), hash_float(k.z), hash_float(k.w));
224}
225
226/* Hashing a number of uint32_t into a float in the range [0, 1]. */
227
229{
230 return float(k) / float(0xFFFFFFFFu);
231}
232
233float hash_to_float(uint32_t kx)
234{
235 return uint_to_float_01(hash(kx));
236}
237
238float hash_to_float(uint32_t kx, uint32_t ky)
239{
240 return uint_to_float_01(hash(kx, ky));
241}
242
243float hash_to_float(uint32_t kx, uint32_t ky, uint32_t kz)
244{
245 return uint_to_float_01(hash(kx, ky, kz));
246}
247
248float hash_to_float(uint32_t kx, uint32_t ky, uint32_t kz, uint32_t kw)
249{
250 return uint_to_float_01(hash(kx, ky, kz, kw));
251}
252
253/* Hashing a number of floats into a float in the range [0, 1]. */
254
256{
257 return uint_to_float_01(hash_float(k));
258}
259
261{
262 return uint_to_float_01(hash_float(k));
263}
264
266{
267 return uint_to_float_01(hash_float(k));
268}
269
271{
272 return uint_to_float_01(hash_float(k));
273}
274
279
281{
282 return float2(hash_float_to_float(float3(k.x, k.y, k.z)),
283 hash_float_to_float(float3(k.z, k.x, k.y)));
284}
285
287{
288 return float2(hash_float_to_float(float4(k.x, k.y, k.z, k.w)),
289 hash_float_to_float(float4(k.z, k.x, k.w, k.y)));
290}
291
293{
294 return float3(hash_float_to_float(k),
296 hash_float_to_float(float2(k, 2.0)));
297}
298
300{
301 return float3(hash_float_to_float(k),
302 hash_float_to_float(float3(k.x, k.y, 1.0)),
303 hash_float_to_float(float3(k.x, k.y, 2.0)));
304}
305
307{
308 return float3(hash_float_to_float(k),
309 hash_float_to_float(float4(k.x, k.y, k.z, 1.0)),
310 hash_float_to_float(float4(k.x, k.y, k.z, 2.0)));
311}
312
314{
315 return float3(hash_float_to_float(k),
316 hash_float_to_float(float4(k.z, k.x, k.w, k.y)),
317 hash_float_to_float(float4(k.w, k.z, k.y, k.x)));
318}
319
321{
322 return float4(hash_float_to_float(k),
323 hash_float_to_float(float4(k.w, k.x, k.y, k.z)),
324 hash_float_to_float(float4(k.z, k.w, k.x, k.y)),
325 hash_float_to_float(float4(k.y, k.z, k.w, k.x)));
326}
327
328/* Hashing a number of integers into floats in [0..1] range. */
329
330static inline float int_to_float_01(int32_t k)
331{
332 return float(k & 0x7fffffff) * (1.0f / float(0x7fffffff));
333}
334
336{
337 int2 h = hash_pcg2d_i(k);
338 return float2(int_to_float_01(h.x), int_to_float_01(h.y));
339}
340
342{
343 int3 h = hash_pcg3d_i(k);
344 return float3(int_to_float_01(h.x), int_to_float_01(h.y), int_to_float_01(h.z));
345}
346
348{
349 int4 h = hash_pcg4d_i(k);
350 return float4(
352}
353
355{
356 return hash_int3_to_float3(int3(k.x, k.y, 0));
357}
358
360{
361 return hash_int4_to_float4(k).xyz();
362}
363
365
366/* -------------------------------------------------------------------- */
375
376/* Linear Interpolation. */
377template<typename T> T static mix(T v0, T v1, float x)
378{
379 return (1 - x) * v0 + x * v1;
380}
381
382/* Bilinear Interpolation:
383 *
384 * v2 v3
385 * @ + + + + @ y
386 * + + ^
387 * + + |
388 * + + |
389 * @ + + + + @ @------> x
390 * v0 v1
391 */
392BLI_INLINE float mix(float v0, float v1, float v2, float v3, float x, float y)
393{
394 float x1 = 1.0 - x;
395 return (1.0 - y) * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x);
396}
397
398/* Trilinear Interpolation:
399 *
400 * v6 v7
401 * @ + + + + + + @
402 * +\ +\
403 * + \ + \
404 * + \ + \
405 * + \ v4 + \ v5
406 * + @ + + + +++ + @ z
407 * + + + + y ^
408 * v2 @ + +++ + + + @ v3 + \ |
409 * \ + \ + \ |
410 * \ + \ + \|
411 * \ + \ + +---------> x
412 * \+ \+
413 * @ + + + + + + @
414 * v0 v1
415 */
416BLI_INLINE float mix(float v0,
417 float v1,
418 float v2,
419 float v3,
420 float v4,
421 float v5,
422 float v6,
423 float v7,
424 float x,
425 float y,
426 float z)
427{
428 float x1 = 1.0 - x;
429 float y1 = 1.0 - y;
430 float z1 = 1.0 - z;
431 return z1 * (y1 * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x)) +
432 z * (y1 * (v4 * x1 + v5 * x) + y * (v6 * x1 + v7 * x));
433}
434
435/* Quadrilinear Interpolation. */
436BLI_INLINE float mix(float v0,
437 float v1,
438 float v2,
439 float v3,
440 float v4,
441 float v5,
442 float v6,
443 float v7,
444 float v8,
445 float v9,
446 float v10,
447 float v11,
448 float v12,
449 float v13,
450 float v14,
451 float v15,
452 float x,
453 float y,
454 float z,
455 float w)
456{
457 return mix(mix(v0, v1, v2, v3, v4, v5, v6, v7, x, y, z),
458 mix(v8, v9, v10, v11, v12, v13, v14, v15, x, y, z),
459 w);
460}
461
462BLI_INLINE float fade(float t)
463{
464 return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
465}
466
467BLI_INLINE float negate_if(float value, uint32_t condition)
468{
469 return (condition != 0u) ? -value : value;
470}
471
472BLI_INLINE float noise_grad(uint32_t hash, float x)
473{
474 uint32_t h = hash & 15u;
475 float g = 1u + (h & 7u);
476 return negate_if(g, h & 8u) * x;
477}
478
479BLI_INLINE float noise_grad(uint32_t hash, float x, float y)
480{
481 uint32_t h = hash & 7u;
482 float u = h < 4u ? x : y;
483 float v = 2.0 * (h < 4u ? y : x);
484 return negate_if(u, h & 1u) + negate_if(v, h & 2u);
485}
486
487BLI_INLINE float noise_grad(uint32_t hash, float x, float y, float z)
488{
489 uint32_t h = hash & 15u;
490 float u = h < 8u ? x : y;
491 float vt = ELEM(h, 12u, 14u) ? x : z;
492 float v = h < 4u ? y : vt;
493 return negate_if(u, h & 1u) + negate_if(v, h & 2u);
494}
495
496BLI_INLINE float noise_grad(uint32_t hash, float x, float y, float z, float w)
497{
498 uint32_t h = hash & 31u;
499 float u = h < 24u ? x : y;
500 float v = h < 16u ? y : z;
501 float s = h < 8u ? z : w;
502 return negate_if(u, h & 1u) + negate_if(v, h & 2u) + negate_if(s, h & 4u);
503}
504
505BLI_INLINE float floor_fraction(float x, int &i)
506{
507 float x_floor = math::floor(x);
508 i = int(x_floor);
509 return x - x_floor;
510}
511
512BLI_INLINE float perlin_noise(float position)
513{
514 int X;
515
516 float fx = floor_fraction(position, X);
517
518 float u = fade(fx);
519
520 float r = mix(noise_grad(hash(X), fx), noise_grad(hash(X + 1), fx - 1.0), u);
521
522 return r;
523}
524
526{
527 int X, Y;
528
529 float fx = floor_fraction(position.x, X);
530 float fy = floor_fraction(position.y, Y);
531
532 float u = fade(fx);
533 float v = fade(fy);
534
535 float r = mix(noise_grad(hash(X, Y), fx, fy),
536 noise_grad(hash(X + 1, Y), fx - 1.0, fy),
537 noise_grad(hash(X, Y + 1), fx, fy - 1.0),
538 noise_grad(hash(X + 1, Y + 1), fx - 1.0, fy - 1.0),
539 u,
540 v);
541
542 return r;
543}
544
546{
547 int X, Y, Z;
548
549 float fx = floor_fraction(position.x, X);
550 float fy = floor_fraction(position.y, Y);
551 float fz = floor_fraction(position.z, Z);
552
553 float u = fade(fx);
554 float v = fade(fy);
555 float w = fade(fz);
556
557 float r = mix(noise_grad(hash(X, Y, Z), fx, fy, fz),
558 noise_grad(hash(X + 1, Y, Z), fx - 1, fy, fz),
559 noise_grad(hash(X, Y + 1, Z), fx, fy - 1, fz),
560 noise_grad(hash(X + 1, Y + 1, Z), fx - 1, fy - 1, fz),
561 noise_grad(hash(X, Y, Z + 1), fx, fy, fz - 1),
562 noise_grad(hash(X + 1, Y, Z + 1), fx - 1, fy, fz - 1),
563 noise_grad(hash(X, Y + 1, Z + 1), fx, fy - 1, fz - 1),
564 noise_grad(hash(X + 1, Y + 1, Z + 1), fx - 1, fy - 1, fz - 1),
565 u,
566 v,
567 w);
568
569 return r;
570}
571
573{
574 int X, Y, Z, W;
575
576 float fx = floor_fraction(position.x, X);
577 float fy = floor_fraction(position.y, Y);
578 float fz = floor_fraction(position.z, Z);
579 float fw = floor_fraction(position.w, W);
580
581 float u = fade(fx);
582 float v = fade(fy);
583 float t = fade(fz);
584 float s = fade(fw);
585
586 float r = mix(
587 noise_grad(hash(X, Y, Z, W), fx, fy, fz, fw),
588 noise_grad(hash(X + 1, Y, Z, W), fx - 1.0, fy, fz, fw),
589 noise_grad(hash(X, Y + 1, Z, W), fx, fy - 1.0, fz, fw),
590 noise_grad(hash(X + 1, Y + 1, Z, W), fx - 1.0, fy - 1.0, fz, fw),
591 noise_grad(hash(X, Y, Z + 1, W), fx, fy, fz - 1.0, fw),
592 noise_grad(hash(X + 1, Y, Z + 1, W), fx - 1.0, fy, fz - 1.0, fw),
593 noise_grad(hash(X, Y + 1, Z + 1, W), fx, fy - 1.0, fz - 1.0, fw),
594 noise_grad(hash(X + 1, Y + 1, Z + 1, W), fx - 1.0, fy - 1.0, fz - 1.0, fw),
595 noise_grad(hash(X, Y, Z, W + 1), fx, fy, fz, fw - 1.0),
596 noise_grad(hash(X + 1, Y, Z, W + 1), fx - 1.0, fy, fz, fw - 1.0),
597 noise_grad(hash(X, Y + 1, Z, W + 1), fx, fy - 1.0, fz, fw - 1.0),
598 noise_grad(hash(X + 1, Y + 1, Z, W + 1), fx - 1.0, fy - 1.0, fz, fw - 1.0),
599 noise_grad(hash(X, Y, Z + 1, W + 1), fx, fy, fz - 1.0, fw - 1.0),
600 noise_grad(hash(X + 1, Y, Z + 1, W + 1), fx - 1.0, fy, fz - 1.0, fw - 1.0),
601 noise_grad(hash(X, Y + 1, Z + 1, W + 1), fx, fy - 1.0, fz - 1.0, fw - 1.0),
602 noise_grad(hash(X + 1, Y + 1, Z + 1, W + 1), fx - 1.0, fy - 1.0, fz - 1.0, fw - 1.0),
603 u,
604 v,
605 t,
606 s);
607
608 return r;
609}
610
611/* Signed versions of perlin noise in the range [-1, 1]. The scale values were computed
612 * experimentally by the OSL developers to remap the noise output to the correct range. */
613
614float perlin_signed(float position)
615{
616 float precision_correction = 0.5f * float(math::abs(position) >= 1000000.0f);
617 /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point
618 * representation issues. */
619 position = math::mod(position, 100000.0f) + precision_correction;
620
621 return perlin_noise(position) * 0.2500f;
622}
623
624float perlin_signed(float2 position)
625{
626 float2 precision_correction = 0.5f * float2(float(math::abs(position.x) >= 1000000.0f),
627 float(math::abs(position.y) >= 1000000.0f));
628 /* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point
629 * representation issues. This causes discontinuities every 100000.0f, however at such scales
630 * this usually shouldn't be noticeable. */
631 position = math::mod(position, 100000.0f) + precision_correction;
632
633 return perlin_noise(position) * 0.6616f;
634}
635
636float perlin_signed(float3 position)
637{
638 float3 precision_correction = 0.5f * float3(float(math::abs(position.x) >= 1000000.0f),
639 float(math::abs(position.y) >= 1000000.0f),
640 float(math::abs(position.z) >= 1000000.0f));
641 /* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point
642 * representation issues. This causes discontinuities every 100000.0f, however at such scales
643 * this usually shouldn't be noticeable. */
644 position = math::mod(position, 100000.0f) + precision_correction;
645
646 return perlin_noise(position) * 0.9820f;
647}
648
649float perlin_signed(float4 position)
650{
651 float4 precision_correction = 0.5f * float4(float(math::abs(position.x) >= 1000000.0f),
652 float(math::abs(position.y) >= 1000000.0f),
653 float(math::abs(position.z) >= 1000000.0f),
654 float(math::abs(position.w) >= 1000000.0f));
655 /* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point
656 * representation issues. This causes discontinuities every 100000.0f, however at such scales
657 * this usually shouldn't be noticeable. */
658 position = math::mod(position, 100000.0f) + precision_correction;
659
660 return perlin_noise(position) * 0.8344f;
661}
662
663/* Positive versions of perlin noise in the range [0, 1]. */
664
665float perlin(float position)
666{
667 return perlin_signed(position) / 2.0f + 0.5f;
668}
669
670float perlin(float2 position)
671{
672 return perlin_signed(position) / 2.0f + 0.5f;
673}
674
675float perlin(float3 position)
676{
677 return perlin_signed(position) / 2.0f + 0.5f;
678}
679
680float perlin(float4 position)
681{
682 return perlin_signed(position) / 2.0f + 0.5f;
683}
684
685/* Fractal perlin noise. */
686
687/* fBM = Fractal Brownian Motion */
688template<typename T>
689#if defined(_MSC_VER) && _MSC_VER >= 1930
690/* The MSVC 2022 optimizer generates bad code for perlin_fractal_distorted when perlin_fbm gets
691 * inlined leading to incorrect results and failing tests that rely on perlin noise. For now just
692 * disable inlining for this function until we can get the compiler fixed. */
694#endif
695 float
697 const float detail,
698 const float roughness,
699 const float lacunarity,
700 const bool normalize)
701{
702 float fscale = 1.0f;
703 float amp = 1.0f;
704 float maxamp = 0.0f;
705 float sum = 0.0f;
706
707 for (int i = 0; i <= int(detail); i++) {
708 float t = perlin_signed(fscale * p);
709 sum += t * amp;
710 maxamp += amp;
711 amp *= roughness;
712 fscale *= lacunarity;
713 }
714 float rmd = detail - std::floor(detail);
715 if (rmd != 0.0f) {
716 float t = perlin_signed(fscale * p);
717 float sum2 = sum + t * amp;
718 return normalize ? mix(0.5f * sum / maxamp + 0.5f, 0.5f * sum2 / (maxamp + amp) + 0.5f, rmd) :
719 mix(sum, sum2, rmd);
720 }
721 return normalize ? 0.5f * sum / maxamp + 0.5f : sum;
722}
723
724/* Explicit instantiation for Wave Texture. */
725template float perlin_fbm<float3>(float3 p,
726 const float detail,
727 const float roughness,
728 const float lacunarity,
729 const bool normalize);
730
731template float perlin_fbm<float2>(float2 p,
732 const float detail,
733 const float roughness,
734 const float lacunarity,
735 const bool normalize);
736
737template<typename T>
738float perlin_multi_fractal(T p, const float detail, const float roughness, const float lacunarity)
739{
740 float value = 1.0f;
741 float pwr = 1.0f;
742
743 for (int i = 0; i <= int(detail); i++) {
744 value *= (pwr * perlin_signed(p) + 1.0f);
745 pwr *= roughness;
746 p *= lacunarity;
747 }
748
749 const float rmd = detail - floorf(detail);
750 if (rmd != 0.0f) {
751 value *= (rmd * pwr * perlin_signed(p) + 1.0f); /* correct? */
752 }
753
754 return value;
755}
756
757template<typename T>
759 T p, const float detail, const float roughness, const float lacunarity, const float offset)
760{
761 float pwr = roughness;
762
763 /* First unscaled octave of function; later octaves are scaled. */
764 float value = offset + perlin_signed(p);
765 p *= lacunarity;
766
767 for (int i = 1; i <= int(detail); i++) {
768 float increment = (perlin_signed(p) + offset) * pwr * value;
769 value += increment;
770 pwr *= roughness;
771 p *= lacunarity;
772 }
773
774 const float rmd = detail - floorf(detail);
775 if (rmd != 0.0f) {
776 float increment = (perlin_signed(p) + offset) * pwr * value;
777 value += rmd * increment;
778 }
779
780 return value;
781}
782
783template<typename T>
785 const float detail,
786 const float roughness,
787 const float lacunarity,
788 const float offset,
789 const float gain)
790{
791 float pwr = 1.0f;
792 float value = 0.0f;
793 float weight = 1.0f;
794
795 for (int i = 0; (weight > 0.001f) && (i <= int(detail)); i++) {
796 weight = std::min(weight, 1.0f);
797
798 float signal = (perlin_signed(p) + offset) * pwr;
799 pwr *= roughness;
800 value += weight * signal;
801 weight *= gain * signal;
802 p *= lacunarity;
803 }
804
805 const float rmd = detail - floorf(detail);
806 if ((rmd != 0.0f) && (weight > 0.001f)) {
807 weight = std::min(weight, 1.0f);
808 float signal = (perlin_signed(p) + offset) * pwr;
809 value += rmd * weight * signal;
810 }
811
812 return value;
813}
814
815template<typename T>
817 const float detail,
818 const float roughness,
819 const float lacunarity,
820 const float offset,
821 const float gain)
822{
823 float pwr = roughness;
824
825 float signal = offset - std::abs(perlin_signed(p));
826 signal *= signal;
827 float value = signal;
828 float weight = 1.0f;
829
830 for (int i = 1; i <= int(detail); i++) {
831 p *= lacunarity;
832 weight = std::clamp(signal * gain, 0.0f, 1.0f);
833 signal = offset - std::abs(perlin_signed(p));
834 signal *= signal;
835 signal *= weight;
836 value += signal * pwr;
837 pwr *= roughness;
838 }
839
840 return value;
841}
842
843enum {
849};
850
851template<typename T>
853 float detail,
854 float roughness,
855 float lacunarity,
856 float offset,
857 float gain,
858 int type,
859 bool normalize)
860{
861 switch (type) {
863 return perlin_multi_fractal<T>(p, detail, roughness, lacunarity);
864 }
866 return perlin_fbm<T>(p, detail, roughness, lacunarity, normalize);
867 }
869 return perlin_hybrid_multi_fractal<T>(p, detail, roughness, lacunarity, offset, gain);
870 }
872 return perlin_ridged_multi_fractal<T>(p, detail, roughness, lacunarity, offset, gain);
873 }
875 return perlin_hetero_terrain<T>(p, detail, roughness, lacunarity, offset);
876 }
877 default: {
878 return 0.0;
879 }
880 }
881}
882
883/* The following offset functions generate random offsets to be added to
884 * positions to act as a seed since the noise functions don't have seed values.
885 * The offset's components are in the range [100, 200], not too high to cause
886 * bad precision and not too small to be noticeable. We use float seed because
887 * OSL only supports float hashes and we need to maintain compatibility with it.
888 */
889
891{
892 return 100.0f + hash_float_to_float(seed) * 100.0f;
893}
894
896{
897 return float2(100.0f + hash_float_to_float(float2(seed, 0.0f)) * 100.0f,
898 100.0f + hash_float_to_float(float2(seed, 1.0f)) * 100.0f);
899}
900
902{
903 return float3(100.0f + hash_float_to_float(float2(seed, 0.0f)) * 100.0f,
904 100.0f + hash_float_to_float(float2(seed, 1.0f)) * 100.0f,
905 100.0f + hash_float_to_float(float2(seed, 2.0f)) * 100.0f);
906}
907
909{
910 return float4(100.0f + hash_float_to_float(float2(seed, 0.0f)) * 100.0f,
911 100.0f + hash_float_to_float(float2(seed, 1.0f)) * 100.0f,
912 100.0f + hash_float_to_float(float2(seed, 2.0f)) * 100.0f,
913 100.0f + hash_float_to_float(float2(seed, 3.0f)) * 100.0f);
914}
915
916/* Perlin noises to be added to the position to distort other noises. */
917
918BLI_INLINE float perlin_distortion(float position, float strength)
919{
920 return perlin_signed(position + random_float_offset(0.0)) * strength;
921}
922
923BLI_INLINE float2 perlin_distortion(float2 position, float strength)
924{
925 return float2(perlin_signed(position + random_float2_offset(0.0f)) * strength,
926 perlin_signed(position + random_float2_offset(1.0f)) * strength);
927}
928
929BLI_INLINE float3 perlin_distortion(float3 position, float strength)
930{
931 return float3(perlin_signed(position + random_float3_offset(0.0f)) * strength,
932 perlin_signed(position + random_float3_offset(1.0f)) * strength,
933 perlin_signed(position + random_float3_offset(2.0f)) * strength);
934}
935
936BLI_INLINE float4 perlin_distortion(float4 position, float strength)
937{
938 return float4(perlin_signed(position + random_float4_offset(0.0f)) * strength,
939 perlin_signed(position + random_float4_offset(1.0f)) * strength,
940 perlin_signed(position + random_float4_offset(2.0f)) * strength,
941 perlin_signed(position + random_float4_offset(3.0f)) * strength);
942}
943
944/* Distorted fractal perlin noise. */
945
946template<typename T>
948 float detail,
949 float roughness,
950 float lacunarity,
951 float offset,
952 float gain,
953 float distortion,
954 int type,
955 bool normalize)
956{
957 position += perlin_distortion(position, distortion);
958 return perlin_select<T>(position, detail, roughness, lacunarity, offset, gain, type, normalize);
959}
960
961template float perlin_fractal_distorted<float>(float position,
962 float detail,
963 float roughness,
964 float lacunarity,
965 float offset,
966 float gain,
967 float distortion,
968 int type,
969 bool normalize);
971 float detail,
972 float roughness,
973 float lacunarity,
974 float offset,
975 float gain,
976 float distortion,
977 int type,
978 bool normalize);
980 float detail,
981 float roughness,
982 float lacunarity,
983 float offset,
984 float gain,
985 float distortion,
986 int type,
987 bool normalize);
989 float detail,
990 float roughness,
991 float lacunarity,
992 float offset,
993 float gain,
994 float distortion,
995 int type,
996 bool normalize);
997
998/* Distorted fractal perlin noise that outputs a float3. The arbitrary seeds are for
999 * compatibility with shading functions. */
1000
1002 float detail,
1003 float roughness,
1004 float lacunarity,
1005 float offset,
1006 float gain,
1007 float distortion,
1008 int type,
1009 bool normalize)
1010{
1011 position += perlin_distortion(position, distortion);
1012 return float3(
1013 perlin_select<float>(position, detail, roughness, lacunarity, offset, gain, type, normalize),
1015 detail,
1016 roughness,
1017 lacunarity,
1018 offset,
1019 gain,
1020 type,
1021 normalize),
1023 detail,
1024 roughness,
1025 lacunarity,
1026 offset,
1027 gain,
1028 type,
1029 normalize));
1030}
1031
1033 float detail,
1034 float roughness,
1035 float lacunarity,
1036 float offset,
1037 float gain,
1038 float distortion,
1039 int type,
1040 bool normalize)
1041{
1042 position += perlin_distortion(position, distortion);
1044 position, detail, roughness, lacunarity, offset, gain, type, normalize),
1046 detail,
1047 roughness,
1048 lacunarity,
1049 offset,
1050 gain,
1051 type,
1052 normalize),
1054 detail,
1055 roughness,
1056 lacunarity,
1057 offset,
1058 gain,
1059 type,
1060 normalize));
1061}
1062
1064 float detail,
1065 float roughness,
1066 float lacunarity,
1067 float offset,
1068 float gain,
1069 float distortion,
1070 int type,
1071 bool normalize)
1072{
1073 position += perlin_distortion(position, distortion);
1075 position, detail, roughness, lacunarity, offset, gain, type, normalize),
1077 detail,
1078 roughness,
1079 lacunarity,
1080 offset,
1081 gain,
1082 type,
1083 normalize),
1085 detail,
1086 roughness,
1087 lacunarity,
1088 offset,
1089 gain,
1090 type,
1091 normalize));
1092}
1093
1095 float detail,
1096 float roughness,
1097 float lacunarity,
1098 float offset,
1099 float gain,
1100 float distortion,
1101 int type,
1102 bool normalize)
1103{
1104 position += perlin_distortion(position, distortion);
1106 position, detail, roughness, lacunarity, offset, gain, type, normalize),
1108 detail,
1109 roughness,
1110 lacunarity,
1111 offset,
1112 gain,
1113 type,
1114 normalize),
1116 detail,
1117 roughness,
1118 lacunarity,
1119 offset,
1120 gain,
1121 type,
1122 normalize));
1123}
1124
1126
1127/* -------------------------------------------------------------------- */
1146
1147/* Ensure to align with DNA. */
1148
1149enum {
1154};
1155
1156enum {
1162};
1163
1164/* ***** Distances ***** */
1165
1166float voronoi_distance(const float a, const float b)
1167{
1168 return std::abs(b - a);
1169}
1170
1172{
1173 switch (params.metric) {
1175 return math::distance(a, b);
1177 return std::abs(a.x - b.x) + std::abs(a.y - b.y);
1179 return std::max(std::abs(a.x - b.x), std::abs(a.y - b.y));
1181 return std::pow(std::pow(std::abs(a.x - b.x), params.exponent) +
1182 std::pow(std::abs(a.y - b.y), params.exponent),
1183 1.0f / params.exponent);
1184 default:
1186 break;
1187 }
1188 return 0.0f;
1189}
1190
1192{
1193 switch (params.metric) {
1195 return math::distance(a, b);
1197 return std::abs(a.x - b.x) + std::abs(a.y - b.y) + std::abs(a.z - b.z);
1199 return std::max({std::abs(a.x - b.x), std::abs(a.y - b.y), std::abs(a.z - b.z)});
1201 return std::pow(std::pow(std::abs(a.x - b.x), params.exponent) +
1202 std::pow(std::abs(a.y - b.y), params.exponent) +
1203 std::pow(std::abs(a.z - b.z), params.exponent),
1204 1.0f / params.exponent);
1205 default:
1207 break;
1208 }
1209 return 0.0f;
1210}
1211
1213{
1214 switch (params.metric) {
1216 return math::distance(a, b);
1218 return std::abs(a.x - b.x) + std::abs(a.y - b.y) + std::abs(a.z - b.z) + std::abs(a.w - b.w);
1220 return std::max(
1221 {std::abs(a.x - b.x), std::abs(a.y - b.y), std::abs(a.z - b.z), std::abs(a.w - b.w)});
1223 return std::pow(std::pow(std::abs(a.x - b.x), params.exponent) +
1224 std::pow(std::abs(a.y - b.y), params.exponent) +
1225 std::pow(std::abs(a.z - b.z), params.exponent) +
1226 std::pow(std::abs(a.w - b.w), params.exponent),
1227 1.0f / params.exponent);
1228 default:
1230 break;
1231 }
1232 return 0.0f;
1233}
1234
1235/* Possibly cheaper/faster version of Voronoi distance, in a way that does not change
1236 * logic of "which distance is the closest?". */
1237template<typename T>
1238static float voronoi_distance_bound(const T a, const T b, const VoronoiParams &params)
1239{
1240 if (params.metric == NOISE_SHD_VORONOI_EUCLIDEAN) {
1241 return math::length_squared(a - b);
1242 }
1243 return voronoi_distance(a, b, params);
1244}
1245
1246/* **** 1D Voronoi **** */
1247
1248float4 voronoi_position(const float coord)
1249{
1250 return {0.0f, 0.0f, 0.0f, coord};
1251}
1252
1254{
1255 float cellPosition = floorf(coord);
1256 float localPosition = coord - cellPosition;
1257
1258 float minDistance = FLT_MAX;
1259 float targetOffset = 0.0f;
1260 float targetPosition = 0.0f;
1261 for (int i = -1; i <= 1; i++) {
1262 float cellOffset = i;
1263 float pointPosition = cellOffset +
1264 hash_float_to_float(cellPosition + cellOffset) * params.randomness;
1265 float distanceToPoint = voronoi_distance(pointPosition, localPosition);
1266 if (distanceToPoint < minDistance) {
1267 targetOffset = cellOffset;
1268 minDistance = distanceToPoint;
1269 targetPosition = pointPosition;
1270 }
1271 }
1272
1273 VoronoiOutput octave;
1274 octave.distance = minDistance;
1275 octave.color = hash_float_to_float3(cellPosition + targetOffset);
1276 octave.position = voronoi_position(targetPosition + cellPosition);
1277 return octave;
1278}
1279
1281 const float coord,
1282 const bool calc_color)
1283{
1284 float cellPosition = floorf(coord);
1285 float localPosition = coord - cellPosition;
1286
1287 float smoothDistance = 0.0f;
1288 float smoothPosition = 0.0f;
1289 float3 smoothColor = {0.0f, 0.0f, 0.0f};
1290 float h = -1.0f;
1291 for (int i = -2; i <= 2; i++) {
1292 float cellOffset = i;
1293 float pointPosition = cellOffset +
1294 hash_float_to_float(cellPosition + cellOffset) * params.randomness;
1295 float distanceToPoint = voronoi_distance(pointPosition, localPosition);
1296 h = h == -1.0f ?
1297 1.0f :
1298 smoothstep(
1299 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / params.smoothness);
1300 float correctionFactor = params.smoothness * h * (1.0f - h);
1301 smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
1302 correctionFactor /= 1.0f + 3.0f * params.smoothness;
1303 float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
1304 if (calc_color) {
1305 /* Only compute Color output if necessary, as it is very expensive. */
1306 smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
1307 }
1308 smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
1309 }
1310
1311 VoronoiOutput octave;
1312 octave.distance = smoothDistance;
1313 octave.color = smoothColor;
1314 octave.position = voronoi_position(cellPosition + smoothPosition);
1315 return octave;
1316}
1317
1319{
1320 float cellPosition = floorf(coord);
1321 float localPosition = coord - cellPosition;
1322
1323 float distanceF1 = FLT_MAX;
1324 float distanceF2 = FLT_MAX;
1325 float offsetF1 = 0.0f;
1326 float positionF1 = 0.0f;
1327 float offsetF2 = 0.0f;
1328 float positionF2 = 0.0f;
1329 for (int i = -1; i <= 1; i++) {
1330 float cellOffset = i;
1331 float pointPosition = cellOffset +
1332 hash_float_to_float(cellPosition + cellOffset) * params.randomness;
1333 float distanceToPoint = voronoi_distance(pointPosition, localPosition);
1334 if (distanceToPoint < distanceF1) {
1335 distanceF2 = distanceF1;
1336 distanceF1 = distanceToPoint;
1337 offsetF2 = offsetF1;
1338 offsetF1 = cellOffset;
1339 positionF2 = positionF1;
1340 positionF1 = pointPosition;
1341 }
1342 else if (distanceToPoint < distanceF2) {
1343 distanceF2 = distanceToPoint;
1344 offsetF2 = cellOffset;
1345 positionF2 = pointPosition;
1346 }
1347 }
1348
1349 VoronoiOutput octave;
1350 octave.distance = distanceF2;
1351 octave.color = hash_float_to_float3(cellPosition + offsetF2);
1352 octave.position = voronoi_position(positionF2 + cellPosition);
1353 return octave;
1354}
1355
1356float voronoi_distance_to_edge(const VoronoiParams &params, const float coord)
1357{
1358 float cellPosition = floorf(coord);
1359 float localPosition = coord - cellPosition;
1360
1361 float midPointPosition = hash_float_to_float(cellPosition) * params.randomness;
1362 float leftPointPosition = -1.0f + hash_float_to_float(cellPosition - 1.0f) * params.randomness;
1363 float rightPointPosition = 1.0f + hash_float_to_float(cellPosition + 1.0f) * params.randomness;
1364 float distanceToMidLeft = fabsf((midPointPosition + leftPointPosition) / 2.0f - localPosition);
1365 float distanceToMidRight = fabsf((midPointPosition + rightPointPosition) / 2.0f - localPosition);
1366
1367 return math::min(distanceToMidLeft, distanceToMidRight);
1368}
1369
1370float voronoi_n_sphere_radius(const VoronoiParams &params, const float coord)
1371{
1372 float cellPosition = floorf(coord);
1373 float localPosition = coord - cellPosition;
1374
1375 float closestPoint = 0.0f;
1376 float closestPointOffset = 0.0f;
1377 float minDistance = FLT_MAX;
1378 for (int i = -1; i <= 1; i++) {
1379 float cellOffset = i;
1380 float pointPosition = cellOffset +
1381 hash_float_to_float(cellPosition + cellOffset) * params.randomness;
1382 float distanceToPoint = fabsf(pointPosition - localPosition);
1383 if (distanceToPoint < minDistance) {
1384 minDistance = distanceToPoint;
1385 closestPoint = pointPosition;
1386 closestPointOffset = cellOffset;
1387 }
1388 }
1389
1390 minDistance = FLT_MAX;
1391 float closestPointToClosestPoint = 0.0f;
1392 for (int i = -1; i <= 1; i++) {
1393 if (i == 0) {
1394 continue;
1395 }
1396 float cellOffset = i + closestPointOffset;
1397 float pointPosition = cellOffset +
1398 hash_float_to_float(cellPosition + cellOffset) * params.randomness;
1399 float distanceToPoint = fabsf(closestPoint - pointPosition);
1400 if (distanceToPoint < minDistance) {
1401 minDistance = distanceToPoint;
1402 closestPointToClosestPoint = pointPosition;
1403 }
1404 }
1405
1406 return fabsf(closestPointToClosestPoint - closestPoint) / 2.0f;
1407}
1408
1409/* **** 2D Voronoi **** */
1410
1412{
1413 return {coord.x, coord.y, 0.0f, 0.0f};
1414}
1415
1417{
1418 float2 cellPosition_f = math::floor(coord);
1419 float2 localPosition = coord - cellPosition_f;
1420 int2 cellPosition = int2(cellPosition_f);
1421
1422 float minDistance = FLT_MAX;
1423 int2 targetOffset = {0, 0};
1424 float2 targetPosition = {0.0f, 0.0f};
1425 for (int j = -1; j <= 1; j++) {
1426 for (int i = -1; i <= 1; i++) {
1427 int2 cellOffset(i, j);
1428 float2 pointPosition = float2(cellOffset) +
1429 hash_int2_to_float2(cellPosition + cellOffset) * params.randomness;
1430 float distanceToPoint = voronoi_distance_bound(pointPosition, localPosition, params);
1431 if (distanceToPoint < minDistance) {
1432 targetOffset = cellOffset;
1433 minDistance = distanceToPoint;
1434 targetPosition = pointPosition;
1435 }
1436 }
1437 }
1438
1439 VoronoiOutput octave;
1440 octave.distance = voronoi_distance(targetPosition, localPosition, params);
1441 octave.color = hash_int2_to_float3(cellPosition + targetOffset);
1442 octave.position = voronoi_position(targetPosition + cellPosition_f);
1443 return octave;
1444}
1445
1447 const float2 coord,
1448 const bool calc_color)
1449{
1450 float2 cellPosition_f = math::floor(coord);
1451 float2 localPosition = coord - cellPosition_f;
1452 int2 cellPosition = int2(cellPosition_f);
1453
1454 float smoothDistance = 0.0f;
1455 float3 smoothColor = {0.0f, 0.0f, 0.0f};
1456 float2 smoothPosition = {0.0f, 0.0f};
1457 float h = -1.0f;
1458 for (int j = -2; j <= 2; j++) {
1459 for (int i = -2; i <= 2; i++) {
1460 int2 cellOffset(i, j);
1461 float2 pointPosition = float2(cellOffset) +
1462 hash_int2_to_float2(cellPosition + cellOffset) * params.randomness;
1463 float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
1464 h = h == -1.0f ?
1465 1.0f :
1466 smoothstep(0.0f,
1467 1.0f,
1468 0.5f + 0.5f * (smoothDistance - distanceToPoint) / params.smoothness);
1469 float correctionFactor = params.smoothness * h * (1.0f - h);
1470 smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
1471 correctionFactor /= 1.0f + 3.0f * params.smoothness;
1472 if (calc_color) {
1473 /* Only compute Color output if necessary, as it is very expensive. */
1474 float3 cellColor = hash_int2_to_float3(cellPosition + cellOffset);
1475 smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
1476 }
1477 smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
1478 }
1479 }
1480
1481 VoronoiOutput octave;
1482 octave.distance = smoothDistance;
1483 octave.color = smoothColor;
1484 octave.position = voronoi_position(cellPosition_f + smoothPosition);
1485 return octave;
1486}
1487
1489{
1490 float2 cellPosition_f = math::floor(coord);
1491 float2 localPosition = coord - cellPosition_f;
1492 int2 cellPosition = int2(cellPosition_f);
1493
1494 float distanceF1 = FLT_MAX;
1495 float distanceF2 = FLT_MAX;
1496 int2 offsetF1 = {0, 0};
1497 float2 positionF1 = {0.0f, 0.0f};
1498 int2 offsetF2 = {0, 0};
1499 float2 positionF2 = {0.0f, 0.0f};
1500 for (int j = -1; j <= 1; j++) {
1501 for (int i = -1; i <= 1; i++) {
1502 int2 cellOffset(i, j);
1503 float2 pointPosition = float2(cellOffset) +
1504 hash_int2_to_float2(cellPosition + cellOffset) * params.randomness;
1505 float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
1506 if (distanceToPoint < distanceF1) {
1507 distanceF2 = distanceF1;
1508 distanceF1 = distanceToPoint;
1509 offsetF2 = offsetF1;
1510 offsetF1 = cellOffset;
1511 positionF2 = positionF1;
1512 positionF1 = pointPosition;
1513 }
1514 else if (distanceToPoint < distanceF2) {
1515 distanceF2 = distanceToPoint;
1516 offsetF2 = cellOffset;
1517 positionF2 = pointPosition;
1518 }
1519 }
1520 }
1521
1522 VoronoiOutput octave;
1523 octave.distance = distanceF2;
1524 octave.color = hash_int2_to_float3(cellPosition + offsetF2);
1525 octave.position = voronoi_position(positionF2 + cellPosition_f);
1526 return octave;
1527}
1528
1530{
1531 float2 cellPosition_f = math::floor(coord);
1532 float2 localPosition = coord - cellPosition_f;
1533 int2 cellPosition = int2(cellPosition_f);
1534
1535 float2 vectorToClosest = {0.0f, 0.0f};
1536 float minDistance = FLT_MAX;
1537 for (int j = -1; j <= 1; j++) {
1538 for (int i = -1; i <= 1; i++) {
1539 int2 cellOffset(i, j);
1540 float2 vectorToPoint = float2(cellOffset) +
1541 hash_int2_to_float2(cellPosition + cellOffset) * params.randomness -
1542 localPosition;
1543 float distanceToPoint = math::dot(vectorToPoint, vectorToPoint);
1544 if (distanceToPoint < minDistance) {
1545 minDistance = distanceToPoint;
1546 vectorToClosest = vectorToPoint;
1547 }
1548 }
1549 }
1550
1551 minDistance = FLT_MAX;
1552 for (int j = -1; j <= 1; j++) {
1553 for (int i = -1; i <= 1; i++) {
1554 int2 cellOffset(i, j);
1555 float2 vectorToPoint = float2(cellOffset) +
1556 hash_int2_to_float2(cellPosition + cellOffset) * params.randomness -
1557 localPosition;
1558 float2 perpendicularToEdge = vectorToPoint - vectorToClosest;
1559 if (math::dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
1560 float distanceToEdge = math::dot((vectorToClosest + vectorToPoint) / 2.0f,
1561 math::normalize(perpendicularToEdge));
1562 minDistance = math::min(minDistance, distanceToEdge);
1563 }
1564 }
1565 }
1566
1567 return minDistance;
1568}
1569
1571{
1572 float2 cellPosition_f = math::floor(coord);
1573 float2 localPosition = coord - cellPosition_f;
1574 int2 cellPosition = int2(cellPosition_f);
1575
1576 float2 closestPoint = {0.0f, 0.0f};
1577 int2 closestPointOffset = {0, 0};
1578 float minDistanceSq = FLT_MAX;
1579 for (int j = -1; j <= 1; j++) {
1580 for (int i = -1; i <= 1; i++) {
1581 int2 cellOffset(i, j);
1582 float2 pointPosition = float2(cellOffset) +
1583 hash_int2_to_float2(cellPosition + cellOffset) * params.randomness;
1584 float distanceToPointSq = math::length_squared(pointPosition - localPosition);
1585 if (distanceToPointSq < minDistanceSq) {
1586 minDistanceSq = distanceToPointSq;
1587 closestPoint = pointPosition;
1588 closestPointOffset = cellOffset;
1589 }
1590 }
1591 }
1592
1593 minDistanceSq = FLT_MAX;
1594 float2 closestPointToClosestPoint = {0.0f, 0.0f};
1595 for (int j = -1; j <= 1; j++) {
1596 for (int i = -1; i <= 1; i++) {
1597 if (i == 0 && j == 0) {
1598 continue;
1599 }
1600 int2 cellOffset = int2(i, j) + closestPointOffset;
1601 float2 pointPosition = float2(cellOffset) +
1602 hash_int2_to_float2(cellPosition + cellOffset) * params.randomness;
1603 float distanceToPointSq = math::length_squared(closestPoint - pointPosition);
1604 if (distanceToPointSq < minDistanceSq) {
1605 minDistanceSq = distanceToPointSq;
1606 closestPointToClosestPoint = pointPosition;
1607 }
1608 }
1609 }
1610
1611 return math::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
1612}
1613
1614/* **** 3D Voronoi **** */
1615
1617{
1618 return {coord.x, coord.y, coord.z, 0.0f};
1619}
1620
1622{
1623 float3 cellPosition_f = math::floor(coord);
1624 float3 localPosition = coord - cellPosition_f;
1625 int3 cellPosition = int3(cellPosition_f);
1626
1627 float minDistance = FLT_MAX;
1628 int3 targetOffset = {0, 0, 0};
1629 float3 targetPosition = {0.0f, 0.0f, 0.0f};
1630 for (int k = -1; k <= 1; k++) {
1631 for (int j = -1; j <= 1; j++) {
1632 for (int i = -1; i <= 1; i++) {
1633 int3 cellOffset(i, j, k);
1634 float3 pointPosition = float3(cellOffset) +
1635 hash_int3_to_float3(cellPosition + cellOffset) * params.randomness;
1636 float distanceToPoint = voronoi_distance_bound(pointPosition, localPosition, params);
1637 if (distanceToPoint < minDistance) {
1638 targetOffset = cellOffset;
1639 minDistance = distanceToPoint;
1640 targetPosition = pointPosition;
1641 }
1642 }
1643 }
1644 }
1645
1646 VoronoiOutput octave;
1647 octave.distance = voronoi_distance(targetPosition, localPosition, params);
1648 octave.color = hash_int3_to_float3(cellPosition + targetOffset);
1649 octave.position = voronoi_position(targetPosition + cellPosition_f);
1650 return octave;
1651}
1652
1654 const float3 coord,
1655 const bool calc_color)
1656{
1657 float3 cellPosition_f = math::floor(coord);
1658 float3 localPosition = coord - cellPosition_f;
1659 int3 cellPosition = int3(cellPosition_f);
1660
1661 float smoothDistance = 0.0f;
1662 float3 smoothColor = {0.0f, 0.0f, 0.0f};
1663 float3 smoothPosition = {0.0f, 0.0f, 0.0f};
1664 float h = -1.0f;
1665 for (int k = -2; k <= 2; k++) {
1666 for (int j = -2; j <= 2; j++) {
1667 for (int i = -2; i <= 2; i++) {
1668 int3 cellOffset(i, j, k);
1669 float3 pointPosition = float3(cellOffset) +
1670 hash_int3_to_float3(cellPosition + cellOffset) * params.randomness;
1671 float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
1672 h = h == -1.0f ?
1673 1.0f :
1674 smoothstep(0.0f,
1675 1.0f,
1676 0.5f + 0.5f * (smoothDistance - distanceToPoint) / params.smoothness);
1677 float correctionFactor = params.smoothness * h * (1.0f - h);
1678 smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
1679 correctionFactor /= 1.0f + 3.0f * params.smoothness;
1680 if (calc_color) {
1681 /* Only compute Color output if necessary, as it is very expensive. */
1682 float3 cellColor = hash_int3_to_float3(cellPosition + cellOffset);
1683 smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
1684 }
1685 smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
1686 }
1687 }
1688 }
1689
1690 VoronoiOutput octave;
1691 octave.distance = smoothDistance;
1692 octave.color = smoothColor;
1693 octave.position = voronoi_position(cellPosition_f + smoothPosition);
1694 return octave;
1695}
1696
1698{
1699 float3 cellPosition_f = math::floor(coord);
1700 float3 localPosition = coord - cellPosition_f;
1701 int3 cellPosition = int3(cellPosition_f);
1702
1703 float distanceF1 = FLT_MAX;
1704 float distanceF2 = FLT_MAX;
1705 int3 offsetF1 = {0, 0, 0};
1706 float3 positionF1 = {0.0f, 0.0f, 0.0f};
1707 int3 offsetF2 = {0, 0, 0};
1708 float3 positionF2 = {0.0f, 0.0f, 0.0f};
1709 for (int k = -1; k <= 1; k++) {
1710 for (int j = -1; j <= 1; j++) {
1711 for (int i = -1; i <= 1; i++) {
1712 int3 cellOffset(i, j, k);
1713 float3 pointPosition = float3(cellOffset) +
1714 hash_int3_to_float3(cellPosition + cellOffset) * params.randomness;
1715 float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
1716 if (distanceToPoint < distanceF1) {
1717 distanceF2 = distanceF1;
1718 distanceF1 = distanceToPoint;
1719 offsetF2 = offsetF1;
1720 offsetF1 = cellOffset;
1721 positionF2 = positionF1;
1722 positionF1 = pointPosition;
1723 }
1724 else if (distanceToPoint < distanceF2) {
1725 distanceF2 = distanceToPoint;
1726 offsetF2 = cellOffset;
1727 positionF2 = pointPosition;
1728 }
1729 }
1730 }
1731 }
1732
1733 VoronoiOutput octave;
1734 octave.distance = distanceF2;
1735 octave.color = hash_int3_to_float3(cellPosition + offsetF2);
1736 octave.position = voronoi_position(positionF2 + cellPosition_f);
1737 return octave;
1738}
1739
1741{
1742 float3 cellPosition_f = math::floor(coord);
1743 float3 localPosition = coord - cellPosition_f;
1744 int3 cellPosition = int3(cellPosition_f);
1745
1746 float3 vectorToClosest = {0.0f, 0.0f, 0.0f};
1747 float minDistance = FLT_MAX;
1748 for (int k = -1; k <= 1; k++) {
1749 for (int j = -1; j <= 1; j++) {
1750 for (int i = -1; i <= 1; i++) {
1751 int3 cellOffset(i, j, k);
1752 float3 vectorToPoint = float3(cellOffset) +
1753 hash_int3_to_float3(cellPosition + cellOffset) * params.randomness -
1754 localPosition;
1755 float distanceToPoint = math::dot(vectorToPoint, vectorToPoint);
1756 if (distanceToPoint < minDistance) {
1757 minDistance = distanceToPoint;
1758 vectorToClosest = vectorToPoint;
1759 }
1760 }
1761 }
1762 }
1763
1764 minDistance = FLT_MAX;
1765 for (int k = -1; k <= 1; k++) {
1766 for (int j = -1; j <= 1; j++) {
1767 for (int i = -1; i <= 1; i++) {
1768 int3 cellOffset(i, j, k);
1769 float3 vectorToPoint = float3(cellOffset) +
1770 hash_int3_to_float3(cellPosition + cellOffset) * params.randomness -
1771 localPosition;
1772 float3 perpendicularToEdge = vectorToPoint - vectorToClosest;
1773 if (math::dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
1774 float distanceToEdge = math::dot((vectorToClosest + vectorToPoint) / 2.0f,
1775 math::normalize(perpendicularToEdge));
1776 minDistance = math::min(minDistance, distanceToEdge);
1777 }
1778 }
1779 }
1780 }
1781
1782 return minDistance;
1783}
1784
1786{
1787 float3 cellPosition_f = math::floor(coord);
1788 float3 localPosition = coord - cellPosition_f;
1789 int3 cellPosition = int3(cellPosition_f);
1790
1791 float3 closestPoint = {0.0f, 0.0f, 0.0f};
1792 int3 closestPointOffset = {0, 0, 0};
1793 float minDistanceSq = FLT_MAX;
1794 for (int k = -1; k <= 1; k++) {
1795 for (int j = -1; j <= 1; j++) {
1796 for (int i = -1; i <= 1; i++) {
1797 int3 cellOffset(i, j, k);
1798 float3 pointPosition = float3(cellOffset) +
1799 hash_int3_to_float3(cellPosition + cellOffset) * params.randomness;
1800 float distanceToPointSq = math::length_squared(pointPosition - localPosition);
1801 if (distanceToPointSq < minDistanceSq) {
1802 minDistanceSq = distanceToPointSq;
1803 closestPoint = pointPosition;
1804 closestPointOffset = cellOffset;
1805 }
1806 }
1807 }
1808 }
1809
1810 minDistanceSq = FLT_MAX;
1811 float3 closestPointToClosestPoint = {0.0f, 0.0f, 0.0f};
1812 for (int k = -1; k <= 1; k++) {
1813 for (int j = -1; j <= 1; j++) {
1814 for (int i = -1; i <= 1; i++) {
1815 if (i == 0 && j == 0 && k == 0) {
1816 continue;
1817 }
1818 int3 cellOffset = int3(i, j, k) + closestPointOffset;
1819 float3 pointPosition = float3(cellOffset) +
1820 hash_int3_to_float3(cellPosition + cellOffset) * params.randomness;
1821 float distanceToPointSq = math::length_squared(closestPoint - pointPosition);
1822 if (distanceToPointSq < minDistanceSq) {
1823 minDistanceSq = distanceToPointSq;
1824 closestPointToClosestPoint = pointPosition;
1825 }
1826 }
1827 }
1828 }
1829
1830 return math::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
1831}
1832
1833/* **** 4D Voronoi **** */
1834
1836{
1837 return coord;
1838}
1839
1841{
1842 float4 cellPosition_f = math::floor(coord);
1843 float4 localPosition = coord - cellPosition_f;
1844 int4 cellPosition = int4(cellPosition_f);
1845
1846 float minDistance = FLT_MAX;
1847 int4 targetOffset = {0, 0, 0, 0};
1848 float4 targetPosition = {0.0f, 0.0f, 0.0f, 0.0f};
1849 for (int u = -1; u <= 1; u++) {
1850 for (int k = -1; k <= 1; k++) {
1851 for (int j = -1; j <= 1; j++) {
1852 for (int i = -1; i <= 1; i++) {
1853 int4 cellOffset(i, j, k, u);
1854 float4 pointPosition = float4(cellOffset) +
1855 hash_int4_to_float4(cellPosition + cellOffset) *
1856 params.randomness;
1857 float distanceToPoint = voronoi_distance_bound(pointPosition, localPosition, params);
1858 if (distanceToPoint < minDistance) {
1859 targetOffset = cellOffset;
1860 minDistance = distanceToPoint;
1861 targetPosition = pointPosition;
1862 }
1863 }
1864 }
1865 }
1866 }
1867
1868 VoronoiOutput octave;
1869 octave.distance = voronoi_distance(targetPosition, localPosition, params);
1870 octave.color = hash_int4_to_float3(cellPosition + targetOffset);
1871 octave.position = voronoi_position(targetPosition + cellPosition_f);
1872 return octave;
1873}
1874
1876 const float4 coord,
1877 const bool calc_color)
1878{
1879 float4 cellPosition_f = math::floor(coord);
1880 float4 localPosition = coord - cellPosition_f;
1881 int4 cellPosition = int4(cellPosition_f);
1882
1883 float smoothDistance = 0.0f;
1884 float3 smoothColor = {0.0f, 0.0f, 0.0f};
1885 float4 smoothPosition = {0.0f, 0.0f, 0.0f, 0.0f};
1886 float h = -1.0f;
1887 for (int u = -2; u <= 2; u++) {
1888 for (int k = -2; k <= 2; k++) {
1889 for (int j = -2; j <= 2; j++) {
1890 for (int i = -2; i <= 2; i++) {
1891 int4 cellOffset(i, j, k, u);
1892 float4 pointPosition = float4(cellOffset) +
1893 hash_int4_to_float4(cellPosition + cellOffset) *
1894 params.randomness;
1895 float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
1896 h = h == -1.0f ?
1897 1.0f :
1898 smoothstep(0.0f,
1899 1.0f,
1900 0.5f + 0.5f * (smoothDistance - distanceToPoint) / params.smoothness);
1901 float correctionFactor = params.smoothness * h * (1.0f - h);
1902 smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
1903 correctionFactor /= 1.0f + 3.0f * params.smoothness;
1904 if (calc_color) {
1905 /* Only compute Color output if necessary, as it is very expensive. */
1906 float3 cellColor = hash_int4_to_float3(cellPosition + cellOffset);
1907 smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
1908 }
1909 smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
1910 }
1911 }
1912 }
1913 }
1914
1915 VoronoiOutput octave;
1916 octave.distance = smoothDistance;
1917 octave.color = smoothColor;
1918 octave.position = voronoi_position(cellPosition_f + smoothPosition);
1919 return octave;
1920}
1921
1923{
1924 float4 cellPosition_f = math::floor(coord);
1925 float4 localPosition = coord - cellPosition_f;
1926 int4 cellPosition = int4(cellPosition_f);
1927
1928 float distanceF1 = FLT_MAX;
1929 float distanceF2 = FLT_MAX;
1930 int4 offsetF1 = {0, 0, 0, 0};
1931 float4 positionF1 = {0.0f, 0.0f, 0.0f, 0.0f};
1932 int4 offsetF2 = {0, 0, 0, 0};
1933 float4 positionF2 = {0.0f, 0.0f, 0.0f, 0.0f};
1934 for (int u = -1; u <= 1; u++) {
1935 for (int k = -1; k <= 1; k++) {
1936 for (int j = -1; j <= 1; j++) {
1937 for (int i = -1; i <= 1; i++) {
1938 int4 cellOffset(i, j, k, u);
1939 float4 pointPosition = float4(cellOffset) +
1940 hash_int4_to_float4(cellPosition + cellOffset) *
1941 params.randomness;
1942 float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
1943 if (distanceToPoint < distanceF1) {
1944 distanceF2 = distanceF1;
1945 distanceF1 = distanceToPoint;
1946 offsetF2 = offsetF1;
1947 offsetF1 = cellOffset;
1948 positionF2 = positionF1;
1949 positionF1 = pointPosition;
1950 }
1951 else if (distanceToPoint < distanceF2) {
1952 distanceF2 = distanceToPoint;
1953 offsetF2 = cellOffset;
1954 positionF2 = pointPosition;
1955 }
1956 }
1957 }
1958 }
1959 }
1960
1961 VoronoiOutput octave;
1962 octave.distance = distanceF2;
1963 octave.color = hash_int4_to_float3(cellPosition + offsetF2);
1964 octave.position = voronoi_position(positionF2 + cellPosition_f);
1965 return octave;
1966}
1967
1969{
1970 float4 cellPosition_f = math::floor(coord);
1971 float4 localPosition = coord - cellPosition_f;
1972 int4 cellPosition = int4(cellPosition_f);
1973
1974 float4 vectorToClosest = {0.0f, 0.0f, 0.0f, 0.0f};
1975 float minDistance = FLT_MAX;
1976 for (int u = -1; u <= 1; u++) {
1977 for (int k = -1; k <= 1; k++) {
1978 for (int j = -1; j <= 1; j++) {
1979 for (int i = -1; i <= 1; i++) {
1980 int4 cellOffset(i, j, k, u);
1981 float4 vectorToPoint = float4(cellOffset) +
1982 hash_int4_to_float4(cellPosition + cellOffset) *
1983 params.randomness -
1984 localPosition;
1985 float distanceToPoint = math::dot(vectorToPoint, vectorToPoint);
1986 if (distanceToPoint < minDistance) {
1987 minDistance = distanceToPoint;
1988 vectorToClosest = vectorToPoint;
1989 }
1990 }
1991 }
1992 }
1993 }
1994
1995 minDistance = FLT_MAX;
1996 for (int u = -1; u <= 1; u++) {
1997 for (int k = -1; k <= 1; k++) {
1998 for (int j = -1; j <= 1; j++) {
1999 for (int i = -1; i <= 1; i++) {
2000 int4 cellOffset(i, j, k, u);
2001 float4 vectorToPoint = float4(cellOffset) +
2002 hash_int4_to_float4(cellPosition + cellOffset) *
2003 params.randomness -
2004 localPosition;
2005 float4 perpendicularToEdge = vectorToPoint - vectorToClosest;
2006 if (math::dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
2007 float distanceToEdge = math::dot((vectorToClosest + vectorToPoint) / 2.0f,
2008 math::normalize(perpendicularToEdge));
2009 minDistance = math::min(minDistance, distanceToEdge);
2010 }
2011 }
2012 }
2013 }
2014 }
2015
2016 return minDistance;
2017}
2018
2020{
2021 float4 cellPosition_f = math::floor(coord);
2022 float4 localPosition = coord - cellPosition_f;
2023 int4 cellPosition = int4(cellPosition_f);
2024
2025 float4 closestPoint = {0.0f, 0.0f, 0.0f, 0.0f};
2026 int4 closestPointOffset = {0, 0, 0, 0};
2027 float minDistanceSq = FLT_MAX;
2028 for (int u = -1; u <= 1; u++) {
2029 for (int k = -1; k <= 1; k++) {
2030 for (int j = -1; j <= 1; j++) {
2031 for (int i = -1; i <= 1; i++) {
2032 int4 cellOffset(i, j, k, u);
2033 float4 pointPosition = float4(cellOffset) +
2034 hash_int4_to_float4(cellPosition + cellOffset) *
2035 params.randomness;
2036 float distanceToPointSq = math::length_squared(pointPosition - localPosition);
2037 if (distanceToPointSq < minDistanceSq) {
2038 minDistanceSq = distanceToPointSq;
2039 closestPoint = pointPosition;
2040 closestPointOffset = cellOffset;
2041 }
2042 }
2043 }
2044 }
2045 }
2046
2047 minDistanceSq = FLT_MAX;
2048 float4 closestPointToClosestPoint = {0.0f, 0.0f, 0.0f, 0.0f};
2049 for (int u = -1; u <= 1; u++) {
2050 for (int k = -1; k <= 1; k++) {
2051 for (int j = -1; j <= 1; j++) {
2052 for (int i = -1; i <= 1; i++) {
2053 if (i == 0 && j == 0 && k == 0 && u == 0) {
2054 continue;
2055 }
2056 int4 cellOffset = int4(i, j, k, u) + closestPointOffset;
2057 float4 pointPosition = float4(cellOffset) +
2058 hash_int4_to_float4(cellPosition + cellOffset) *
2059 params.randomness;
2060 float distanceToPointSq = math::length_squared(closestPoint - pointPosition);
2061 if (distanceToPointSq < minDistanceSq) {
2062 minDistanceSq = distanceToPointSq;
2063 closestPointToClosestPoint = pointPosition;
2064 }
2065 }
2066 }
2067 }
2068 }
2069
2070 return math::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
2071}
2072
2073/* **** Fractal Voronoi **** */
2074
2075/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
2076 * by lerps. */
2077template<typename T>
2079 const T coord,
2080 const bool calc_color /* Only used to optimize Smooth F1 */)
2081{
2082 float amplitude = 1.0f;
2083 float max_amplitude = 0.0f;
2084 float scale = 1.0f;
2085
2087 const bool zero_input = params.detail == 0.0f || params.roughness == 0.0f;
2088
2089 for (int i = 0; i <= ceilf(params.detail); ++i) {
2090 VoronoiOutput octave = (params.feature == NOISE_SHD_VORONOI_F2) ?
2091 voronoi_f2(params, coord * scale) :
2092 (params.feature == NOISE_SHD_VORONOI_SMOOTH_F1 &&
2093 params.smoothness != 0.0f) ?
2094 voronoi_smooth_f1(params, coord * scale, calc_color) :
2095 voronoi_f1(params, coord * scale);
2096
2097 if (zero_input) {
2098 max_amplitude = 1.0f;
2099 output = octave;
2100 break;
2101 }
2102 if (i <= params.detail) {
2103 max_amplitude += amplitude;
2104 output.distance += octave.distance * amplitude;
2105 output.color += octave.color * amplitude;
2106 output.position = mix(output.position, octave.position / scale, amplitude);
2107 scale *= params.lacunarity;
2108 amplitude *= params.roughness;
2109 }
2110 else {
2111 float remainder = params.detail - floorf(params.detail);
2112 if (remainder != 0.0f) {
2113 max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder);
2114 output.distance = mix(
2115 output.distance, output.distance + octave.distance * amplitude, remainder);
2116 output.color = mix(output.color, output.color + octave.color * amplitude, remainder);
2117 output.position = mix(
2118 output.position, mix(output.position, octave.position / scale, amplitude), remainder);
2119 }
2120 }
2121 }
2122
2123 if (params.normalize) {
2124 output.distance /= max_amplitude * params.max_distance;
2125 output.color /= max_amplitude;
2126 }
2127
2128 output.position = (params.scale != 0.0f) ? output.position / params.scale :
2129 float4{0.0f, 0.0f, 0.0f, 0.0f};
2130
2131 return output;
2132}
2133
2134/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
2135 * by lerps. */
2136template<typename T>
2138{
2139 float amplitude = 1.0f;
2140 float max_amplitude = params.max_distance;
2141 float scale = 1.0f;
2142 float distance = 8.0f;
2143
2144 const bool zero_input = params.detail == 0.0f || params.roughness == 0.0f;
2145
2146 for (int i = 0; i <= ceilf(params.detail); ++i) {
2147 const float octave_distance = voronoi_distance_to_edge(params, coord * scale);
2148
2149 if (zero_input) {
2150 distance = octave_distance;
2151 break;
2152 }
2153 if (i <= params.detail) {
2154 max_amplitude = mix(max_amplitude, params.max_distance / scale, amplitude);
2155 distance = mix(distance, math::min(distance, octave_distance / scale), amplitude);
2156 scale *= params.lacunarity;
2157 amplitude *= params.roughness;
2158 }
2159 else {
2160 float remainder = params.detail - floorf(params.detail);
2161 if (remainder != 0.0f) {
2162 float lerp_amplitude = mix(max_amplitude, params.max_distance / scale, amplitude);
2163 max_amplitude = mix(max_amplitude, lerp_amplitude, remainder);
2164 float lerp_distance = mix(
2165 distance, math::min(distance, octave_distance / scale), amplitude);
2166 distance = mix(distance, math::min(distance, lerp_distance), remainder);
2167 }
2168 }
2169 }
2170
2171 if (params.normalize) {
2172 distance /= max_amplitude;
2173 }
2174
2175 return distance;
2176}
2177
2178/* Explicit function template instantiation */
2179
2181 const float coord,
2182 const bool calc_color);
2184 const float2 coord,
2185 const bool calc_color);
2187 const float3 coord,
2188 const bool calc_color);
2190 const float4 coord,
2191 const bool calc_color);
2192
2194 const float coord);
2196 const float2 coord);
2198 const float3 coord);
2200 const float4 coord);
2202
2203/* -------------------------------------------------------------------- */
2222
2223/* The original Gabor noise paper specifies that the impulses count for each cell should be
2224 * computed by sampling a Poisson distribution whose mean is the impulse density. However,
2225 * Tavernier's paper showed that stratified Poisson point sampling is better assuming the weights
2226 * are sampled using a Bernoulli distribution, as shown in Figure (3). By stratified sampling, they
2227 * mean a constant number of impulses per cell, so the stratification is the grid itself in that
2228 * sense, as described in the supplementary material of the paper. */
2229static constexpr int gabor_impulses_count = 8;
2230
2231/* Computes a 2D Gabor kernel based on Equation (6) in the original Gabor noise paper. Where the
2232 * frequency argument is the F_0 parameter and the orientation argument is the w_0 parameter. We
2233 * assume the Gaussian envelope has a unit magnitude, that is, K = 1. That is because we will
2234 * eventually normalize the final noise value to the unit range, so the multiplication by the
2235 * magnitude will be canceled by the normalization. Further, we also assume a unit Gaussian width,
2236 * that is, a = 1. That is because it does not provide much artistic control. It follows that the
2237 * Gaussian will be truncated at pi.
2238 *
2239 * To avoid the discontinuities caused by the aforementioned truncation, the Gaussian is windowed
2240 * using a Hann window, that is because contrary to the claim made in the original Gabor paper,
2241 * truncating the Gaussian produces significant artifacts especially when differentiated for bump
2242 * mapping. The Hann window is C1 continuous and has limited effect on the shape of the Gaussian,
2243 * so it felt like an appropriate choice.
2244 *
2245 * Finally, instead of computing the Gabor value directly, we instead use the complex phasor
2246 * formulation described in section 3.1.1 in Tricard's paper. That's done to be able to compute the
2247 * phase and intensity of the Gabor noise after summation based on equations (8) and (9). The
2248 * return value of the Gabor kernel function is then a complex number whose real value is the
2249 * value computed in the original Gabor noise paper, and whose imaginary part is the sine
2250 * counterpart of the real part, which is the only extra computation in the new formulation.
2251 *
2252 * Note that while the original Gabor noise paper uses the cosine part of the phasor, that is, the
2253 * real part of the phasor, we use the sine part instead, that is, the imaginary part of the
2254 * phasor, as suggested by Tavernier's paper in "Section 3.3. Instance stationarity and
2255 * normalization", to ensure a zero mean, which should help with normalization. */
2257 const float frequency,
2258 const float orientation)
2259{
2260 const float distance_squared = math::length_squared(position);
2261 const float hann_window = 0.5f + 0.5f * math::cos(math::numbers::pi * distance_squared);
2262 const float gaussian_envelop = math::exp(-math::numbers::pi * distance_squared);
2263 const float windowed_gaussian_envelope = gaussian_envelop * hann_window;
2264
2265 const float2 frequency_vector = frequency * float2(cos(orientation), sin(orientation));
2266 const float angle = 2.0f * math::numbers::pi * math::dot(position, frequency_vector);
2267 const float2 phasor = float2(math::cos(angle), math::sin(angle));
2268
2269 return windowed_gaussian_envelope * phasor;
2270}
2271
2308{
2309 const float integral_of_gabor_squared = 0.25f;
2310 const float second_moment = 0.5f;
2311 return math::sqrt(gabor_impulses_count * second_moment * integral_of_gabor_squared);
2312}
2313
2314/* Computes the Gabor noise value at the given position for the given cell. This is essentially the
2315 * sum in Equation (8) in the original Gabor noise paper, where we sum Gabor kernels sampled at a
2316 * random position with a random weight. The orientation of the kernel is constant for anisotropic
2317 * noise while it is random for isotropic noise. The original Gabor noise paper mentions that the
2318 * weights should be uniformly distributed in the [-1, 1] range, however, Tavernier's paper showed
2319 * that using a Bernoulli distribution yields better results, so that is what we do. */
2321 const float2 position,
2322 const float frequency,
2323 const float isotropy,
2324 const float base_orientation)
2325
2326{
2327 float2 noise(0.0f);
2328 for (const int i : IndexRange(gabor_impulses_count)) {
2329 /* Compute unique seeds for each of the needed random variables. */
2330 const float3 seed_for_orientation(cell.x, cell.y, i * 3);
2331 const float3 seed_for_kernel_center(cell.x, cell.y, i * 3 + 1);
2332 const float3 seed_for_weight(cell.x, cell.y, i * 3 + 2);
2333
2334 /* For isotropic noise, add a random orientation amount, while for anisotropic noise, use the
2335 * base orientation. Linearly interpolate between the two cases using the isotropy factor. Note
2336 * that the random orientation range spans pi as opposed to two pi, that's because the Gabor
2337 * kernel is symmetric around pi. */
2338 const float random_orientation = (noise::hash_float_to_float(seed_for_orientation) - 0.5f) *
2340 const float orientation = base_orientation + random_orientation * isotropy;
2341
2342 const float2 kernel_center = noise::hash_float_to_float2(seed_for_kernel_center);
2343 const float2 position_in_kernel_space = position - kernel_center;
2344
2345 /* The kernel is windowed beyond the unit distance, so early exit with a zero for points that
2346 * are further than a unit radius. */
2347 if (math::length_squared(position_in_kernel_space) >= 1.0f) {
2348 continue;
2349 }
2350
2351 /* We either add or subtract the Gabor kernel based on a Bernoulli distribution of equal
2352 * probability. */
2353 const float weight = noise::hash_float_to_float(seed_for_weight) < 0.5f ? -1.0f : 1.0f;
2354
2355 noise += weight * compute_2d_gabor_kernel(position_in_kernel_space, frequency, orientation);
2356 }
2357 return noise;
2358}
2359
2360/* Computes the Gabor noise value by dividing the space into a grid and evaluating the Gabor noise
2361 * in the space of each cell of the 3x3 cell neighborhood. */
2362static float2 compute_2d_gabor_noise(const float2 coordinates,
2363 const float frequency,
2364 const float isotropy,
2365 const float base_orientation)
2366{
2367 const float2 cell_position = math::floor(coordinates);
2368 const float2 local_position = coordinates - cell_position;
2369
2370 float2 sum(0.0f);
2371 for (int j = -1; j <= 1; j++) {
2372 for (int i = -1; i <= 1; i++) {
2373 const float2 cell_offset = float2(i, j);
2374 const float2 current_cell_position = cell_position + cell_offset;
2375 const float2 position_in_cell_space = local_position - cell_offset;
2377 current_cell_position, position_in_cell_space, frequency, isotropy, base_orientation);
2378 }
2379 }
2380
2381 return sum;
2382}
2383
2384/* Identical to compute_2d_gabor_kernel, except it is evaluated in 3D space. Notice that Equation
2385 * (6) in the original Gabor noise paper computes the frequency vector using (cos(w_0), sin(w_0)),
2386 * which we also do in the 2D variant, however, for 3D, the orientation is already a unit frequency
2387 * vector, so we just need to scale it by the frequency value. */
2389 const float frequency,
2390 const float3 orientation)
2391{
2392 const float distance_squared = math::length_squared(position);
2393 const float hann_window = 0.5f + 0.5f * math::cos(math::numbers::pi * distance_squared);
2394 const float gaussian_envelop = math::exp(-math::numbers::pi * distance_squared);
2395 const float windowed_gaussian_envelope = gaussian_envelop * hann_window;
2396
2397 const float3 frequency_vector = frequency * orientation;
2398 const float angle = 2.0f * math::numbers::pi * math::dot(position, frequency_vector);
2399 const float2 phasor = float2(math::cos(angle), math::sin(angle));
2400
2401 return windowed_gaussian_envelope * phasor;
2402}
2403
2404/* Identical to compute_2d_gabor_standard_deviation except we do triple integration in 3D. The only
2405 * difference is the denominator in the integral expression, which is 2^{5 / 2} for the 3D case
2406 * instead of 4 for the 2D case. Similarly, the limit evaluates to 1 / (4 * sqrt(2)). */
2408{
2409 const float integral_of_gabor_squared = 1.0f / (4.0f * math::numbers::sqrt2);
2410 const float second_moment = 0.5f;
2411 return math::sqrt(gabor_impulses_count * second_moment * integral_of_gabor_squared);
2412}
2413
2414/* Computes the orientation of the Gabor kernel such that it is constant for anisotropic
2415 * noise while it is random for isotropic noise. We randomize in spherical coordinates for a
2416 * uniform distribution. */
2417static float3 compute_3d_orientation(const float3 orientation,
2418 const float isotropy,
2419 const float4 seed)
2420{
2421 /* Return the base orientation in case we are completely anisotropic. */
2422 if (isotropy == 0.0) {
2423 return orientation;
2424 }
2425
2426 /* Compute the orientation in spherical coordinates. */
2427 float inclination = math::acos(orientation.z);
2428 float azimuth = math::sign(orientation.y) *
2429 math::acos(orientation.x / math::length(float2(orientation.x, orientation.y)));
2430
2431 /* For isotropic noise, add a random orientation amount, while for anisotropic noise, use the
2432 * base orientation. Linearly interpolate between the two cases using the isotropy factor. Note
2433 * that the random orientation range is to pi as opposed to two pi, that's because the Gabor
2434 * kernel is symmetric around pi. */
2436 inclination += random_angles.x * isotropy;
2437 azimuth += random_angles.y * isotropy;
2438
2439 /* Convert back to Cartesian coordinates, */
2440 return float3(math::sin(inclination) * math::cos(azimuth),
2441 math::sin(inclination) * math::sin(azimuth),
2442 math::cos(inclination));
2443}
2444
2446 const float3 position,
2447 const float frequency,
2448 const float isotropy,
2449 const float3 base_orientation)
2450
2451{
2452 float2 noise(0.0f);
2453 for (const int i : IndexRange(gabor_impulses_count)) {
2454 /* Compute unique seeds for each of the needed random variables. */
2455 const float4 seed_for_orientation(cell.x, cell.y, cell.z, i * 3);
2456 const float4 seed_for_kernel_center(cell.x, cell.y, cell.z, i * 3 + 1);
2457 const float4 seed_for_weight(cell.x, cell.y, cell.z, i * 3 + 2);
2458
2459 const float3 orientation = compute_3d_orientation(
2460 base_orientation, isotropy, seed_for_orientation);
2461
2462 const float3 kernel_center = noise::hash_float_to_float3(seed_for_kernel_center);
2463 const float3 position_in_kernel_space = position - kernel_center;
2464
2465 /* The kernel is windowed beyond the unit distance, so early exit with a zero for points that
2466 * are further than a unit radius. */
2467 if (math::length_squared(position_in_kernel_space) >= 1.0f) {
2468 continue;
2469 }
2470
2471 /* We either add or subtract the Gabor kernel based on a Bernoulli distribution of equal
2472 * probability. */
2473 const float weight = noise::hash_float_to_float(seed_for_weight) < 0.5f ? -1.0f : 1.0f;
2474
2475 noise += weight * compute_3d_gabor_kernel(position_in_kernel_space, frequency, orientation);
2476 }
2477 return noise;
2478}
2479
2480/* Identical to compute_2d_gabor_noise but works in the 3D neighborhood of the noise. */
2481static float2 compute_3d_gabor_noise(const float3 coordinates,
2482 const float frequency,
2483 const float isotropy,
2484 const float3 base_orientation)
2485{
2486 const float3 cell_position = math::floor(coordinates);
2487 const float3 local_position = coordinates - cell_position;
2488
2489 float2 sum(0.0f);
2490 for (int k = -1; k <= 1; k++) {
2491 for (int j = -1; j <= 1; j++) {
2492 for (int i = -1; i <= 1; i++) {
2493 const float3 cell_offset = float3(i, j, k);
2494 const float3 current_cell_position = cell_position + cell_offset;
2495 const float3 position_in_cell_space = local_position - cell_offset;
2497 current_cell_position, position_in_cell_space, frequency, isotropy, base_orientation);
2498 }
2499 }
2500 }
2501
2502 return sum;
2503}
2504
2505void gabor(const float2 coordinates,
2506 const float scale,
2507 const float frequency,
2508 const float anisotropy,
2509 const float orientation,
2510 float *r_value,
2511 float *r_phase,
2512 float *r_intensity)
2513{
2514 const float2 scaled_coordinates = coordinates * scale;
2515 const float isotropy = 1.0f - math::clamp(anisotropy, 0.0f, 1.0f);
2516 const float sanitized_frequency = math::max(0.001f, frequency);
2517
2518 const float2 phasor = compute_2d_gabor_noise(
2519 scaled_coordinates, sanitized_frequency, isotropy, orientation);
2520 const float standard_deviation = compute_2d_gabor_standard_deviation();
2521
2522 /* Normalize the noise by dividing by six times the standard deviation, which was determined
2523 * empirically. */
2524 const float normalization_factor = 6.0f * standard_deviation;
2525
2526 /* As discussed in compute_2d_gabor_kernel, we use the imaginary part of the phasor as the Gabor
2527 * value. But remap to [0, 1] from [-1, 1]. */
2528 if (r_value) {
2529 *r_value = (phasor.y / normalization_factor) * 0.5f + 0.5f;
2530 }
2531
2532 /* Compute the phase based on equation (9) in Tricard's paper. But remap the phase into the
2533 * [0, 1] range. */
2534 if (r_phase) {
2535 *r_phase = (math::atan2(phasor.y, phasor.x) + math::numbers::pi) / (2.0f * math::numbers::pi);
2536 }
2537
2538 /* Compute the intensity based on equation (8) in Tricard's paper. */
2539 if (r_intensity) {
2540 *r_intensity = math::length(phasor) / normalization_factor;
2541 }
2542}
2543
2544void gabor(const float3 coordinates,
2545 const float scale,
2546 const float frequency,
2547 const float anisotropy,
2548 const float3 orientation,
2549 float *r_value,
2550 float *r_phase,
2551 float *r_intensity)
2552{
2553 const float3 scaled_coordinates = coordinates * scale;
2554 const float isotropy = 1.0f - math::clamp(anisotropy, 0.0f, 1.0f);
2555 const float sanitized_frequency = math::max(0.001f, frequency);
2556
2557 const float3 normalized_orientation = math::normalize(orientation);
2558 const float2 phasor = compute_3d_gabor_noise(
2559 scaled_coordinates, sanitized_frequency, isotropy, normalized_orientation);
2560 const float standard_deviation = compute_3d_gabor_standard_deviation();
2561
2562 /* Normalize the noise by dividing by six times the standard deviation, which was determined
2563 * empirically. */
2564 const float normalization_factor = 6.0f * standard_deviation;
2565
2566 /* As discussed in compute_2d_gabor_kernel, we use the imaginary part of the phasor as the Gabor
2567 * value. But remap to [0, 1] from [-1, 1]. */
2568 if (r_value) {
2569 *r_value = (phasor.y / normalization_factor) * 0.5f + 0.5f;
2570 }
2571
2572 /* Compute the phase based on equation (9) in Tricard's paper. But remap the phase into the
2573 * [0, 1] range. */
2574 if (r_phase) {
2575 *r_phase = (math::atan2(phasor.y, phasor.x) + math::numbers::pi) / (2.0f * math::numbers::pi);
2576 }
2577
2578 /* Compute the intensity based on equation (8) in Tricard's paper. */
2579 if (r_intensity) {
2580 *r_intensity = math::length(phasor) / normalization_factor;
2581 }
2582}
2583
2585
2586} // namespace blender::noise
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_INLINE
#define BLI_NOINLINE
#define ELEM(...)
#define X
#define Z
#define Y
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
static T sum(const btAlignedObjectArray< T > &items)
static unsigned long seed
Definition btSoftBody.h:39
nullptr float
#define output
#define sin
#define cos
VecBase< float, D > normalize(VecOp< float, D >) RET
float distance(VecOp< float, D >, VecOp< float, D >) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
MINLINE float smoothstep(float edge0, float edge1, float x)
#define T
T length_squared(const VecBase< T, Size > &a)
T cos(const AngleRadianBase< T > &a)
T clamp(const T &a, const T &min, const T &max)
T acos(const T &a)
T sqrt(const T &a)
T sign(const T &a)
T floor(const T &a)
T distance(const T &a, const T &b)
T length(const VecBase< T, Size > &a)
T exp(const T &x)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
T min(const T &a, const T &b)
T atan2(const T &y, const T &x)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
T sin(const AngleRadianBase< T > &a)
T max(const T &a, const T &b)
T mod(const T &a, const T &b)
T abs(const T &a)
static ATTR_NO_SIGNED_INT_OVERFLOW int4 hash_pcg4d_i(int4 v)
Definition noise.cc:186
static float int_to_float_01(int32_t k)
Definition noise.cc:330
template VoronoiOutput fractal_voronoi_x_fx< float4 >(const VoronoiParams &params, const float4 coord, const bool calc_color)
template float fractal_voronoi_distance_to_edge< float >(const VoronoiParams &params, const float coord)
float3 perlin_float3_fractal_distorted(float position, float detail, float roughness, float lacunarity, float offset, float gain, float distortion, int type, bool normalize)
Definition noise.cc:1001
BLI_INLINE float negate_if(float value, uint32_t condition)
Definition noise.cc:467
static float3 hash_int3_to_float3(int3 k)
Definition noise.cc:341
BLI_INLINE float uint_to_float_01(uint32_t k)
Definition noise.cc:228
float perlin_ridged_multi_fractal(T p, const float detail, const float roughness, const float lacunarity, const float offset, const float gain)
Definition noise.cc:816
static float2 compute_3d_gabor_noise(const float3 coordinates, const float frequency, const float isotropy, const float3 base_orientation)
Definition noise.cc:2481
uint32_t hash_float(float kx)
Definition noise.cc:201
static float compute_3d_gabor_standard_deviation()
Definition noise.cc:2407
template float perlin_fbm< float3 >(float3 p, const float detail, const float roughness, const float lacunarity, const bool normalize)
static float2 compute_2d_gabor_noise_cell(const float2 cell, const float2 position, const float frequency, const float isotropy, const float base_orientation)
Definition noise.cc:2320
BLI_INLINE float perlin_distortion(float position, float strength)
Definition noise.cc:918
float hash_float_to_float(float k)
Definition noise.cc:255
float perlin_signed(float position)
Definition noise.cc:614
void gabor(const float2 coordinates, const float scale, const float frequency, const float anisotropy, const float orientation, float *r_value, float *r_phase, float *r_intensity)
Definition noise.cc:2505
template float perlin_fractal_distorted< float >(float position, float detail, float roughness, float lacunarity, float offset, float gain, float distortion, int type, bool normalize)
BLI_INLINE void hash_bit_mix(uint32_t &a, uint32_t &b, uint32_t &c)
Definition noise.cc:50
float4 voronoi_position(const float coord)
Definition noise.cc:1248
BLI_INLINE float fade(float t)
Definition noise.cc:462
@ NOISE_SHD_VORONOI_MANHATTAN
Definition noise.cc:1151
@ NOISE_SHD_VORONOI_MINKOWSKI
Definition noise.cc:1153
@ NOISE_SHD_VORONOI_EUCLIDEAN
Definition noise.cc:1150
@ NOISE_SHD_VORONOI_CHEBYCHEV
Definition noise.cc:1152
VoronoiOutput voronoi_smooth_f1(const VoronoiParams &params, const float coord, const bool calc_color)
Definition noise.cc:1280
float voronoi_n_sphere_radius(const VoronoiParams &params, const float coord)
Definition noise.cc:1370
static float2 compute_2d_gabor_noise(const float2 coordinates, const float frequency, const float isotropy, const float base_orientation)
Definition noise.cc:2362
float perlin(float position)
Definition noise.cc:665
BLI_INLINE float random_float_offset(float seed)
Definition noise.cc:890
static float voronoi_distance_bound(const T a, const T b, const VoronoiParams &params)
Definition noise.cc:1238
BLI_INLINE float floor_fraction(float x, int &i)
Definition noise.cc:505
float voronoi_distance_to_edge(const VoronoiParams &params, const float coord)
Definition noise.cc:1356
BLI_INLINE uint32_t float_as_uint(float f)
Definition noise.cc:142
static float4 hash_int4_to_float4(int4 k)
Definition noise.cc:347
template VoronoiOutput fractal_voronoi_x_fx< float3 >(const VoronoiParams &params, const float3 coord, const bool calc_color)
static float2 hash_int2_to_float2(int2 k)
Definition noise.cc:335
template float perlin_fractal_distorted< float2 >(float2 position, float detail, float roughness, float lacunarity, float offset, float gain, float distortion, int type, bool normalize)
BLI_INLINE float3 random_float3_offset(float seed)
Definition noise.cc:901
static float3 hash_int2_to_float3(int2 k)
Definition noise.cc:354
static float2 compute_3d_gabor_noise_cell(const float3 cell, const float3 position, const float frequency, const float isotropy, const float3 base_orientation)
Definition noise.cc:2445
static float3 hash_int4_to_float3(int4 k)
Definition noise.cc:359
static float2 compute_2d_gabor_kernel(const float2 position, const float frequency, const float orientation)
Definition noise.cc:2256
VoronoiOutput fractal_voronoi_x_fx(const VoronoiParams &params, const T coord, const bool calc_color)
Definition noise.cc:2078
float voronoi_distance(const float a, const float b)
Definition noise.cc:1166
static float2 compute_3d_gabor_kernel(const float3 position, const float frequency, const float3 orientation)
Definition noise.cc:2388
@ NOISE_SHD_PERLIN_MULTIFRACTAL
Definition noise.cc:844
@ NOISE_SHD_PERLIN_FBM
Definition noise.cc:845
@ NOISE_SHD_PERLIN_RIDGED_MULTIFRACTAL
Definition noise.cc:847
@ NOISE_SHD_PERLIN_HYBRID_MULTIFRACTAL
Definition noise.cc:846
@ NOISE_SHD_PERLIN_HETERO_TERRAIN
Definition noise.cc:848
template float perlin_fractal_distorted< float4 >(float4 position, float detail, float roughness, float lacunarity, float offset, float gain, float distortion, int type, bool normalize)
BLI_INLINE float2 random_float2_offset(float seed)
Definition noise.cc:895
float perlin_fbm(T p, float detail, float roughness, float lacunarity, bool normalize)
Definition noise.cc:696
VoronoiOutput voronoi_f2(const VoronoiParams &params, const float coord)
Definition noise.cc:1318
float3 hash_float_to_float3(float k)
Definition noise.cc:292
uint32_t hash(uint32_t kx)
Definition noise.cc:90
template VoronoiOutput fractal_voronoi_x_fx< float >(const VoronoiParams &params, const float coord, const bool calc_color)
template float perlin_fbm< float2 >(float2 p, const float detail, const float roughness, const float lacunarity, const bool normalize)
@ NOISE_SHD_VORONOI_N_SPHERE_RADIUS
Definition noise.cc:1161
@ NOISE_SHD_VORONOI_SMOOTH_F1
Definition noise.cc:1159
@ NOISE_SHD_VORONOI_F2
Definition noise.cc:1158
@ NOISE_SHD_VORONOI_DISTANCE_TO_EDGE
Definition noise.cc:1160
@ NOISE_SHD_VORONOI_F1
Definition noise.cc:1157
BLI_INLINE float4 random_float4_offset(float seed)
Definition noise.cc:908
BLI_INLINE float perlin_noise(float position)
Definition noise.cc:512
static ATTR_NO_SIGNED_INT_OVERFLOW int3 hash_pcg3d_i(int3 v)
Definition noise.cc:172
float fractal_voronoi_distance_to_edge(const VoronoiParams &params, const T coord)
Definition noise.cc:2137
BLI_INLINE void hash_bit_final(uint32_t &a, uint32_t &b, uint32_t &c)
Definition noise.cc:72
float4 hash_float_to_float4(float4 k)
Definition noise.cc:320
float perlin_hybrid_multi_fractal(T p, const float detail, const float roughness, const float lacunarity, const float offset, const float gain)
Definition noise.cc:784
static float compute_2d_gabor_standard_deviation()
Definition noise.cc:2307
float perlin_select(T p, float detail, float roughness, float lacunarity, float offset, float gain, int type, bool normalize)
Definition noise.cc:852
BLI_INLINE float noise_grad(uint32_t hash, float x)
Definition noise.cc:472
VoronoiOutput voronoi_f1(const VoronoiParams &params, const float coord)
Definition noise.cc:1253
float perlin_multi_fractal(T p, const float detail, const float roughness, const float lacunarity)
Definition noise.cc:738
template float fractal_voronoi_distance_to_edge< float3 >(const VoronoiParams &params, const float3 coord)
static constexpr int gabor_impulses_count
Definition noise.cc:2229
static T mix(T v0, T v1, float x)
Definition noise.cc:377
float perlin_fractal_distorted(T position, float detail, float roughness, float lacunarity, float offset, float gain, float distortion, int type, bool normalize)
Definition noise.cc:947
static ATTR_NO_SIGNED_INT_OVERFLOW int2 hash_pcg2d_i(int2 v)
Definition noise.cc:160
template float perlin_fractal_distorted< float3 >(float3 position, float detail, float roughness, float lacunarity, float offset, float gain, float distortion, int type, bool normalize)
template VoronoiOutput fractal_voronoi_x_fx< float2 >(const VoronoiParams &params, const float2 coord, const bool calc_color)
template float fractal_voronoi_distance_to_edge< float4 >(const VoronoiParams &params, const float4 coord)
BLI_INLINE uint32_t hash_bit_rotate(uint32_t x, uint32_t k)
Definition noise.cc:45
float perlin_hetero_terrain(T p, const float detail, const float roughness, const float lacunarity, const float offset)
Definition noise.cc:758
float2 hash_float_to_float2(float2 k)
Definition noise.cc:275
static float3 compute_3d_orientation(const float3 orientation, const float isotropy, const float4 seed)
Definition noise.cc:2417
float hash_to_float(uint32_t kx)
Definition noise.cc:233
template float fractal_voronoi_distance_to_edge< float2 >(const VoronoiParams &params, const float2 coord)
VecBase< int32_t, 4 > int4
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
#define ATTR_NO_SIGNED_INT_OVERFLOW
Definition noise.cc:34
#define hash
Definition noise_c.cc:154
#define mix
#define floorf
#define fabsf
#define ceilf
#define FLT_MAX
Definition stdcycles.h:14
VecBase< T, 3 > xyz() const
i
Definition text_draw.cc:230