diff --git a/intern/cycles/kernel/osl/shaders/node_noise.h b/intern/cycles/kernel/osl/shaders/node_noise.h index 0f8912d7bf1..21d5f0fd28e 100644 --- a/intern/cycles/kernel/osl/shaders/node_noise.h +++ b/intern/cycles/kernel/osl/shaders/node_noise.h @@ -7,76 +7,82 @@ #define vector3 point -float safe_noise(float p) +float safe_noise(float co) { - float f = noise("noise", p); - if (isinf(f)) { - return 0.5; - } - return f; + /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point + * representation issues. */ + float p = fmod(co, 100000.0); + + return noise("noise", p); } -float safe_noise(vector2 p) +float safe_noise(vector2 co) { - float f = noise("noise", p.x, p.y); - if (isinf(f)) { - return 0.5; - } - return f; + /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point + * representation issues. This causes discontinuities every 100000.0, however at such scales this + * usually shouldn't be noticeable. */ + vector2 p = fmod(co, 100000.0); + + return noise("noise", p.x, p.y); } -float safe_noise(vector3 p) +float safe_noise(vector3 co) { - float f = noise("noise", p); - if (isinf(f)) { - return 0.5; - } - return f; + /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point + * representation issues. This causes discontinuities every 100000.0, however at such scales this + * usually shouldn't be noticeable. */ + vector3 p = fmod(co, 100000.0); + + return noise("noise", p); } -float safe_noise(vector4 p) +float safe_noise(vector4 co) { - float f = noise("noise", vector3(p.x, p.y, p.z), p.w); - if (isinf(f)) { - return 0.5; - } - return f; + /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point + * representation issues. This causes discontinuities every 100000.0, however at such scales this + * usually shouldn't be noticeable. */ + vector4 p = fmod(co, 100000.0); + + return noise("noise", vector3(p.x, p.y, p.z), p.w); } -float safe_snoise(float p) +float safe_snoise(float co) { - float f = noise("snoise", p); - if (isinf(f)) { - return 0.0; - } - return f; + /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point + * representation issues. */ + float p = fmod(co, 100000.0); + + return noise("snoise", p); } -float safe_snoise(vector2 p) +float safe_snoise(vector2 co) { - float f = noise("snoise", p.x, p.y); - if (isinf(f)) { - return 0.0; - } - return f; + /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point + * representation issues. This causes discontinuities every 100000.0, however at such scales this + * usually shouldn't be noticeable. */ + vector2 p = fmod(co, 100000.0); + + return noise("snoise", p.x, p.y); } -float safe_snoise(vector3 p) +float safe_snoise(vector3 co) { - float f = noise("snoise", p); - if (isinf(f)) { - return 0.0; - } - return f; + /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point + * representation issues. This causes discontinuities every 100000.0, however at such scales this + * usually shouldn't be noticeable. */ + vector3 p = fmod(co, 100000.0); + + return noise("snoise", p); } -float safe_snoise(vector4 p) +float safe_snoise(vector4 co) { - float f = noise("snoise", vector3(p.x, p.y, p.z), p.w); - if (isinf(f)) { - return 0.0; - } - return f; + /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point + * representation issues. This causes discontinuities every 100000.0, however at such scales this + * usually shouldn't be noticeable. */ + vector4 p = fmod(co, 100000.0); + + return noise("snoise", vector3(p.x, p.y, p.z), p.w); } #define NOISE_FBM(T) \ diff --git a/intern/cycles/kernel/svm/noise.h b/intern/cycles/kernel/svm/noise.h index 4a2d7a474df..cb6355a558a 100644 --- a/intern/cycles/kernel/svm/noise.h +++ b/intern/cycles/kernel/svm/noise.h @@ -684,7 +684,12 @@ ccl_device_inline float noise_scale4(float result) ccl_device_inline float snoise_1d(float p) { - return noise_scale1(ensure_finite(perlin_1d(p))); + /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point + * representation issues. */ + /* The 1D variant of fmod is called fmodf. */ + p = fmodf(p, 100000.0f); + + return noise_scale1(perlin_1d(p)); } ccl_device_inline float noise_1d(float p) @@ -694,7 +699,12 @@ ccl_device_inline float noise_1d(float p) ccl_device_inline float snoise_2d(float2 p) { - return noise_scale2(ensure_finite(perlin_2d(p.x, p.y))); + /* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point + * representation issues. This causes discontinuities every 100000.0f, however at such scales + * this usually shouldn't be noticeable. */ + p = fmod(p, 100000.0f); + + return noise_scale2(perlin_2d(p.x, p.y)); } ccl_device_inline float noise_2d(float2 p) @@ -704,7 +714,12 @@ ccl_device_inline float noise_2d(float2 p) ccl_device_inline float snoise_3d(float3 p) { - return noise_scale3(ensure_finite(perlin_3d(p.x, p.y, p.z))); + /* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point + * representation issues. This causes discontinuities every 100000.0f, however at such scales + * this usually shouldn't be noticeable. */ + p = fmod(p, 100000.0f); + + return noise_scale3(perlin_3d(p.x, p.y, p.z)); } ccl_device_inline float noise_3d(float3 p) @@ -714,7 +729,12 @@ ccl_device_inline float noise_3d(float3 p) ccl_device_inline float snoise_4d(float4 p) { - return noise_scale4(ensure_finite(perlin_4d(p.x, p.y, p.z, p.w))); + /* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point + * representation issues. This causes discontinuities every 100000.0f, however at such scales + * this usually shouldn't be noticeable. */ + p = fmod(p, 100000.0f); + + return noise_scale4(perlin_4d(p.x, p.y, p.z, p.w)); } ccl_device_inline float noise_4d(float4 p) diff --git a/intern/cycles/util/math_float2.h b/intern/cycles/util/math_float2.h index 95337a082e6..d1aaab3b461 100644 --- a/intern/cycles/util/math_float2.h +++ b/intern/cycles/util/math_float2.h @@ -198,6 +198,11 @@ ccl_device_inline float2 clamp(const float2 a, const float2 mn, const float2 mx) return min(max(a, mn), mx); } +ccl_device_inline float2 fmod(const float2 a, const float b) +{ + return make_float2(fmodf(a.x, b), fmodf(a.y, b)); +} + ccl_device_inline float2 fabs(const float2 a) { return make_float2(fabsf(a.x), fabsf(a.y)); diff --git a/intern/cycles/util/math_float3.h b/intern/cycles/util/math_float3.h index fd3dc0d71aa..81943900ad7 100644 --- a/intern/cycles/util/math_float3.h +++ b/intern/cycles/util/math_float3.h @@ -309,6 +309,11 @@ ccl_device_inline float3 fabs(const float3 a) # endif } +ccl_device_inline float3 fmod(const float3 a, const float b) +{ + return make_float3(fmodf(a.x, b), fmodf(a.y, b), fmodf(a.z, b)); +} + ccl_device_inline float3 sqrt(const float3 a) { # ifdef __KERNEL_SSE__ diff --git a/intern/cycles/util/math_float4.h b/intern/cycles/util/math_float4.h index 369b5fef3c2..9921f718beb 100644 --- a/intern/cycles/util/math_float4.h +++ b/intern/cycles/util/math_float4.h @@ -465,6 +465,11 @@ ccl_device_inline float4 fabs(const float4 a) # endif } +ccl_device_inline float4 fmod(const float4 a, const float b) +{ + return make_float4(fmodf(a.x, b), fmodf(a.y, b), fmodf(a.z, b), fmodf(a.w, b)); +} + ccl_device_inline float4 floor(const float4 a) { # ifdef __KERNEL_SSE__ diff --git a/source/blender/blenlib/intern/noise.cc b/source/blender/blenlib/intern/noise.cc index 1c03f7d7cc8..c0403191ad8 100644 --- a/source/blender/blenlib/intern/noise.cc +++ b/source/blender/blenlib/intern/noise.cc @@ -490,21 +490,40 @@ BLI_INLINE float perlin_noise(float4 position) float perlin_signed(float position) { + /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point + * representation issues. */ + position = math::mod(position, 100000.0f); + return perlin_noise(position) * 0.2500f; } float perlin_signed(float2 position) { + /* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point + * representation issues. This causes discontinuities every 100000.0f, however at such scales + * this usually shouldn't be noticeable. */ + position = math::mod(position, 100000.0f); + return perlin_noise(position) * 0.6616f; } float perlin_signed(float3 position) { + /* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point + * representation issues. This causes discontinuities every 100000.0f, however at such scales + * this usually shouldn't be noticeable. */ + position = math::mod(position, 100000.0f); + return perlin_noise(position) * 0.9820f; } float perlin_signed(float4 position) { + /* Repeat Perlin noise texture every 100000.0f on each axis to prevent floating point + * representation issues. This causes discontinuities every 100000.0f, however at such scales + * this usually shouldn't be noticeable. */ + position = math::mod(position, 100000.0f); + return perlin_noise(position) * 0.8344f; } diff --git a/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl index f697ef1be2e..8fb15b38e5b 100644 --- a/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl +++ b/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl @@ -24,6 +24,24 @@ float compatible_fmod(float a, float b) return 0.0; } +vec2 compatible_fmod(vec2 a, float b) +{ + return vec2(compatible_fmod(a.x, b), compatible_fmod(a.y, b)); +} + +vec3 compatible_fmod(vec3 a, float b) +{ + return vec3(compatible_fmod(a.x, b), compatible_fmod(a.y, b), compatible_fmod(a.z, b)); +} + +vec4 compatible_fmod(vec4 a, float b) +{ + return vec4(compatible_fmod(a.x, b), + compatible_fmod(a.y, b), + compatible_fmod(a.z, b), + compatible_fmod(a.w, b)); +} + float compatible_pow(float x, float y) { if (y == 0.0) { /* x^0 -> 1, including 0^0 */ diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl index 7facf282913..9cb201c0017 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl @@ -2,6 +2,7 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ +#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl) #pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl) /* clang-format off */ @@ -260,8 +261,11 @@ float noise_scale4(float result) float snoise(float p) { - float r = noise_perlin(p); - return (isinf(r)) ? 0.0 : noise_scale1(r); + /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point + * representation issues. */ + p = compatible_fmod(p, 100000.0); + + return noise_scale1(noise_perlin(p)); } float noise(float p) @@ -271,8 +275,12 @@ float noise(float p) float snoise(vec2 p) { - float r = noise_perlin(p); - return (isinf(r)) ? 0.0 : noise_scale2(r); + /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point + * representation issues. This causes discontinuities every 100000.0, however at such scales this + * usually shouldn't be noticeable. */ + p = compatible_fmod(p, 100000.0); + + return noise_scale2(noise_perlin(p)); } float noise(vec2 p) @@ -282,8 +290,12 @@ float noise(vec2 p) float snoise(vec3 p) { - float r = noise_perlin(p); - return (isinf(r)) ? 0.0 : noise_scale3(r); + /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point + * representation issues. This causes discontinuities every 100000.0, however at such scales this + * usually shouldn't be noticeable. */ + p = compatible_fmod(p, 100000.0); + + return noise_scale3(noise_perlin(p)); } float noise(vec3 p) @@ -293,8 +305,12 @@ float noise(vec3 p) float snoise(vec4 p) { - float r = noise_perlin(p); - return (isinf(r)) ? 0.0 : noise_scale4(r); + /* Repeat Perlin noise texture every 100000.0 on each axis to prevent floating point + * representation issues. This causes discontinuities every 100000.0, however at such scales this + * usually shouldn't be noticeable. */ + p = compatible_fmod(p, 100000.0); + + return noise_scale4(noise_perlin(p)); } float noise(vec4 p)