BLI: Add Cycles compatible Perlin noise

This patch adds new Perlin noise functions to BLI. The noises are compatible
with the shading texture noises in EEVEE, SVM, and OSL.

The existing Jenkins hash functions couldn't be used because they are not
compatible with the shading implementations and an attempt at adjusting the
implementation will break compatibility in various areas of Blender. So the
simplest approach is to reimplement the relevant hashing functions inside the
noise module itself.

Additionally, this patch also adds a minimal float4 structure to use in the
interface of the noise functions.

Reviewed By: JacquesLucke

Differential Revision: https://developer.blender.org/D12443
This commit is contained in:
Omar Emara 2021-09-10 14:25:32 +02:00
parent 60cfdf0809
commit a1167e910a
Notes: blender-bot 2023-02-14 08:06:35 +01:00
Referenced by issue #91226, Implement Cycles compatible perlin noise in blenlib
4 changed files with 854 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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