This is a follow up of the previous commit. These functions are useful for other areas of Blender as well.
718 lines
20 KiB
C++
718 lines
20 KiB
C++
/*
|
|
* 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);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
BLI_INLINE uint32_t float_as_uint(float f)
|
|
{
|
|
union {
|
|
uint32_t i;
|
|
float f;
|
|
} u;
|
|
u.f = f;
|
|
return u.i;
|
|
}
|
|
|
|
uint32_t hash_float(float kx)
|
|
{
|
|
return hash(float_as_uint(kx));
|
|
}
|
|
|
|
uint32_t hash_float(float2 k)
|
|
{
|
|
return hash(float_as_uint(k.x), float_as_uint(k.y));
|
|
}
|
|
|
|
uint32_t hash_float(float3 k)
|
|
{
|
|
return hash(float_as_uint(k.x), float_as_uint(k.y), float_as_uint(k.z));
|
|
}
|
|
|
|
uint32_t hash_float(float4 k)
|
|
{
|
|
return hash(float_as_uint(k.x), float_as_uint(k.y), float_as_uint(k.z), float_as_uint(k.w));
|
|
}
|
|
|
|
/* Hashing a number of uint32_t into a float in the range [0, 1]. */
|
|
|
|
BLI_INLINE float uint_to_float_01(uint32_t k)
|
|
{
|
|
return static_cast<float>(k) / static_cast<float>(0xFFFFFFFFu);
|
|
}
|
|
|
|
float hash_to_float(uint32_t kx)
|
|
{
|
|
return uint_to_float_01(hash(kx));
|
|
}
|
|
|
|
float hash_to_float(uint32_t kx, uint32_t ky)
|
|
{
|
|
return uint_to_float_01(hash(kx, ky));
|
|
}
|
|
|
|
float hash_to_float(uint32_t kx, uint32_t ky, uint32_t kz)
|
|
{
|
|
return uint_to_float_01(hash(kx, ky, kz));
|
|
}
|
|
|
|
float hash_to_float(uint32_t kx, uint32_t ky, uint32_t kz, uint32_t kw)
|
|
{
|
|
return uint_to_float_01(hash(kx, ky, kz, kw));
|
|
}
|
|
|
|
/* Hashing a number of floats into a float in the range [0, 1]. */
|
|
|
|
float hash_float_to_float(float k)
|
|
{
|
|
return hash_to_float(hash_float(k));
|
|
}
|
|
|
|
float hash_float_to_float(float2 k)
|
|
{
|
|
return hash_to_float(hash_float(k));
|
|
}
|
|
|
|
float hash_float_to_float(float3 k)
|
|
{
|
|
return hash_to_float(hash_float(k));
|
|
}
|
|
|
|
float hash_float_to_float(float4 k)
|
|
{
|
|
return hash_to_float(hash_float(k));
|
|
}
|
|
|
|
/* ------------
|
|
* 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_float_to_float(seed) * 100.0f;
|
|
}
|
|
|
|
BLI_INLINE float2 random_float2_offset(float seed)
|
|
{
|
|
return float2(100.0f + hash_float_to_float(float2(seed, 0.0f)) * 100.0f,
|
|
100.0f + hash_float_to_float(float2(seed, 1.0f)) * 100.0f);
|
|
}
|
|
|
|
BLI_INLINE float3 random_float3_offset(float seed)
|
|
{
|
|
return float3(100.0f + hash_float_to_float(float2(seed, 0.0f)) * 100.0f,
|
|
100.0f + hash_float_to_float(float2(seed, 1.0f)) * 100.0f,
|
|
100.0f + hash_float_to_float(float2(seed, 2.0f)) * 100.0f);
|
|
}
|
|
|
|
BLI_INLINE float4 random_float4_offset(float seed)
|
|
{
|
|
return float4(100.0f + hash_float_to_float(float2(seed, 0.0f)) * 100.0f,
|
|
100.0f + hash_float_to_float(float2(seed, 1.0f)) * 100.0f,
|
|
100.0f + hash_float_to_float(float2(seed, 2.0f)) * 100.0f,
|
|
100.0f + hash_float_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
|