Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenlib/BLI_float4.hh86
-rw-r--r--source/blender/blenlib/BLI_noise.hh72
-rw-r--r--source/blender/blenlib/CMakeLists.txt3
-rw-r--r--source/blender/blenlib/intern/noise.cc693
4 files changed, 854 insertions, 0 deletions
diff --git a/source/blender/blenlib/BLI_float4.hh b/source/blender/blenlib/BLI_float4.hh
new file mode 100644
index 00000000000..b1feee3121b
--- /dev/null
+++ b/source/blender/blenlib/BLI_float4.hh
@@ -0,0 +1,86 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+namespace blender {
+
+struct float4 {
+ float x, y, z, w;
+
+ float4() = default;
+
+ float4(const float *ptr) : x{ptr[0]}, y{ptr[1]}, z{ptr[2]}, w{ptr[3]}
+ {
+ }
+
+ explicit float4(float value) : x(value), y(value), z(value), w(value)
+ {
+ }
+
+ explicit float4(int value) : x(value), y(value), z(value), w(value)
+ {
+ }
+
+ float4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w)
+ {
+ }
+
+ operator float *()
+ {
+ return &x;
+ }
+
+ operator const float *() const
+ {
+ return &x;
+ }
+
+ float4 &operator+=(const float4 &other)
+ {
+ x += other.x;
+ y += other.y;
+ z += other.z;
+ w += other.w;
+ return *this;
+ }
+
+ friend float4 operator+(const float4 &a, const float4 &b)
+ {
+ return {a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w};
+ }
+
+ float4 &operator*=(float factor)
+ {
+ x *= factor;
+ y *= factor;
+ z *= factor;
+ w *= factor;
+ return *this;
+ }
+
+ friend float4 operator*(const float4 &a, float b)
+ {
+ return {a.x * b, a.y * b, a.z * b, a.w * b};
+ }
+
+ friend float4 operator*(float a, const float4 &b)
+ {
+ return b * a;
+ }
+};
+
+} // namespace blender
diff --git a/source/blender/blenlib/BLI_noise.hh b/source/blender/blenlib/BLI_noise.hh
new file mode 100644
index 00000000000..760ff082d06
--- /dev/null
+++ b/source/blender/blenlib/BLI_noise.hh
@@ -0,0 +1,72 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include "BLI_float2.hh"
+#include "BLI_float3.hh"
+#include "BLI_float4.hh"
+
+namespace blender::noise {
+
+/* Perlin noise in the range [-1, 1]. */
+
+float perlin_signed(float position);
+float perlin_signed(float2 position);
+float perlin_signed(float3 position);
+float perlin_signed(float4 position);
+
+/* Perlin noise in the range [0, 1]. */
+
+float perlin(float position);
+float perlin(float2 position);
+float perlin(float3 position);
+float perlin(float4 position);
+
+/* Fractal perlin noise in the range [0, 1]. */
+
+float perlin_fractal(float position, float octaves, float roughness);
+float perlin_fractal(float2 position, float octaves, float roughness);
+float perlin_fractal(float3 position, float octaves, float roughness);
+float perlin_fractal(float4 position, float octaves, float roughness);
+
+/* Positive distorted fractal perlin noise. */
+
+float perlin_fractal_distorted(float position, float octaves, float roughness, float distortion);
+float perlin_fractal_distorted(float2 position, float octaves, float roughness, float distortion);
+float perlin_fractal_distorted(float3 position, float octaves, float roughness, float distortion);
+float perlin_fractal_distorted(float4 position, float octaves, float roughness, float distortion);
+
+/* Positive distorted fractal perlin noise that outputs a float3. */
+
+float3 perlin_float3_fractal_distorted(float position,
+ float octaves,
+ float roughness,
+ float distortion);
+float3 perlin_float3_fractal_distorted(float2 position,
+ float octaves,
+ float roughness,
+ float distortion);
+float3 perlin_float3_fractal_distorted(float3 position,
+ float octaves,
+ float roughness,
+ float distortion);
+float3 perlin_float3_fractal_distorted(float4 position,
+ float octaves,
+ float roughness,
+ float distortion);
+
+} // namespace blender::noise
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 24178535068..fc058793d11 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -116,6 +116,7 @@ set(SRC
intern/mesh_boolean.cc
intern/mesh_intersect.cc
intern/noise.c
+ intern/noise.cc
intern/path_util.c
intern/polyfill_2d.c
intern/polyfill_2d_beautify.c
@@ -203,6 +204,7 @@ set(SRC
BLI_filereader.h
BLI_float2.hh
BLI_float3.hh
+ BLI_float4.hh
BLI_float4x4.hh
BLI_fnmatch.h
BLI_function_ref.hh
@@ -264,6 +266,7 @@ set(SRC
BLI_mpq3.hh
BLI_multi_value_map.hh
BLI_noise.h
+ BLI_noise.hh
BLI_path_util.h
BLI_polyfill_2d.h
BLI_polyfill_2d_beautify.h
diff --git a/source/blender/blenlib/intern/noise.cc b/source/blender/blenlib/intern/noise.cc
new file mode 100644
index 00000000000..c057c12e543
--- /dev/null
+++ b/source/blender/blenlib/intern/noise.cc
@@ -0,0 +1,693 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <cmath>
+#include <cstdint>
+
+#include "BLI_float2.hh"
+#include "BLI_float3.hh"
+#include "BLI_float4.hh"
+#include "BLI_noise.hh"
+#include "BLI_utildefines.h"
+
+namespace blender::noise {
+/* ------------------------------
+ * Jenkins Lookup3 Hash Functions
+ * ------------------------------
+ *
+ * https://burtleburtle.net/bob/c/lookup3.c
+ *
+ */
+
+BLI_INLINE uint32_t hash_bit_rotate(uint32_t x, uint32_t k)
+{
+ return (x << k) | (x >> (32 - k));
+}
+
+BLI_INLINE void hash_bit_mix(uint32_t &a, uint32_t &b, uint32_t &c)
+{
+ a -= c;
+ a ^= hash_bit_rotate(c, 4);
+ c += b;
+ b -= a;
+ b ^= hash_bit_rotate(a, 6);
+ a += c;
+ c -= b;
+ c ^= hash_bit_rotate(b, 8);
+ b += a;
+ a -= c;
+ a ^= hash_bit_rotate(c, 16);
+ c += b;
+ b -= a;
+ b ^= hash_bit_rotate(a, 19);
+ a += c;
+ c -= b;
+ c ^= hash_bit_rotate(b, 4);
+ b += a;
+}
+
+BLI_INLINE void hash_bit_final(uint32_t &a, uint32_t &b, uint32_t &c)
+{
+ c ^= b;
+ c -= hash_bit_rotate(b, 14);
+ a ^= c;
+ a -= hash_bit_rotate(c, 11);
+ b ^= a;
+ b -= hash_bit_rotate(a, 25);
+ c ^= b;
+ c -= hash_bit_rotate(b, 16);
+ a ^= c;
+ a -= hash_bit_rotate(c, 4);
+ b ^= a;
+ b -= hash_bit_rotate(a, 14);
+ c ^= b;
+ c -= hash_bit_rotate(b, 24);
+}
+
+BLI_INLINE uint32_t hash(uint32_t kx)
+{
+ uint32_t a, b, c;
+ a = b = c = 0xdeadbeef + (1 << 2) + 13;
+
+ a += kx;
+ hash_bit_final(a, b, c);
+
+ return c;
+}
+
+BLI_INLINE uint32_t hash(uint32_t kx, uint32_t ky)
+{
+ uint32_t a, b, c;
+ a = b = c = 0xdeadbeef + (2 << 2) + 13;
+
+ b += ky;
+ a += kx;
+ hash_bit_final(a, b, c);
+
+ return c;
+}
+
+BLI_INLINE uint32_t hash(uint32_t kx, uint32_t ky, uint32_t kz)
+{
+ uint32_t a, b, c;
+ a = b = c = 0xdeadbeef + (3 << 2) + 13;
+
+ c += kz;
+ b += ky;
+ a += kx;
+ hash_bit_final(a, b, c);
+
+ return c;
+}
+
+BLI_INLINE uint32_t hash(uint32_t kx, uint32_t ky, uint32_t kz, uint32_t kw)
+{
+ uint32_t a, b, c;
+ a = b = c = 0xdeadbeef + (4 << 2) + 13;
+
+ a += kx;
+ b += ky;
+ c += kz;
+ hash_bit_mix(a, b, c);
+
+ a += kw;
+ hash_bit_final(a, b, c);
+
+ return c;
+}
+
+/* Hashing a number of uint32_t into a float in the range [0, 1]. */
+
+BLI_INLINE float hash_to_float(uint32_t kx)
+{
+ return static_cast<float>(hash(kx)) / static_cast<float>(0xFFFFFFFFu);
+}
+
+BLI_INLINE float hash_to_float(uint32_t kx, uint32_t ky)
+{
+ return static_cast<float>(hash(kx, ky)) / static_cast<float>(0xFFFFFFFFu);
+}
+
+BLI_INLINE float hash_to_float(uint32_t kx, uint32_t ky, uint32_t kz)
+{
+ return static_cast<float>(hash(kx, ky, kz)) / static_cast<float>(0xFFFFFFFFu);
+}
+
+BLI_INLINE float hash_to_float(uint32_t kx, uint32_t ky, uint32_t kz, uint32_t kw)
+{
+ return static_cast<float>(hash(kx, ky, kz, kw)) / static_cast<float>(0xFFFFFFFFu);
+}
+
+/* Hashing a number of floats into a float in the range [0, 1]. */
+
+BLI_INLINE uint32_t float_as_uint(float f)
+{
+ union {
+ uint32_t i;
+ float f;
+ } u;
+ u.f = f;
+ return u.i;
+}
+
+BLI_INLINE float hash_to_float(float k)
+{
+ return hash_to_float(float_as_uint(k));
+}
+
+BLI_INLINE float hash_to_float(float2 k)
+{
+ return hash_to_float(float_as_uint(k.x), float_as_uint(k.y));
+}
+
+BLI_INLINE float hash_to_float(float3 k)
+{
+ return hash_to_float(float_as_uint(k.x), float_as_uint(k.y), float_as_uint(k.z));
+}
+
+BLI_INLINE float hash_to_float(float4 k)
+{
+ return hash_to_float(
+ float_as_uint(k.x), float_as_uint(k.y), float_as_uint(k.z), float_as_uint(k.w));
+}
+
+/* ------------
+ * Perlin Noise
+ * ------------
+ *
+ * Perlin, Ken. "Improving noise." Proceedings of the 29th annual conference on Computer graphics
+ * and interactive techniques. 2002.
+ *
+ * This implementation is functionally identical to the implementations in EEVEE, OSL, and SVM. So
+ * any changes should be applied in all relevant implementations.
+ */
+
+/* Linear Interpolation. */
+BLI_INLINE float mix(float v0, float v1, float x)
+{
+ return (1 - x) * v0 + x * v1;
+}
+
+/* Bilinear Interpolation:
+ *
+ * v2 v3
+ * @ + + + + @ y
+ * + + ^
+ * + + |
+ * + + |
+ * @ + + + + @ @------> x
+ * v0 v1
+ *
+ */
+BLI_INLINE float mix(float v0, float v1, float v2, float v3, float x, float y)
+{
+ float x1 = 1.0 - x;
+ return (1.0 - y) * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x);
+}
+
+/* Trilinear Interpolation:
+ *
+ * v6 v7
+ * @ + + + + + + @
+ * +\ +\
+ * + \ + \
+ * + \ + \
+ * + \ v4 + \ v5
+ * + @ + + + +++ + @ z
+ * + + + + y ^
+ * v2 @ + +++ + + + @ v3 + \ |
+ * \ + \ + \ |
+ * \ + \ + \|
+ * \ + \ + +---------> x
+ * \+ \+
+ * @ + + + + + + @
+ * v0 v1
+ */
+BLI_INLINE float mix(float v0,
+ float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6,
+ float v7,
+ float x,
+ float y,
+ float z)
+{
+ float x1 = 1.0 - x;
+ float y1 = 1.0 - y;
+ float z1 = 1.0 - z;
+ return z1 * (y1 * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x)) +
+ z * (y1 * (v4 * x1 + v5 * x) + y * (v6 * x1 + v7 * x));
+}
+
+/* Quadrilinear Interpolation. */
+BLI_INLINE float mix(float v0,
+ float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6,
+ float v7,
+ float v8,
+ float v9,
+ float v10,
+ float v11,
+ float v12,
+ float v13,
+ float v14,
+ float v15,
+ float x,
+ float y,
+ float z,
+ float w)
+{
+ return mix(mix(v0, v1, v2, v3, v4, v5, v6, v7, x, y, z),
+ mix(v8, v9, v10, v11, v12, v13, v14, v15, x, y, z),
+ w);
+}
+
+BLI_INLINE float fade(float t)
+{
+ return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
+}
+
+BLI_INLINE float negate_if(float value, uint32_t condition)
+{
+ return (condition != 0u) ? -value : value;
+}
+
+BLI_INLINE float noise_grad(uint32_t hash, float x)
+{
+ uint32_t h = hash & 15u;
+ float g = 1u + (h & 7u);
+ return negate_if(g, h & 8u) * x;
+}
+
+BLI_INLINE float noise_grad(uint32_t hash, float x, float y)
+{
+ uint32_t h = hash & 7u;
+ float u = h < 4u ? x : y;
+ float v = 2.0 * (h < 4u ? y : x);
+ return negate_if(u, h & 1u) + negate_if(v, h & 2u);
+}
+
+BLI_INLINE float noise_grad(uint32_t hash, float x, float y, float z)
+{
+ uint32_t h = hash & 15u;
+ float u = h < 8u ? x : y;
+ float vt = ((h == 12u) || (h == 14u)) ? x : z;
+ float v = h < 4u ? y : vt;
+ return negate_if(u, h & 1u) + negate_if(v, h & 2u);
+}
+
+BLI_INLINE float noise_grad(uint32_t hash, float x, float y, float z, float w)
+{
+ uint32_t h = hash & 31u;
+ float u = h < 24u ? x : y;
+ float v = h < 16u ? y : z;
+ float s = h < 8u ? z : w;
+ return negate_if(u, h & 1u) + negate_if(v, h & 2u) + negate_if(s, h & 4u);
+}
+
+BLI_INLINE float floor_fraction(float x, int &i)
+{
+ i = (int)x - ((x < 0) ? 1 : 0);
+ return x - i;
+}
+
+BLI_INLINE float perlin_noise(float position)
+{
+ int X;
+
+ float fx = floor_fraction(position, X);
+
+ float u = fade(fx);
+
+ float r = mix(noise_grad(hash(X), fx), noise_grad(hash(X + 1), fx - 1.0), u);
+
+ return r;
+}
+
+BLI_INLINE float perlin_noise(float2 position)
+{
+ int X, Y;
+
+ float fx = floor_fraction(position.x, X);
+ float fy = floor_fraction(position.y, Y);
+
+ float u = fade(fx);
+ float v = fade(fy);
+
+ float r = mix(noise_grad(hash(X, Y), fx, fy),
+ noise_grad(hash(X + 1, Y), fx - 1.0, fy),
+ noise_grad(hash(X, Y + 1), fx, fy - 1.0),
+ noise_grad(hash(X + 1, Y + 1), fx - 1.0, fy - 1.0),
+ u,
+ v);
+
+ return r;
+}
+
+BLI_INLINE float perlin_noise(float3 position)
+{
+ int X, Y, Z;
+
+ float fx = floor_fraction(position.x, X);
+ float fy = floor_fraction(position.y, Y);
+ float fz = floor_fraction(position.z, Z);
+
+ float u = fade(fx);
+ float v = fade(fy);
+ float w = fade(fz);
+
+ float r = mix(noise_grad(hash(X, Y, Z), fx, fy, fz),
+ noise_grad(hash(X + 1, Y, Z), fx - 1, fy, fz),
+ noise_grad(hash(X, Y + 1, Z), fx, fy - 1, fz),
+ noise_grad(hash(X + 1, Y + 1, Z), fx - 1, fy - 1, fz),
+ noise_grad(hash(X, Y, Z + 1), fx, fy, fz - 1),
+ noise_grad(hash(X + 1, Y, Z + 1), fx - 1, fy, fz - 1),
+ noise_grad(hash(X, Y + 1, Z + 1), fx, fy - 1, fz - 1),
+ noise_grad(hash(X + 1, Y + 1, Z + 1), fx - 1, fy - 1, fz - 1),
+ u,
+ v,
+ w);
+
+ return r;
+}
+
+BLI_INLINE float perlin_noise(float4 position)
+{
+ int X, Y, Z, W;
+
+ float fx = floor_fraction(position.x, X);
+ float fy = floor_fraction(position.y, Y);
+ float fz = floor_fraction(position.z, Z);
+ float fw = floor_fraction(position.w, W);
+
+ float u = fade(fx);
+ float v = fade(fy);
+ float t = fade(fz);
+ float s = fade(fw);
+
+ float r = mix(
+ noise_grad(hash(X, Y, Z, W), fx, fy, fz, fw),
+ noise_grad(hash(X + 1, Y, Z, W), fx - 1.0, fy, fz, fw),
+ noise_grad(hash(X, Y + 1, Z, W), fx, fy - 1.0, fz, fw),
+ noise_grad(hash(X + 1, Y + 1, Z, W), fx - 1.0, fy - 1.0, fz, fw),
+ noise_grad(hash(X, Y, Z + 1, W), fx, fy, fz - 1.0, fw),
+ noise_grad(hash(X + 1, Y, Z + 1, W), fx - 1.0, fy, fz - 1.0, fw),
+ noise_grad(hash(X, Y + 1, Z + 1, W), fx, fy - 1.0, fz - 1.0, fw),
+ noise_grad(hash(X + 1, Y + 1, Z + 1, W), fx - 1.0, fy - 1.0, fz - 1.0, fw),
+ noise_grad(hash(X, Y, Z, W + 1), fx, fy, fz, fw - 1.0),
+ noise_grad(hash(X + 1, Y, Z, W + 1), fx - 1.0, fy, fz, fw - 1.0),
+ noise_grad(hash(X, Y + 1, Z, W + 1), fx, fy - 1.0, fz, fw - 1.0),
+ noise_grad(hash(X + 1, Y + 1, Z, W + 1), fx - 1.0, fy - 1.0, fz, fw - 1.0),
+ noise_grad(hash(X, Y, Z + 1, W + 1), fx, fy, fz - 1.0, fw - 1.0),
+ noise_grad(hash(X + 1, Y, Z + 1, W + 1), fx - 1.0, fy, fz - 1.0, fw - 1.0),
+ noise_grad(hash(X, Y + 1, Z + 1, W + 1), fx, fy - 1.0, fz - 1.0, fw - 1.0),
+ noise_grad(hash(X + 1, Y + 1, Z + 1, W + 1), fx - 1.0, fy - 1.0, fz - 1.0, fw - 1.0),
+ u,
+ v,
+ t,
+ s);
+
+ return r;
+}
+
+/* Signed versions of perlin noise in the range [-1, 1]. The scale values were computed
+ * experimentally by the OSL developers to remap the noise output to the correct range. */
+
+float perlin_signed(float position)
+{
+ return perlin_noise(position) * 0.2500f;
+}
+
+float perlin_signed(float2 position)
+{
+ return perlin_noise(position) * 0.6616f;
+}
+
+float perlin_signed(float3 position)
+{
+ return perlin_noise(position) * 0.9820f;
+}
+
+float perlin_signed(float4 position)
+{
+ return perlin_noise(position) * 0.8344f;
+}
+
+/* Positive versions of perlin noise in the range [0, 1]. */
+
+float perlin(float position)
+{
+ return perlin_signed(position) / 2.0f + 0.5f;
+}
+
+float perlin(float2 position)
+{
+ return perlin_signed(position) / 2.0f + 0.5f;
+}
+
+float perlin(float3 position)
+{
+ return perlin_signed(position) / 2.0f + 0.5f;
+}
+
+float perlin(float4 position)
+{
+ return perlin_signed(position) / 2.0f + 0.5f;
+}
+
+/* Positive fractal perlin noise. */
+
+template<typename T> float perlin_fractal_template(T position, float octaves, float roughness)
+{
+ float fscale = 1.0f;
+ float amp = 1.0f;
+ float maxamp = 0.0f;
+ float sum = 0.0f;
+ octaves = CLAMPIS(octaves, 0.0f, 16.0f);
+ int n = static_cast<int>(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = perlin(fscale * position);
+ sum += t * amp;
+ maxamp += amp;
+ amp *= CLAMPIS(roughness, 0.0f, 1.0f);
+ fscale *= 2.0f;
+ }
+ float rmd = octaves - std::floor(octaves);
+ if (rmd == 0.0f) {
+ return sum / maxamp;
+ }
+
+ float t = perlin(fscale * position);
+ float sum2 = sum + t * amp;
+ sum /= maxamp;
+ sum2 /= maxamp + amp;
+ return (1.0f - rmd) * sum + rmd * sum2;
+}
+
+float perlin_fractal(float position, float octaves, float roughness)
+{
+ return perlin_fractal_template(position, octaves, roughness);
+}
+
+float perlin_fractal(float2 position, float octaves, float roughness)
+{
+ return perlin_fractal_template(position, octaves, roughness);
+}
+
+float perlin_fractal(float3 position, float octaves, float roughness)
+{
+ return perlin_fractal_template(position, octaves, roughness);
+}
+
+float perlin_fractal(float4 position, float octaves, float roughness)
+{
+ return perlin_fractal_template(position, octaves, roughness);
+}
+
+/* The following offset functions generate random offsets to be added to
+ * positions to act as a seed since the noise functions don't have seed values.
+ * The offset's components are in the range [100, 200], not too high to cause
+ * bad precision and not too small to be noticeable. We use float seed because
+ * OSL only support float hashes and we need to maintain compatibility with it.
+ */
+
+BLI_INLINE float random_float_offset(float seed)
+{
+ return 100.0f + hash_to_float(seed) * 100.0f;
+}
+
+BLI_INLINE float2 random_float2_offset(float seed)
+{
+ return float2(100.0f + hash_to_float(float2(seed, 0.0f)) * 100.0f,
+ 100.0f + hash_to_float(float2(seed, 1.0f)) * 100.0f);
+}
+
+BLI_INLINE float3 random_float3_offset(float seed)
+{
+ return float3(100.0f + hash_to_float(float2(seed, 0.0f)) * 100.0f,
+ 100.0f + hash_to_float(float2(seed, 1.0f)) * 100.0f,
+ 100.0f + hash_to_float(float2(seed, 2.0f)) * 100.0f);
+}
+
+BLI_INLINE float4 random_float4_offset(float seed)
+{
+ return float4(100.0f + hash_to_float(float2(seed, 0.0f)) * 100.0f,
+ 100.0f + hash_to_float(float2(seed, 1.0f)) * 100.0f,
+ 100.0f + hash_to_float(float2(seed, 2.0f)) * 100.0f,
+ 100.0f + hash_to_float(float2(seed, 3.0f)) * 100.0f);
+}
+
+/* Perlin noises to be added to the position to distort other noises. */
+
+BLI_INLINE float perlin_distortion(float position, float strength)
+{
+ return perlin_signed(position + random_float_offset(0.0)) * strength;
+}
+
+BLI_INLINE float2 perlin_distortion(float2 position, float strength)
+{
+ return float2(perlin_signed(position + random_float2_offset(0.0f)) * strength,
+ perlin_signed(position + random_float2_offset(1.0f)) * strength);
+}
+
+BLI_INLINE float3 perlin_distortion(float3 position, float strength)
+{
+ return float3(perlin_signed(position + random_float3_offset(0.0f)) * strength,
+ perlin_signed(position + random_float3_offset(1.0f)) * strength,
+ perlin_signed(position + random_float3_offset(2.0f)) * strength);
+}
+
+BLI_INLINE float4 perlin_distortion(float4 position, float strength)
+{
+ return float4(perlin_signed(position + random_float4_offset(0.0f)) * strength,
+ perlin_signed(position + random_float4_offset(1.0f)) * strength,
+ perlin_signed(position + random_float4_offset(2.0f)) * strength,
+ perlin_signed(position + random_float4_offset(3.0f)) * strength);
+}
+
+/* Positive distorted fractal perlin noise. */
+
+float perlin_fractal_distorted(float position, float octaves, float roughness, float distortion)
+{
+ position += perlin_distortion(position, distortion);
+ return perlin_fractal(position, octaves, roughness);
+}
+
+float perlin_fractal_distorted(float2 position, float octaves, float roughness, float distortion)
+{
+ position += perlin_distortion(position, distortion);
+ return perlin_fractal(position, octaves, roughness);
+}
+
+float perlin_fractal_distorted(float3 position, float octaves, float roughness, float distortion)
+{
+ position += perlin_distortion(position, distortion);
+ return perlin_fractal(position, octaves, roughness);
+}
+
+float perlin_fractal_distorted(float4 position, float octaves, float roughness, float distortion)
+{
+ position += perlin_distortion(position, distortion);
+ return perlin_fractal(position, octaves, roughness);
+}
+
+/* Positive distorted fractal perlin noise that outputs a float3. The arbitrary seeds are for
+ * compatibility with shading functions. */
+
+float3 perlin_float3_fractal_distorted(float position,
+ float octaves,
+ float roughness,
+ float distortion)
+{
+ position += perlin_distortion(position, distortion);
+ return float3(perlin_fractal(position, octaves, roughness),
+ perlin_fractal(position + random_float_offset(1.0f), octaves, roughness),
+ perlin_fractal(position + random_float_offset(2.0f), octaves, roughness));
+}
+
+float3 perlin_float3_fractal_distorted(float2 position,
+ float octaves,
+ float roughness,
+ float distortion)
+{
+ position += perlin_distortion(position, distortion);
+ return float3(perlin_fractal(position, octaves, roughness),
+ perlin_fractal(position + random_float2_offset(2.0f), octaves, roughness),
+ perlin_fractal(position + random_float2_offset(3.0f), octaves, roughness));
+}
+
+float3 perlin_float3_fractal_distorted(float3 position,
+ float octaves,
+ float roughness,
+ float distortion)
+{
+ position += perlin_distortion(position, distortion);
+ return float3(perlin_fractal(position, octaves, roughness),
+ perlin_fractal(position + random_float3_offset(3.0f), octaves, roughness),
+ perlin_fractal(position + random_float3_offset(4.0f), octaves, roughness));
+}
+
+float3 perlin_float3_fractal_distorted(float4 position,
+ float octaves,
+ float roughness,
+ float distortion)
+{
+ position += perlin_distortion(position, distortion);
+ return float3(perlin_fractal(position, octaves, roughness),
+ perlin_fractal(position + random_float4_offset(4.0f), octaves, roughness),
+ perlin_fractal(position + random_float4_offset(5.0f), octaves, roughness));
+}
+
+} // namespace blender::noise