diff options
37 files changed, 2419 insertions, 566 deletions
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index ca51482c98e..e81336cd692 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -798,6 +798,7 @@ static ShaderNode *add_node(Scene *scene, else if (b_node.is_a(&RNA_ShaderNodeTexNoise)) { BL::ShaderNodeTexNoise b_noise_node(b_node); NoiseTextureNode *noise = new NoiseTextureNode(); + noise->dimensions = b_noise_node.dimensions(); BL::TexMapping b_texture_mapping(b_noise_node.texture_mapping()); get_tex_mapping(&noise->tex_mapping, b_texture_mapping); node = noise; diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 48439a8b68f..89ecdc6b7ac 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -214,7 +214,7 @@ set(SRC_SVM_HEADERS svm/svm_sepcomb_vector.h svm/svm_sky.h svm/svm_tex_coord.h - svm/svm_texture.h + svm/svm_fractal_noise.h svm/svm_types.h svm/svm_value.h svm/svm_vector_transform.h diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt index c50bffe27b2..a45c43e01ed 100644 --- a/intern/cycles/kernel/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/shaders/CMakeLists.txt @@ -97,10 +97,12 @@ set(SRC_OSL set(SRC_OSL_HEADERS node_color.h node_fresnel.h + node_noise.h node_ramp_util.h - node_texture.h stdosl.h oslutil.h + vector2.h + vector4.h ) set(SRC_OSO diff --git a/intern/cycles/kernel/shaders/node_brick_texture.osl b/intern/cycles/kernel/shaders/node_brick_texture.osl index 0abc3574c48..30644ef2ff3 100644 --- a/intern/cycles/kernel/shaders/node_brick_texture.osl +++ b/intern/cycles/kernel/shaders/node_brick_texture.osl @@ -15,7 +15,6 @@ */ #include "stdosl.h" -#include "node_texture.h" /* Brick */ diff --git a/intern/cycles/kernel/shaders/node_checker_texture.osl b/intern/cycles/kernel/shaders/node_checker_texture.osl index e068f7952ed..e05cf20099f 100644 --- a/intern/cycles/kernel/shaders/node_checker_texture.osl +++ b/intern/cycles/kernel/shaders/node_checker_texture.osl @@ -15,7 +15,6 @@ */ #include "stdosl.h" -#include "node_texture.h" /* Checker */ diff --git a/intern/cycles/kernel/shaders/node_gradient_texture.osl b/intern/cycles/kernel/shaders/node_gradient_texture.osl index 52bf466673d..5cc81d367f2 100644 --- a/intern/cycles/kernel/shaders/node_gradient_texture.osl +++ b/intern/cycles/kernel/shaders/node_gradient_texture.osl @@ -15,7 +15,6 @@ */ #include "stdosl.h" -#include "node_texture.h" /* Gradient */ diff --git a/intern/cycles/kernel/shaders/node_ies_light.osl b/intern/cycles/kernel/shaders/node_ies_light.osl index ce0173451da..6e9181cde40 100644 --- a/intern/cycles/kernel/shaders/node_ies_light.osl +++ b/intern/cycles/kernel/shaders/node_ies_light.osl @@ -15,7 +15,6 @@ */ #include "stdosl.h" -#include "node_texture.h" /* IES Light */ diff --git a/intern/cycles/kernel/shaders/node_magic_texture.osl b/intern/cycles/kernel/shaders/node_magic_texture.osl index aa700e575ef..26e7d57278b 100644 --- a/intern/cycles/kernel/shaders/node_magic_texture.osl +++ b/intern/cycles/kernel/shaders/node_magic_texture.osl @@ -15,7 +15,6 @@ */ #include "stdosl.h" -#include "node_texture.h" /* Magic */ diff --git a/intern/cycles/kernel/shaders/node_musgrave_texture.osl b/intern/cycles/kernel/shaders/node_musgrave_texture.osl index a7877c43d46..0bf462e2103 100644 --- a/intern/cycles/kernel/shaders/node_musgrave_texture.osl +++ b/intern/cycles/kernel/shaders/node_musgrave_texture.osl @@ -15,7 +15,7 @@ */ #include "stdosl.h" -#include "node_texture.h" +#include "node_noise.h" /* Musgrave fBm * @@ -36,14 +36,14 @@ float noise_musgrave_fBm(point ip, float H, float lacunarity, float octaves) point p = ip; for (i = 0; i < (int)octaves; i++) { - value += safe_noise(p, "signed") * pwr; + value += safe_noise(p) * pwr; pwr *= pwHL; p *= lacunarity; } rmd = octaves - floor(octaves); if (rmd != 0.0) - value += rmd * safe_noise(p, "signed") * pwr; + value += rmd * safe_noise(p) * pwr; return value; } @@ -65,14 +65,14 @@ float noise_musgrave_multi_fractal(point ip, float H, float lacunarity, float oc point p = ip; for (i = 0; i < (int)octaves; i++) { - value *= (pwr * safe_noise(p, "signed") + 1.0); + value *= (pwr * safe_noise(p) + 1.0); pwr *= pwHL; p *= lacunarity; } rmd = octaves - floor(octaves); if (rmd != 0.0) - value *= (rmd * pwr * safe_noise(p, "signed") + 1.0); /* correct? */ + value *= (rmd * pwr * safe_noise(p) + 1.0); /* correct? */ return value; } @@ -95,11 +95,11 @@ float noise_musgrave_hetero_terrain( point p = ip; /* first unscaled octave of function; later octaves are scaled */ - value = offset + safe_noise(p, "signed"); + value = offset + safe_noise(p); p *= lacunarity; for (i = 1; i < (int)octaves; i++) { - increment = (safe_noise(p, "signed") + offset) * pwr * value; + increment = (safe_noise(p) + offset) * pwr * value; value += increment; pwr *= pwHL; p *= lacunarity; @@ -107,7 +107,7 @@ float noise_musgrave_hetero_terrain( rmd = octaves - floor(octaves); if (rmd != 0.0) { - increment = (safe_noise(p, "signed") + offset) * pwr * value; + increment = (safe_noise(p) + offset) * pwr * value; value += rmd * increment; } @@ -131,7 +131,7 @@ float noise_musgrave_hybrid_multi_fractal( int i; point p = ip; - result = safe_noise(p, "signed") + offset; + result = safe_noise(p) + offset; weight = gain * result; p *= lacunarity; @@ -139,7 +139,7 @@ float noise_musgrave_hybrid_multi_fractal( if (weight > 1.0) weight = 1.0; - signal = (safe_noise(p, "signed") + offset) * pwr; + signal = (safe_noise(p) + offset) * pwr; pwr *= pwHL; result += weight * signal; weight *= gain * signal; @@ -148,7 +148,7 @@ float noise_musgrave_hybrid_multi_fractal( rmd = octaves - floor(octaves); if (rmd != 0.0) - result += rmd * ((safe_noise(p, "signed") + offset) * pwr); + result += rmd * ((safe_noise(p) + offset) * pwr); return result; } @@ -170,7 +170,7 @@ float noise_musgrave_ridged_multi_fractal( int i; point p = ip; - signal = offset - fabs(safe_noise(p, "signed")); + signal = offset - fabs(safe_noise(p)); signal *= signal; result = signal; weight = 1.0; @@ -178,7 +178,7 @@ float noise_musgrave_ridged_multi_fractal( for (i = 1; i < (int)octaves; i++) { p *= lacunarity; weight = clamp(signal * gain, 0.0, 1.0); - signal = offset - fabs(safe_noise(p, "signed")); + signal = offset - fabs(safe_noise(p)); signal *= signal; signal *= weight; result += signal * pwr; diff --git a/intern/cycles/kernel/shaders/node_noise.h b/intern/cycles/kernel/shaders/node_noise.h new file mode 100644 index 00000000000..23d1987a00e --- /dev/null +++ b/intern/cycles/kernel/shaders/node_noise.h @@ -0,0 +1,198 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "vector2.h" +#include "vector4.h" + +#define vector3 point + +float safe_noise(float p) +{ + float f = noise("noise", p); + if (isinf(f)) + return 0.5; + return f; +} + +float safe_noise(vector2 p) +{ + float f = noise("noise", p.x, p.y); + if (isinf(f)) + return 0.5; + return f; +} + +float safe_noise(vector3 p) +{ + float f = noise("noise", p); + if (isinf(f)) + return 0.5; + return f; +} + +float safe_noise(vector4 p) +{ + float f = noise("noise", vector3(p.x, p.y, p.z), p.w); + if (isinf(f)) + return 0.5; + return f; +} + +float safe_snoise(float p) +{ + float f = noise("snoise", p); + if (isinf(f)) + return 0.0; + return f; +} + +float safe_snoise(vector2 p) +{ + float f = noise("snoise", p.x, p.y); + if (isinf(f)) + return 0.0; + return f; +} + +float safe_snoise(vector3 p) +{ + float f = noise("snoise", p); + if (isinf(f)) + return 0.0; + return f; +} + +float safe_snoise(vector4 p) +{ + float f = noise("snoise", vector3(p.x, p.y, p.z), p.w); + if (isinf(f)) + return 0.0; + return f; +} + +/* The fractal_noise functions are all exactly the same except for the input type. */ +float fractal_noise(float p, float details) +{ + float fscale = 1.0; + float amp = 1.0; + float sum = 0.0; + float octaves = clamp(details, 0.0, 16.0); + int n = (int)octaves; + for (int i = 0; i <= n; i++) { + float t = safe_noise(fscale * p); + sum += t * amp; + amp *= 0.5; + fscale *= 2.0; + } + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float t = safe_noise(fscale * p); + float sum2 = sum + t * amp; + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); + return (1.0 - rmd) * sum + rmd * sum2; + } + else { + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + return sum; + } +} + +/* The fractal_noise functions are all exactly the same except for the input type. */ +float fractal_noise(vector2 p, float details) +{ + float fscale = 1.0; + float amp = 1.0; + float sum = 0.0; + float octaves = clamp(details, 0.0, 16.0); + int n = (int)octaves; + for (int i = 0; i <= n; i++) { + float t = safe_noise(fscale * p); + sum += t * amp; + amp *= 0.5; + fscale *= 2.0; + } + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float t = safe_noise(fscale * p); + float sum2 = sum + t * amp; + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); + return (1.0 - rmd) * sum + rmd * sum2; + } + else { + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + return sum; + } +} + +/* The fractal_noise functions are all exactly the same except for the input type. */ +float fractal_noise(vector3 p, float details) +{ + float fscale = 1.0; + float amp = 1.0; + float sum = 0.0; + float octaves = clamp(details, 0.0, 16.0); + int n = (int)octaves; + for (int i = 0; i <= n; i++) { + float t = safe_noise(fscale * p); + sum += t * amp; + amp *= 0.5; + fscale *= 2.0; + } + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float t = safe_noise(fscale * p); + float sum2 = sum + t * amp; + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); + return (1.0 - rmd) * sum + rmd * sum2; + } + else { + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + return sum; + } +} + +/* The fractal_noise functions are all exactly the same except for the input type. */ +float fractal_noise(vector4 p, float details) +{ + float fscale = 1.0; + float amp = 1.0; + float sum = 0.0; + float octaves = clamp(details, 0.0, 16.0); + int n = (int)octaves; + for (int i = 0; i <= n; i++) { + float t = safe_noise(fscale * p); + sum += t * amp; + amp *= 0.5; + fscale *= 2.0; + } + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float t = safe_noise(fscale * p); + float sum2 = sum + t * amp; + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); + return (1.0 - rmd) * sum + rmd * sum2; + } + else { + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + return sum; + } +} + +#undef vector3 diff --git a/intern/cycles/kernel/shaders/node_noise_texture.osl b/intern/cycles/kernel/shaders/node_noise_texture.osl index 2cbd571e206..242a7e33f60 100644 --- a/intern/cycles/kernel/shaders/node_noise_texture.osl +++ b/intern/cycles/kernel/shaders/node_noise_texture.osl @@ -15,46 +15,134 @@ */ #include "stdosl.h" -#include "node_texture.h" +#include "vector2.h" +#include "vector4.h" +#include "node_noise.h" -/* Noise */ +#define vector3 point -float noise(point ip, float distortion, float detail, output color Color) +/* The following offset functions generate random offsets to be added to texture + * coordinates to act as a seed since the noise functions don't have seed values. + * A seed value is needed for generating distortion textures and color outputs. + * The offset's components are in the range [100, 200], not too high to cause + * bad precision and not to small to be noticeable. We use float seed because + * OSL only support float hashes. + */ + +float random_float_offset(float seed) +{ + return 100.0 + noise("hash", seed) * 100.0; +} + +vector2 random_vector2_offset(float seed) +{ + return vector2(100.0 + noise("hash", seed, 0.0) * 100.0, + 100.0 + noise("hash", seed, 1.0) * 100.0); +} + +vector3 random_vector3_offset(float seed) { - point r; - point p = ip; - int hard = 0; + return vector3(100.0 + noise("hash", seed, 0.0) * 100.0, + 100.0 + noise("hash", seed, 1.0) * 100.0, + 100.0 + noise("hash", seed, 2.0) * 100.0); +} + +vector4 random_vector4_offset(float seed) +{ + return vector4(100.0 + noise("hash", seed, 0.0) * 100.0, + 100.0 + noise("hash", seed, 1.0) * 100.0, + 100.0 + noise("hash", seed, 2.0) * 100.0, + 100.0 + noise("hash", seed, 3.0) * 100.0); +} +float noise_texture(float co, float detail, float distortion, output color Color) +{ + float p = co; if (distortion != 0.0) { - r[0] = safe_noise(p + point(13.5), "unsigned") * distortion; - r[1] = safe_noise(p, "unsigned") * distortion; - r[2] = safe_noise(p - point(13.5), "unsigned") * distortion; + p += safe_noise(p + random_float_offset(0.0)) * distortion; + } + + float value = fractal_noise(p, detail); + Color = color(value, + fractal_noise(p + random_float_offset(1.0), detail), + fractal_noise(p + random_float_offset(2.0), detail)); + return value; +} - p += r; +float noise_texture(vector2 co, float detail, float distortion, output color Color) +{ + vector2 p = co; + if (distortion != 0.0) { + p += vector2(safe_noise(p + random_vector2_offset(0.0)) * distortion, + safe_noise(p + random_vector2_offset(1.0)) * distortion); } - float fac = noise_turbulence(p, detail, hard); + float value = fractal_noise(p, detail); + Color = color(value, + fractal_noise(p + random_vector2_offset(2.0), detail), + fractal_noise(p + random_vector2_offset(3.0), detail)); + return value; +} - Color = color(fac, - noise_turbulence(point(p[1], p[0], p[2]), detail, hard), - noise_turbulence(point(p[1], p[2], p[0]), detail, hard)); +float noise_texture(vector3 co, float detail, float distortion, output color Color) +{ + vector3 p = co; + if (distortion != 0.0) { + p += vector3(safe_noise(p + random_vector3_offset(0.0)) * distortion, + safe_noise(p + random_vector3_offset(1.0)) * distortion, + safe_noise(p + random_vector3_offset(2.0)) * distortion); + } - return fac; + float value = fractal_noise(p, detail); + Color = color(value, + fractal_noise(p + random_vector3_offset(3.0), detail), + fractal_noise(p + random_vector3_offset(4.0), detail)); + return value; +} + +float noise_texture(vector4 co, float detail, float distortion, output color Color) +{ + vector4 p = co; + if (distortion != 0.0) { + p += vector4(safe_noise(p + random_vector4_offset(0.0)) * distortion, + safe_noise(p + random_vector4_offset(1.0)) * distortion, + safe_noise(p + random_vector4_offset(2.0)) * distortion, + safe_noise(p + random_vector4_offset(3.0)) * distortion); + } + + float value = fractal_noise(p, detail); + Color = color(value, + fractal_noise(p + random_vector4_offset(4.0), detail), + fractal_noise(p + random_vector4_offset(5.0), detail)); + return value; } shader node_noise_texture(int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - float Distortion = 0.0, + string dimensions = "3D", + vector3 Vector = vector3(0, 0, 0), + float W = 0.0, float Scale = 5.0, float Detail = 2.0, - point Vector = P, + float Distortion = 0.0, output float Fac = 0.0, output color Color = 0.0) { - point p = Vector; - + vector3 p = Vector; if (use_mapping) p = transform(mapping, p); + + p *= Scale; + float w = W * Scale; - Fac = noise(p * Scale, Distortion, Detail, Color); + if (dimensions == "1D") + Fac = noise_texture(w, Detail, Distortion, Color); + else if (dimensions == "2D") + Fac = noise_texture(vector2(p[0], p[1]), Detail, Distortion, Color); + else if (dimensions == "3D") + Fac = noise_texture(p, Detail, Distortion, Color); + else if (dimensions == "4D") + Fac = noise_texture(vector4(p[0], p[1], p[2], w), Detail, Distortion, Color); + else + error("Unknown dimension!"); } diff --git a/intern/cycles/kernel/shaders/node_texture.h b/intern/cycles/kernel/shaders/node_texture.h deleted file mode 100644 index e1f3b900ee5..00000000000 --- a/intern/cycles/kernel/shaders/node_texture.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2011-2013 Blender Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Voronoi / Worley like */ - -color cellnoise_color(point p) -{ - float r = cellnoise(p); - float g = cellnoise(point(p[1], p[0], p[2])); - float b = cellnoise(point(p[1], p[2], p[0])); - - return color(r, g, b); -} - -void voronoi(point p, float e, float da[4], point pa[4]) -{ - /* returns distances in da and point coords in pa */ - int xx, yy, zz, xi, yi, zi; - - xi = (int)floor(p[0]); - yi = (int)floor(p[1]); - zi = (int)floor(p[2]); - - da[0] = 1e10; - da[1] = 1e10; - da[2] = 1e10; - da[3] = 1e10; - - for (xx = xi - 1; xx <= xi + 1; xx++) { - for (yy = yi - 1; yy <= yi + 1; yy++) { - for (zz = zi - 1; zz <= zi + 1; zz++) { - point ip = point(xx, yy, zz); - point vp = (point)cellnoise_color(ip); - point pd = p - (vp + ip); - float d = dot(pd, pd); - - vp += point(xx, yy, zz); - - if (d < da[0]) { - da[3] = da[2]; - da[2] = da[1]; - da[1] = da[0]; - da[0] = d; - - pa[3] = pa[2]; - pa[2] = pa[1]; - pa[1] = pa[0]; - pa[0] = vp; - } - else if (d < da[1]) { - da[3] = da[2]; - da[2] = da[1]; - da[1] = d; - - pa[3] = pa[2]; - pa[2] = pa[1]; - pa[1] = vp; - } - else if (d < da[2]) { - da[3] = da[2]; - da[2] = d; - - pa[3] = pa[2]; - pa[2] = vp; - } - else if (d < da[3]) { - da[3] = d; - pa[3] = vp; - } - } - } - } -} - -/* Noise Bases */ - -float safe_noise(point p, string type) -{ - float f = 0.0; - - /* Perlin noise in range -1..1 */ - if (type == "signed") - f = noise("perlin", p); - - /* Perlin noise in range 0..1 */ - else - f = noise(p); - - /* can happen for big coordinates, things even out to 0.5 then anyway */ - if (!isfinite(f)) - return 0.5; - - return f; -} - -/* Turbulence */ - -float noise_turbulence(point p, float details, int hard) -{ - float fscale = 1.0; - float amp = 1.0; - float sum = 0.0; - int i, n; - - float octaves = clamp(details, 0.0, 16.0); - n = (int)octaves; - - for (i = 0; i <= n; i++) { - float t = safe_noise(fscale * p, "unsigned"); - - if (hard) - t = fabs(2.0 * t - 1.0); - - sum += t * amp; - amp *= 0.5; - fscale *= 2.0; - } - - float rmd = octaves - floor(octaves); - - if (rmd != 0.0) { - float t = safe_noise(fscale * p, "unsigned"); - - if (hard) - t = fabs(2.0 * t - 1.0); - - float sum2 = sum + t * amp; - - sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); - sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); - - return (1.0 - rmd) * sum + rmd * sum2; - } - else { - sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); - return sum; - } -} - -/* Utility */ - -float nonzero(float f, float eps) -{ - float r; - - if (abs(f) < eps) - r = sign(f) * eps; - else - r = f; - - return r; -} diff --git a/intern/cycles/kernel/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/shaders/node_voronoi_texture.osl index 34c86d5b98d..0d547b4b615 100644 --- a/intern/cycles/kernel/shaders/node_voronoi_texture.osl +++ b/intern/cycles/kernel/shaders/node_voronoi_texture.osl @@ -15,7 +15,15 @@ */ #include "stdosl.h" -#include "node_texture.h" + +color cellnoise_color(point p) +{ + float r = cellnoise(p); + float g = cellnoise(point(p[1], p[0], p[2])); + float b = cellnoise(point(p[1], p[2], p[0])); + + return color(r, g, b); +} void voronoi_m(point p, string metric, float e, float da[4], point pa[4]) { diff --git a/intern/cycles/kernel/shaders/node_wave_texture.osl b/intern/cycles/kernel/shaders/node_wave_texture.osl index dfc2dbfb800..60591b79b33 100644 --- a/intern/cycles/kernel/shaders/node_wave_texture.osl +++ b/intern/cycles/kernel/shaders/node_wave_texture.osl @@ -15,7 +15,7 @@ */ #include "stdosl.h" -#include "node_texture.h" +#include "node_noise.h" /* Wave */ @@ -31,7 +31,7 @@ float wave(point p, string type, string profile, float detail, float distortion, } if (distortion != 0.0) { - n = n + (distortion * noise_turbulence(p * dscale, detail, 0)); + n = n + (distortion * fractal_noise(p * dscale, detail)); } if (profile == "sine") { diff --git a/intern/cycles/kernel/shaders/vector2.h b/intern/cycles/kernel/shaders/vector2.h new file mode 100644 index 00000000000..c524735d892 --- /dev/null +++ b/intern/cycles/kernel/shaders/vector2.h @@ -0,0 +1,291 @@ +// Open Shading Language : Copyright (c) 2009-2017 Sony Pictures Imageworks Inc., et al. +// https://github.com/imageworks/OpenShadingLanguage/blob/master/LICENSE + +#pragma once +#define VECTOR2_H + +// vector2 is a 2D vector +struct vector2 { + float x; + float y; +}; + +// +// For vector2, define math operators to match vector +// + +vector2 __operator__neg__(vector2 a) +{ + return vector2(-a.x, -a.y); +} + +vector2 __operator__add__(vector2 a, vector2 b) +{ + return vector2(a.x + b.x, a.y + b.y); +} + +vector2 __operator__add__(vector2 a, int b) +{ + return a + vector2(b, b); +} + +vector2 __operator__add__(vector2 a, float b) +{ + return a + vector2(b, b); +} + +vector2 __operator__add__(int a, vector2 b) +{ + return vector2(a, a) + b; +} + +vector2 __operator__add__(float a, vector2 b) +{ + return vector2(a, a) + b; +} + +vector2 __operator__sub__(vector2 a, vector2 b) +{ + return vector2(a.x - b.x, a.y - b.y); +} + +vector2 __operator__sub__(vector2 a, int b) +{ + return a - vector2(b, b); +} + +vector2 __operator__sub__(vector2 a, float b) +{ + return a - vector2(b, b); +} + +vector2 __operator__sub__(int a, vector2 b) +{ + return vector2(a, a) - b; +} + +vector2 __operator__sub__(float a, vector2 b) +{ + return vector2(a, a) - b; +} + +vector2 __operator__mul__(vector2 a, vector2 b) +{ + return vector2(a.x * b.x, a.y * b.y); +} + +vector2 __operator__mul__(vector2 a, int b) +{ + return a * vector2(b, b); +} + +vector2 __operator__mul__(vector2 a, float b) +{ + return a * vector2(b, b); +} + +vector2 __operator__mul__(int a, vector2 b) +{ + return b * vector2(a, a); +} + +vector2 __operator__mul__(float a, vector2 b) +{ + return b * vector2(a, a); +} + +vector2 __operator__div__(vector2 a, vector2 b) +{ + return vector2(a.x / b.x, a.y / b.y); +} + +vector2 __operator__div__(vector2 a, int b) +{ + float b_inv = 1 / b; + return a * vector2(b_inv, b_inv); +} + +vector2 __operator__div__(vector2 a, float b) +{ + float b_inv = 1 / b; + return a * vector2(b_inv, b_inv); +} + +vector2 __operator__div__(int a, vector2 b) +{ + return vector2(a, a) / b; +} + +vector2 __operator__div__(float a, vector2 b) +{ + return vector2(a, a) / b; +} + +int __operator__eq__(vector2 a, vector2 b) +{ + return (a.x == b.x) && (a.y == b.y); +} + +int __operator__ne__(vector2 a, vector2 b) +{ + return (a.x != b.x) || (a.y != b.y); +} + +// +// For vector2, define most of the stdosl functions to match vector +// + +vector2 abs(vector2 a) +{ + return vector2(abs(a.x), abs(a.y)); +} + +vector2 ceil(vector2 a) +{ + return vector2(ceil(a.x), ceil(a.y)); +} + +vector2 floor(vector2 a) +{ + return vector2(floor(a.x), floor(a.y)); +} + +vector2 sqrt(vector2 a) +{ + return vector2(sqrt(a.x), sqrt(a.y)); +} + +vector2 exp(vector2 a) +{ + return vector2(exp(a.x), exp(a.y)); +} + +vector2 log(vector2 a) +{ + return vector2(log(a.x), log(a.y)); +} + +vector2 log2(vector2 a) +{ + return vector2(log2(a.x), log2(a.y)); +} + +vector2 mix(vector2 a, vector2 b, float x) +{ + return vector2(mix(a.x, b.x, x), mix(a.y, b.y, x)); +} + +float dot(vector2 a, vector2 b) +{ + return (a.x * b.x + a.y * b.y); +} + +float length(vector2 a) +{ + return hypot(a.x, a.y); +} + +vector2 smoothstep(vector2 low, vector2 high, vector2 in) +{ + return vector2(smoothstep(low.x, high.x, in.x), smoothstep(low.y, high.y, in.y)); +} + +vector2 smoothstep(float low, float high, vector2 in) +{ + return vector2(smoothstep(low, high, in.x), smoothstep(low, high, in.y)); +} + +vector2 clamp(vector2 in, vector2 low, vector2 high) +{ + return vector2(clamp(in.x, low.x, high.x), clamp(in.y, low.y, high.y)); +} + +vector2 clamp(vector2 in, float low, float high) +{ + return clamp(in, vector2(low, low), vector2(high, high)); +} + +vector2 max(vector2 a, vector2 b) +{ + return vector2(max(a.x, b.x), max(a.y, b.y)); +} + +vector2 max(vector2 a, float b) +{ + return max(a, vector2(b, b)); +} + +vector2 normalize(vector2 a) +{ + return a / length(a); +} + +vector2 min(vector2 a, vector2 b) +{ + return vector2(min(a.x, a.x), min(b.y, b.y)); +} + +vector2 min(vector2 a, float b) +{ + return min(a, vector2(b, b)); +} + +vector2 fmod(vector2 a, vector2 b) +{ + return vector2(fmod(a.x, b.x), fmod(a.y, b.y)); +} + +vector2 fmod(vector2 a, float b) +{ + return fmod(a, vector2(b, b)); +} + +vector2 pow(vector2 in, vector2 amount) +{ + return vector2(pow(in.x, amount.x), pow(in.y, amount.y)); +} + +vector2 pow(vector2 in, float amount) +{ + return pow(in, vector2(amount, amount)); +} + +vector2 sign(vector2 a) +{ + return vector2(sign(a.x), sign(a.y)); +} + +vector2 sin(vector2 a) +{ + return vector2(sin(a.x), sin(a.y)); +} + +vector2 cos(vector2 a) +{ + return vector2(cos(a.x), cos(a.y)); +} + +vector2 tan(vector2 a) +{ + return vector2(tan(a.x), tan(a.y)); +} + +vector2 asin(vector2 a) +{ + return vector2(asin(a.x), asin(a.y)); +} + +vector2 acos(vector2 a) +{ + return vector2(acos(a.x), acos(a.y)); +} + +vector2 atan2(vector2 a, float f) +{ + return vector2(atan2(a.x, f), atan2(a.y, f)); +} + +vector2 atan2(vector2 a, vector2 b) +{ + return vector2(atan2(a.x, b.x), atan2(a.y, b.y)); +} diff --git a/intern/cycles/kernel/shaders/vector4.h b/intern/cycles/kernel/shaders/vector4.h new file mode 100644 index 00000000000..58e1b3c2e23 --- /dev/null +++ b/intern/cycles/kernel/shaders/vector4.h @@ -0,0 +1,327 @@ +// Open Shading Language : Copyright (c) 2009-2017 Sony Pictures Imageworks Inc., et al. +// https://github.com/imageworks/OpenShadingLanguage/blob/master/LICENSE + +#pragma once +#define VECTOR4_H + +// vector4 is a 4D vector +struct vector4 { + float x; + float y; + float z; + float w; +}; + +// +// For vector4, define math operators to match vector +// + +vector4 __operator__neg__(vector4 a) +{ + return vector4(-a.x, -a.y, -a.z, -a.w); +} + +vector4 __operator__add__(vector4 a, vector4 b) +{ + return vector4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); +} + +vector4 __operator__add__(vector4 a, int b) +{ + return a + vector4(b, b, b, b); +} + +vector4 __operator__add__(vector4 a, float b) +{ + return a + vector4(b, b, b, b); +} + +vector4 __operator__add__(int a, vector4 b) +{ + return vector4(a, a, a, a) + b; +} + +vector4 __operator__add__(float a, vector4 b) +{ + return vector4(a, a, a, a) + b; +} + +vector4 __operator__sub__(vector4 a, vector4 b) +{ + return vector4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); +} + +vector4 __operator__sub__(vector4 a, int b) +{ + return a - vector4(b, b, b, b); +} + +vector4 __operator__sub__(vector4 a, float b) +{ + return a - vector4(b, b, b, b); +} + +vector4 __operator__sub__(int a, vector4 b) +{ + return vector4(a, a, a, a) - b; +} + +vector4 __operator__sub__(float a, vector4 b) +{ + return vector4(a, a, a, a) - b; +} + +vector4 __operator__mul__(vector4 a, vector4 b) +{ + return vector4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); +} + +vector4 __operator__mul__(vector4 a, int b) +{ + return a * vector4(b, b, b, b); +} + +vector4 __operator__mul__(vector4 a, float b) +{ + return a * vector4(b, b, b, b); +} + +vector4 __operator__mul__(int a, vector4 b) +{ + return vector4(a, a, a, a) * b; +} + +vector4 __operator__mul__(float a, vector4 b) +{ + return vector4(a, a, a, a) * b; +} + +vector4 __operator__div__(vector4 a, vector4 b) +{ + return vector4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); +} + +vector4 __operator__div__(vector4 a, int b) +{ + float b_inv = 1 / b; + return a * vector4(b_inv, b_inv, b_inv, b_inv); +} + +vector4 __operator__div__(vector4 a, float b) +{ + float b_inv = 1 / b; + return a * vector4(b_inv, b_inv, b_inv, b_inv); +} + +vector4 __operator__div__(int a, vector4 b) +{ + return vector4(a, a, a, a) / b; +} + +vector4 __operator__div__(float a, vector4 b) +{ + return vector4(a, a, a, a) / b; +} + +int __operator__eq__(vector4 a, vector4 b) +{ + return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w); +} + +int __operator__ne__(vector4 a, vector4 b) +{ + return (a.x != b.x) || (a.y != b.y) || (a.z != b.z) || (a.w != b.w); +} + +// +// For vector4, define most of the stdosl functions to match vector +// + +vector4 abs(vector4 in) +{ + return vector4(abs(in.x), abs(in.y), abs(in.z), abs(in.w)); +} + +vector4 ceil(vector4 in) +{ + return vector4(ceil(in.x), ceil(in.y), ceil(in.z), ceil(in.w)); +} + +vector4 floor(vector4 in) +{ + return vector4(floor(in.x), floor(in.y), floor(in.z), floor(in.w)); +} + +vector4 sqrt(vector4 in) +{ + return vector4(sqrt(in.x), sqrt(in.y), sqrt(in.z), sqrt(in.w)); +} + +vector4 exp(vector4 in) +{ + return vector4(exp(in.x), exp(in.y), exp(in.z), exp(in.w)); +} + +vector4 log(vector4 in) +{ + return vector4(log(in.x), log(in.y), log(in.z), log(in.w)); +} + +vector4 log2(vector4 in) +{ + return vector4(log2(in.x), log2(in.y), log2(in.z), log2(in.w)); +} + +vector4 mix(vector4 value1, vector4 value2, float x) +{ + return vector4(mix(value1.x, value2.x, x), + mix(value1.y, value2.y, x), + mix(value1.z, value2.z, x), + mix(value1.w, value2.w, x)); +} + +vector vec4ToVec3(vector4 v) +{ + return vector(v.x, v.y, v.z) / v.w; +} + +float dot(vector4 a, vector4 b) +{ + return ((a.x * b.x) + (a.y * b.y) + (a.z * b.z) + (a.w * b.w)); +} + +float length(vector4 a) +{ + return sqrt(a.x * a.x + a.y * a.y + a.z * a.z + a.w * a.w); +} + +vector4 smoothstep(vector4 low, vector4 high, vector4 in) +{ + return vector4(smoothstep(low.x, high.x, in.x), + smoothstep(low.y, high.y, in.y), + smoothstep(low.z, high.z, in.z), + smoothstep(low.w, high.w, in.w)); +} + +vector4 smoothstep(float low, float high, vector4 in) +{ + return vector4(smoothstep(low, high, in.x), + smoothstep(low, high, in.y), + smoothstep(low, high, in.z), + smoothstep(low, high, in.w)); +} + +vector4 clamp(vector4 in, vector4 low, vector4 high) +{ + return vector4(clamp(in.x, low.x, high.x), + clamp(in.y, low.y, high.y), + clamp(in.z, low.z, high.z), + clamp(in.w, low.w, high.w)); +} + +vector4 clamp(vector4 in, float low, float high) +{ + return vector4(clamp(in.x, low, high), + clamp(in.y, low, high), + clamp(in.z, low, high), + clamp(in.w, low, high)); +} + +vector4 max(vector4 a, vector4 b) +{ + return vector4(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w)); +} + +vector4 max(vector4 a, float b) +{ + return max(a, vector4(b, b, b, b)); +} + +vector4 normalize(vector4 a) +{ + return a / length(a); +} + +vector4 min(vector4 a, vector4 b) +{ + return vector4(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w)); +} + +vector4 min(vector4 a, float b) +{ + return min(a, vector4(b, b, b, b)); +} + +vector4 fmod(vector4 a, vector4 b) +{ + return vector4(fmod(a.x, b.x), fmod(a.y, b.y), fmod(a.z, b.z), fmod(a.w, b.w)); +} + +vector4 fmod(vector4 a, float b) +{ + return fmod(a, vector4(b, b, b, b)); +} + +vector4 pow(vector4 in, vector4 amount) +{ + return vector4( + pow(in.x, amount.x), pow(in.y, amount.y), pow(in.z, amount.z), pow(in.w, amount.w)); +} + +vector4 pow(vector4 in, float amount) +{ + return vector4(pow(in.x, amount), pow(in.y, amount), pow(in.z, amount), pow(in.w, amount)); +} + +vector4 sign(vector4 a) +{ + return vector4(sign(a.x), sign(a.y), sign(a.z), sign(a.w)); +} + +vector4 sin(vector4 a) +{ + return vector4(sin(a.x), sin(a.y), sin(a.z), sin(a.w)); +} + +vector4 cos(vector4 a) +{ + return vector4(cos(a.x), cos(a.y), cos(a.z), cos(a.w)); +} + +vector4 tan(vector4 a) +{ + return vector4(tan(a.x), tan(a.y), tan(a.z), tan(a.w)); +} + +vector4 asin(vector4 a) +{ + return vector4(asin(a.x), asin(a.y), asin(a.z), asin(a.w)); +} + +vector4 acos(vector4 a) +{ + return vector4(acos(a.x), acos(a.y), acos(a.z), acos(a.w)); +} + +vector4 atan2(vector4 a, float f) +{ + return vector4(atan2(a.x, f), atan2(a.y, f), atan2(a.z, f), atan2(a.w, f)); +} + +vector4 atan2(vector4 a, vector4 b) +{ + return vector4(atan2(a.x, b.x), atan2(a.y, b.y), atan2(a.z, b.z), atan2(a.w, b.w)); +} + +vector4 transform(matrix M, vector4 p) +{ + return vector4(M[0][0] * p.x + M[0][1] * p.y + M[0][2] * p.z + M[0][2] * p.w, + M[1][0] * p.x + M[1][1] * p.y + M[1][2] * p.z + M[1][2] * p.w, + M[2][0] * p.x + M[2][1] * p.y + M[2][2] * p.z + M[2][2] * p.w, + M[3][0] * p.x + M[3][1] * p.y + M[3][2] * p.z + M[3][2] * p.w); +} + +vector4 transform(string fromspace, string tospace, vector4 p) +{ + return transform(matrix(fromspace, tospace), p); +} diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index ab8570618ab..95954aaf99e 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -158,7 +158,7 @@ CCL_NAMESPACE_END /* Nodes */ #include "kernel/svm/svm_noise.h" -#include "svm_texture.h" +#include "svm_fractal_noise.h" #include "kernel/svm/svm_color_util.h" #include "kernel/svm/svm_math_util.h" @@ -313,7 +313,7 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, svm_node_tex_image_box(kg, sd, stack, node); break; case NODE_TEX_NOISE: - svm_node_tex_noise(kg, sd, stack, node, &offset); + svm_node_tex_noise(kg, sd, stack, node.y, node.z, node.w, &offset); break; # endif /* __TEXTURES__ */ # ifdef __EXTRA_NODES__ diff --git a/intern/cycles/kernel/svm/svm_fractal_noise.h b/intern/cycles/kernel/svm/svm_fractal_noise.h new file mode 100644 index 00000000000..5b2e4a28fce --- /dev/null +++ b/intern/cycles/kernel/svm/svm_fractal_noise.h @@ -0,0 +1,131 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +CCL_NAMESPACE_BEGIN + +/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */ +ccl_device_noinline float fractal_noise_1d(float p, float octaves) +{ + float fscale = 1.0f; + float amp = 1.0f; + float sum = 0.0f; + octaves = clamp(octaves, 0.0f, 16.0f); + int n = float_to_int(octaves); + for (int i = 0; i <= n; i++) { + float t = noise_1d(fscale * p); + sum += t * amp; + amp *= 0.5f; + fscale *= 2.0f; + } + float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + float t = noise_1d(fscale * p); + float sum2 = sum + t * amp; + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); + return (1.0f - rmd) * sum + rmd * sum2; + } + else { + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + return sum; + } +} + +/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */ +ccl_device_noinline float fractal_noise_2d(float2 p, float octaves) +{ + float fscale = 1.0f; + float amp = 1.0f; + float sum = 0.0f; + octaves = clamp(octaves, 0.0f, 16.0f); + int n = float_to_int(octaves); + for (int i = 0; i <= n; i++) { + float t = noise_2d(fscale * p); + sum += t * amp; + amp *= 0.5f; + fscale *= 2.0f; + } + float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + float t = noise_2d(fscale * p); + float sum2 = sum + t * amp; + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); + return (1.0f - rmd) * sum + rmd * sum2; + } + else { + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + return sum; + } +} + +/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */ +ccl_device_noinline float fractal_noise_3d(float3 p, float octaves) +{ + float fscale = 1.0f; + float amp = 1.0f; + float sum = 0.0f; + octaves = clamp(octaves, 0.0f, 16.0f); + int n = float_to_int(octaves); + for (int i = 0; i <= n; i++) { + float t = noise_3d(fscale * p); + sum += t * amp; + amp *= 0.5f; + fscale *= 2.0f; + } + float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + float t = noise_3d(fscale * p); + float sum2 = sum + t * amp; + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); + return (1.0f - rmd) * sum + rmd * sum2; + } + else { + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + return sum; + } +} + +/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */ +ccl_device_noinline float fractal_noise_4d(float4 p, float octaves) +{ + float fscale = 1.0f; + float amp = 1.0f; + float sum = 0.0f; + octaves = clamp(octaves, 0.0f, 16.0f); + int n = float_to_int(octaves); + for (int i = 0; i <= n; i++) { + float t = noise_4d(fscale * p); + sum += t * amp; + amp *= 0.5f; + fscale *= 2.0f; + } + float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + float t = noise_4d(fscale * p); + float sum2 = sum + t * amp; + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); + return (1.0f - rmd) * sum + rmd * sum2; + } + else { + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + return sum; + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/svm_musgrave.h b/intern/cycles/kernel/svm/svm_musgrave.h index 9291c7e7295..db87f04581f 100644 --- a/intern/cycles/kernel/svm/svm_musgrave.h +++ b/intern/cycles/kernel/svm/svm_musgrave.h @@ -37,14 +37,14 @@ ccl_device_noinline_cpu float noise_musgrave_fBm(float3 p, int i; for (i = 0; i < float_to_int(octaves); i++) { - value += snoise(p) * pwr; + value += snoise_3d(p) * pwr; pwr *= pwHL; p *= lacunarity; } rmd = octaves - floorf(octaves); if (rmd != 0.0f) - value += rmd * snoise(p) * pwr; + value += rmd * snoise_3d(p) * pwr; return value; } @@ -68,14 +68,14 @@ ccl_device_noinline_cpu float noise_musgrave_multi_fractal(float3 p, int i; for (i = 0; i < float_to_int(octaves); i++) { - value *= (pwr * snoise(p) + 1.0f); + value *= (pwr * snoise_3d(p) + 1.0f); pwr *= pwHL; p *= lacunarity; } rmd = octaves - floorf(octaves); if (rmd != 0.0f) - value *= (rmd * pwr * snoise(p) + 1.0f); /* correct? */ + value *= (rmd * pwr * snoise_3d(p) + 1.0f); /* correct? */ return value; } @@ -97,11 +97,11 @@ ccl_device_noinline_cpu float noise_musgrave_hetero_terrain( int i; /* first unscaled octave of function; later octaves are scaled */ - value = offset + snoise(p); + value = offset + snoise_3d(p); p *= lacunarity; for (i = 1; i < float_to_int(octaves); i++) { - increment = (snoise(p) + offset) * pwr * value; + increment = (snoise_3d(p) + offset) * pwr * value; value += increment; pwr *= pwHL; p *= lacunarity; @@ -109,7 +109,7 @@ ccl_device_noinline_cpu float noise_musgrave_hetero_terrain( rmd = octaves - floorf(octaves); if (rmd != 0.0f) { - increment = (snoise(p) + offset) * pwr * value; + increment = (snoise_3d(p) + offset) * pwr * value; value += rmd * increment; } @@ -132,7 +132,7 @@ ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal( float pwr = pwHL; int i; - result = snoise(p) + offset; + result = snoise_3d(p) + offset; weight = gain * result; p *= lacunarity; @@ -140,7 +140,7 @@ ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal( if (weight > 1.0f) weight = 1.0f; - signal = (snoise(p) + offset) * pwr; + signal = (snoise_3d(p) + offset) * pwr; pwr *= pwHL; result += weight * signal; weight *= gain * signal; @@ -149,7 +149,7 @@ ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal( rmd = octaves - floorf(octaves); if (rmd != 0.0f) - result += rmd * ((snoise(p) + offset) * pwr); + result += rmd * ((snoise_3d(p) + offset) * pwr); return result; } @@ -170,7 +170,7 @@ ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal( float pwr = pwHL; int i; - signal = offset - fabsf(snoise(p)); + signal = offset - fabsf(snoise_3d(p)); signal *= signal; result = signal; weight = 1.0f; @@ -178,7 +178,7 @@ ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal( for (i = 1; i < float_to_int(octaves); i++) { p *= lacunarity; weight = saturate(signal * gain); - signal = offset - fabsf(snoise(p)); + signal = offset - fabsf(snoise_3d(p)); signal *= signal; signal *= weight; result += signal * pwr; diff --git a/intern/cycles/kernel/svm/svm_noise.h b/intern/cycles/kernel/svm/svm_noise.h index dd375af27e5..35b74fb4b3e 100644 --- a/intern/cycles/kernel/svm/svm_noise.h +++ b/intern/cycles/kernel/svm/svm_noise.h @@ -32,246 +32,566 @@ CCL_NAMESPACE_BEGIN -#ifdef __KERNEL_SSE2__ -ccl_device_inline ssei quick_floor_sse(const ssef &x) -{ - ssei b = truncatei(x); - ssei isneg = cast((x < ssef(0.0f)).m128); - return b + isneg; // unsaturated add 0xffffffff is the same as subtract -1 -} -#endif - -#ifdef __KERNEL_SSE2__ -ccl_device_inline ssei hash_sse(const ssei &kx, const ssei &ky, const ssei &kz) -{ -# define rot(x, k) (((x) << (k)) | (srl(x, 32 - (k)))) -# define xor_rot(a, b, c) \ - do { \ - a = a ^ b; \ - a = a - rot(b, c); \ - } while (0) - - uint len = 3; - ssei magic = ssei(0xdeadbeef + (len << 2) + 13); - ssei a = magic + kx; - ssei b = magic + ky; - ssei c = magic + kz; - - xor_rot(c, b, 14); - xor_rot(a, c, 11); - xor_rot(b, a, 25); - xor_rot(c, b, 16); - xor_rot(a, c, 4); - xor_rot(b, a, 14); - xor_rot(c, b, 24); - - return c; -# undef rot -# undef xor_rot -} -#endif +/* **** Perlin Noise **** */ -#if 0 // unused -ccl_device int imod(int a, int b) +ccl_device float fade(float t) { - a %= b; - return a < 0 ? a + b : a; + return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); } -ccl_device uint phash(int kx, int ky, int kz, int3 p) +ccl_device_inline float negate_if(float val, int condition) { - return hash(imod(kx, p.x), imod(ky, p.y), imod(kz, p.z)); + return (condition) ? -val : val; } -#endif -#ifndef __KERNEL_SSE2__ -ccl_device float floorfrac(float x, int *i) +ccl_device float grad1(int hash, float x) { - *i = quick_floor_to_int(x); - return x - *i; + int h = hash & 15; + float g = 1 + (h & 7); + return negate_if(g, h & 8) * x; } -#else -ccl_device_inline ssef floorfrac_sse(const ssef &x, ssei *i) + +ccl_device_noinline_cpu float perlin_1d(float x) { - *i = quick_floor_sse(x); - return x - ssef(*i); + int X; + float fx = floorfrac(x, &X); + float u = fade(fx); + + return mix(grad1(hash_uint(X), fx), grad1(hash_uint(X + 1), fx - 1.0f), u); } -#endif +/* 2D, 3D, and 4D noise can be accelerated using SSE, so we first check if + * SSE is supported, that is, if __KERNEL_SSE2__ is defined. If it is not + * supported, we do a standard implementation, but if it is supported, we + * do an implementation using SSE intrinsics. + */ #ifndef __KERNEL_SSE2__ -ccl_device float fade(float t) + +/* ** Standard Implementation ** */ + +/* Bilinear Interpolation: + * + * v2 v3 + * @ + + + + @ y + * + + ^ + * + + | + * + + | + * @ + + + + @ @------> x + * v0 v1 + * + */ +ccl_device float bi_mix(float v0, float v1, float v2, float v3, float x, float y) { - return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); + float x1 = 1.0f - x; + return (1.0f - y) * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x); } -#else -ccl_device_inline ssef fade_sse(const ssef *t) + +/* Trilinear Interpolation: + * + * v6 v7 + * @ + + + + + + @ + * +\ +\ + * + \ + \ + * + \ + \ + * + \ v4 + \ v5 + * + @ + + + +++ + @ z + * + + + + y ^ + * v2 @ + +++ + + + @ v3 + \ | + * \ + \ + \ | + * \ + \ + \| + * \ + \ + +---------> x + * \+ \+ + * @ + + + + + + @ + * v0 v1 + */ +ccl_device float tri_mix(float v0, + float v1, + float v2, + float v3, + float v4, + float v5, + float v6, + float v7, + float x, + float y, + float z) { - ssef a = madd(*t, ssef(6.0f), ssef(-15.0f)); - ssef b = madd(*t, a, ssef(10.0f)); - return ((*t) * (*t)) * ((*t) * b); + float x1 = 1.0f - x; + float y1 = 1.0f - y; + float z1 = 1.0f - z; + return z1 * (y1 * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x)) + + z * (y1 * (v4 * x1 + v5 * x) + y * (v6 * x1 + v7 * x)); } -#endif -#ifndef __KERNEL_SSE2__ -ccl_device float nerp(float t, float a, float b) +ccl_device float quad_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 (1.0f - t) * a + t * b; + return mix(tri_mix(v0, v1, v2, v3, v4, v5, v6, v7, x, y, z), + tri_mix(v8, v9, v10, v11, v12, v13, v14, v15, x, y, z), + w); } -#else -ccl_device_inline ssef nerp_sse(const ssef &t, const ssef &a, const ssef &b) + +ccl_device float grad2(int hash, float x, float y) { - ssef x1 = (ssef(1.0f) - t) * a; - return madd(t, b, x1); + int h = hash & 7; + float u = h < 4 ? x : y; + float v = 2.0f * (h < 4 ? y : x); + return negate_if(u, h & 1) + negate_if(v, h & 2); } -#endif -#ifndef __KERNEL_SSE2__ -ccl_device float grad(int hash, float x, float y, float z) +ccl_device float grad3(int hash, float x, float y, float z) { - // use vectors pointing to the edges of the cube int h = hash & 15; float u = h < 8 ? x : y; - float vt = ((h == 12) | (h == 14)) ? x : z; + float vt = ((h == 12) || (h == 14)) ? x : z; float v = h < 4 ? y : vt; - return ((h & 1) ? -u : u) + ((h & 2) ? -v : v); + return negate_if(u, h & 1) + negate_if(v, h & 2); } -#else -ccl_device_inline ssef grad_sse(const ssei &hash, const ssef &x, const ssef &y, const ssef &z) -{ - ssei c1 = ssei(1); - ssei c2 = ssei(2); - ssei h = hash & ssei(15); // h = hash & 15 +ccl_device float grad4(int hash, float x, float y, float z, float w) +{ + int h = hash & 31; + float u = h < 24 ? x : y; + float v = h < 16 ? y : z; + float s = h < 8 ? z : w; + return negate_if(u, h & 1) + negate_if(v, h & 2) + negate_if(s, h & 4); +} - sseb case_ux = h < ssei(8); // 0xffffffff if h < 8 else 0 +ccl_device_noinline_cpu float perlin_2d(float x, float y) +{ + int X; + int Y; - ssef u = select(case_ux, x, y); // u = h<8 ? x : y + float fx = floorfrac(x, &X); + float fy = floorfrac(y, &Y); - sseb case_vy = h < ssei(4); // 0xffffffff if h < 4 else 0 + float u = fade(fx); + float v = fade(fy); - sseb case_h12 = h == ssei(12); // 0xffffffff if h == 12 else 0 - sseb case_h14 = h == ssei(14); // 0xffffffff if h == 14 else 0 + float r = bi_mix(grad2(hash_uint2(X, Y), fx, fy), + grad2(hash_uint2(X + 1, Y), fx - 1.0f, fy), + grad2(hash_uint2(X, Y + 1), fx, fy - 1.0f), + grad2(hash_uint2(X + 1, Y + 1), fx - 1.0f, fy - 1.0f), + u, + v); - sseb case_vx = case_h12 | case_h14; // 0xffffffff if h == 12 or h == 14 else 0 + return r; +} - ssef v = select(case_vy, y, select(case_vx, x, z)); // v = h<4 ? y : h == 12 || h == 14 ? x : z +ccl_device_noinline_cpu float perlin_3d(float x, float y, float z) +{ + int X; + int Y; + int Z; - ssei case_uneg = (h & c1) << 31; // 1<<31 if h&1 else 0 - ssef case_uneg_mask = cast(case_uneg); // -0.0 if h&1 else +0.0 - ssef ru = u ^ case_uneg_mask; // -u if h&1 else u (copy float sign) + float fx = floorfrac(x, &X); + float fy = floorfrac(y, &Y); + float fz = floorfrac(z, &Z); - ssei case_vneg = (h & c2) << 30; // 2<<30 if h&2 else 0 - ssef case_vneg_mask = cast(case_vneg); // -0.0 if h&2 else +0.0 - ssef rv = v ^ case_vneg_mask; // -v if h&2 else v (copy float sign) + float u = fade(fx); + float v = fade(fy); + float w = fade(fz); - ssef r = ru + rv; // ((h&1) ? -u : u) + ((h&2) ? -v : v) + float r = tri_mix(grad3(hash_uint3(X, Y, Z), fx, fy, fz), + grad3(hash_uint3(X + 1, Y, Z), fx - 1.0f, fy, fz), + grad3(hash_uint3(X, Y + 1, Z), fx, fy - 1.0f, fz), + grad3(hash_uint3(X + 1, Y + 1, Z), fx - 1.0f, fy - 1.0f, fz), + grad3(hash_uint3(X, Y, Z + 1), fx, fy, fz - 1.0f), + grad3(hash_uint3(X + 1, Y, Z + 1), fx - 1.0f, fy, fz - 1.0f), + grad3(hash_uint3(X, Y + 1, Z + 1), fx, fy - 1.0f, fz - 1.0f), + grad3(hash_uint3(X + 1, Y + 1, Z + 1), fx - 1.0f, fy - 1.0f, fz - 1.0f), + u, + v, + w); return r; } -#endif -#ifndef __KERNEL_SSE2__ -ccl_device float scale3(float result) -{ - return 0.9820f * result; -} -#else -ccl_device_inline ssef scale3_sse(const ssef &result) -{ - return ssef(0.9820f) * result; -} -#endif - -#ifndef __KERNEL_SSE2__ -ccl_device_noinline_cpu float perlin(float x, float y, float z) +ccl_device_noinline_cpu float perlin_4d(float x, float y, float z, float w) { int X; - float fx = floorfrac(x, &X); int Y; - float fy = floorfrac(y, &Y); int Z; + int W; + + float fx = floorfrac(x, &X); + float fy = floorfrac(y, &Y); float fz = floorfrac(z, &Z); + float fw = floorfrac(w, &W); float u = fade(fx); float v = fade(fy); - float w = fade(fz); + float t = fade(fz); + float s = fade(fw); + + float r = quad_mix( + grad4(hash_uint4(X, Y, Z, W), fx, fy, fz, fw), + grad4(hash_uint4(X + 1, Y, Z, W), fx - 1.0f, fy, fz, fw), + grad4(hash_uint4(X, Y + 1, Z, W), fx, fy - 1.0f, fz, fw), + grad4(hash_uint4(X + 1, Y + 1, Z, W), fx - 1.0f, fy - 1.0f, fz, fw), + grad4(hash_uint4(X, Y, Z + 1, W), fx, fy, fz - 1.0f, fw), + grad4(hash_uint4(X + 1, Y, Z + 1, W), fx - 1.0f, fy, fz - 1.0f, fw), + grad4(hash_uint4(X, Y + 1, Z + 1, W), fx, fy - 1.0f, fz - 1.0f, fw), + grad4(hash_uint4(X + 1, Y + 1, Z + 1, W), fx - 1.0f, fy - 1.0f, fz - 1.0f, fw), + grad4(hash_uint4(X, Y, Z, W + 1), fx, fy, fz, fw - 1.0f), + grad4(hash_uint4(X + 1, Y, Z, W + 1), fx - 1.0f, fy, fz, fw - 1.0f), + grad4(hash_uint4(X, Y + 1, Z, W + 1), fx, fy - 1.0f, fz, fw - 1.0f), + grad4(hash_uint4(X + 1, Y + 1, Z, W + 1), fx - 1.0f, fy - 1.0f, fz, fw - 1.0f), + grad4(hash_uint4(X, Y, Z + 1, W + 1), fx, fy, fz - 1.0f, fw - 1.0f), + grad4(hash_uint4(X + 1, Y, Z + 1, W + 1), fx - 1.0f, fy, fz - 1.0f, fw - 1.0f), + grad4(hash_uint4(X, Y + 1, Z + 1, W + 1), fx, fy - 1.0f, fz - 1.0f, fw - 1.0f), + grad4(hash_uint4(X + 1, Y + 1, Z + 1, W + 1), fx - 1.0f, fy - 1.0f, fz - 1.0f, fw - 1.0f), + u, + v, + t, + s); - float result; - - result = nerp( - w, - nerp(v, - nerp(u, - grad(hash_uint3(X, Y, Z), fx, fy, fz), - grad(hash_uint3(X + 1, Y, Z), fx - 1.0f, fy, fz)), - nerp(u, - grad(hash_uint3(X, Y + 1, Z), fx, fy - 1.0f, fz), - grad(hash_uint3(X + 1, Y + 1, Z), fx - 1.0f, fy - 1.0f, fz))), - nerp(v, - nerp(u, - grad(hash_uint3(X, Y, Z + 1), fx, fy, fz - 1.0f), - grad(hash_uint3(X + 1, Y, Z + 1), fx - 1.0f, fy, fz - 1.0f)), - nerp(u, - grad(hash_uint3(X, Y + 1, Z + 1), fx, fy - 1.0f, fz - 1.0f), - grad(hash_uint3(X + 1, Y + 1, Z + 1), fx - 1.0f, fy - 1.0f, fz - 1.0f)))); - float r = scale3(result); - - /* can happen for big coordinates, things even out to 0.0 then anyway */ - return (isfinite(r)) ? r : 0.0f; + return r; } + #else -ccl_device_noinline float perlin(float x, float y, float z) + +/* ** SSE Implementation ** */ + +/* SSE Bilinear Interpolation: + * + * The function takes two ssef inputs: + * - p : Contains the values at the points (v0, v1, v2, v3). + * - f : Contains the values (x, y, _, _). The third and fourth values are unused. + * + * The interpolation is done in two steps: + * 1. Interpolate (v0, v1) and (v2, v3) along the x axis to get g (g0, g1). + * (v2, v3) is generated by moving v2 and v3 to the first and second + * places of the ssef using the shuffle mask <2, 3, 2, 3>. The third and + * fourth values are unused. + * 2. Interplate g0 and g1 along the y axis to get the final value. + * g1 is generated by populating an ssef with the second value of g. + * Only the first value is important in the final ssef. + * + * v1 v3 g1 + * @ + + + + @ @ y + * + + (1) + (2) ^ + * + + ---> + ---> final | + * + + + | + * @ + + + + @ @ @------> x + * v0 v2 g0 + * + */ +ccl_device_inline ssef bi_mix(ssef p, ssef f) +{ + ssef g = mix(p, shuffle<2, 3, 2, 3>(p), shuffle<0>(f)); + return mix(g, shuffle<1>(g), shuffle<1>(f)); +} + +/* SSE Trilinear Interpolation: + * + * The function takes three ssef inputs: + * - p : Contains the values at the points (v0, v1, v2, v3). + * - q : Contains the values at the points (v4, v5, v6, v7). + * - f : Contains the values (x, y, z, _). The fourth value is unused. + * + * The interpolation is done in three steps: + * 1. Interpolate p and q along the x axis to get s (s0, s1, s2, s3). + * 2. Interpolate (s0, s1) and (s2, s3) along the y axis to get g (g0, g1). + * (s2, s3) is generated by moving v2 and v3 to the first and second + * places of the ssef using the shuffle mask <2, 3, 2, 3>. The third and + * fourth values are unused. + * 3. Interplate g0 and g1 along the z axis to get the final value. + * g1 is generated by populating an ssef with the second value of g. + * Only the first value is important in the final ssef. + * + * v3 v7 + * @ + + + + + + @ s3 @ + * +\ +\ +\ + * + \ + \ + \ + * + \ + \ + \ g1 + * + \ v1 + \ v5 + \ s1 @ + * + @ + + + +++ + @ + @ + z + * + + + + (1) + + (2) + (3) y ^ + * v2 @ + +++ + + + @ v6 + ---> s2 @ + ---> + ---> final \ | + * \ + \ + \ + + \ | + * \ + \ + \ + + \| + * \ + \ + \ + @ +---------> x + * \+ \+ \+ g0 + * @ + + + + + + @ @ + * v0 v4 s0 + */ +ccl_device_inline ssef tri_mix(ssef p, ssef q, ssef f) +{ + ssef s = mix(p, q, shuffle<0>(f)); + ssef g = mix(s, shuffle<2, 3, 2, 3>(s), shuffle<1>(f)); + return mix(g, shuffle<1>(g), shuffle<2>(f)); +} + +/* SSE Quadrilinear Interpolation: + * + * Quadrilinear interpolation is as simple as a linear interpolation + * between two trilinear interpolations. + * + */ +ccl_device_inline ssef quad_mix(ssef p, ssef q, ssef r, ssef s, ssef f) +{ + return mix(tri_mix(p, q, f), tri_mix(r, s, f), shuffle<3>(f)); +} + +ccl_device_inline ssef fade(const ssef &t) +{ + ssef a = madd(t, 6.0f, -15.0f); + ssef b = madd(t, a, 10.0f); + return (t * t) * (t * b); +} + +/* Negate val if the nth bit of h is 1. */ +# define negate_if_nth_bit(val, h, n) ((val) ^ cast(((h) & (1 << (n))) << (31 - (n)))) + +ccl_device_inline ssef grad(const ssei &hash, const ssef &x, const ssef &y) +{ + ssei h = hash & 7; + ssef u = select(h < 4, x, y); + ssef v = 2.0f * select(h < 4, y, x); + return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1); +} + +ccl_device_inline ssef grad(const ssei &hash, const ssef &x, const ssef &y, const ssef &z) +{ + ssei h = hash & 15; + ssef u = select(h < 8, x, y); + ssef vt = select((h == 12) | (h == 14), x, z); + ssef v = select(h < 4, y, vt); + return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1); +} + +ccl_device_inline ssef +grad(const ssei &hash, const ssef &x, const ssef &y, const ssef &z, const ssef &w) +{ + ssei h = hash & 31; + ssef u = select(h < 24, x, y); + ssef v = select(h < 16, y, z); + ssef s = select(h < 8, z, w); + return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1) + negate_if_nth_bit(s, h, 2); +} + +/* We use SSE to compute and interpolate 4 gradients at once: + * + * Point Offset from v0 + * v0 (0, 0) + * v1 (0, 1) + * v2 (1, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(V, V + 1)) + * v3 (1, 1) ^ + * | |__________| (0, 0, 1, 1) = shuffle<0, 0, 0, 0>(V, V + 1) + * | ^ + * |__________________________| + * + */ +ccl_device_noinline float perlin_2d(float x, float y) +{ + ssei XY; + ssef fxy = floorfrac(ssef(x, y, 0.0f, 0.0f), &XY); + ssef uv = fade(fxy); + + ssei XY1 = XY + 1; + ssei X = shuffle<0, 0, 0, 0>(XY, XY1); + ssei Y = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(XY, XY1)); + + ssei h = hash_ssei2(X, Y); + + ssef fxy1 = fxy - 1.0f; + ssef fx = shuffle<0, 0, 0, 0>(fxy, fxy1); + ssef fy = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(fxy, fxy1)); + + ssef g = grad(h, fx, fy); + + return extract<0>(bi_mix(g, uv)); +} + +/* We use SSE to compute and interpolate 4 gradients at once. Since we have 8 + * gradients in 3D, we need to compute two sets of gradients at the points: + * + * Point Offset from v0 + * v0 (0, 0, 0) + * v1 (0, 0, 1) + * v2 (0, 1, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1)) + * v3 (0, 1, 1) ^ + * | |__________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1) + * | ^ + * |__________________________| + * + * Point Offset from v0 + * v4 (1, 0, 0) + * v5 (1, 0, 1) + * v6 (1, 1, 0) + * v7 (1, 1, 1) + * + */ +ccl_device_noinline float perlin_3d(float x, float y, float z) { - ssef xyz = ssef(x, y, z, 0.0f); ssei XYZ; + ssef fxyz = floorfrac(ssef(x, y, z, 0.0f), &XYZ); + ssef uvw = fade(fxyz); - ssef fxyz = floorfrac_sse(xyz, &XYZ); + ssei XYZ1 = XYZ + 1; + ssei Y = shuffle<1, 1, 1, 1>(XYZ, XYZ1); + ssei Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZ, XYZ1)); - ssef uvw = fade_sse(&fxyz); - ssef u = shuffle<0>(uvw), v = shuffle<1>(uvw), w = shuffle<2>(uvw); + ssei h1 = hash_ssei3(shuffle<0>(XYZ), Y, Z); + ssei h2 = hash_ssei3(shuffle<0>(XYZ1), Y, Z); - ssei XYZ_ofc = XYZ + ssei(1); - ssei vdy = shuffle<1, 1, 1, 1>(XYZ, XYZ_ofc); // +0, +0, +1, +1 - ssei vdz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZ, XYZ_ofc)); // +0, +1, +0, +1 + ssef fxyz1 = fxyz - 1.0f; + ssef fy = shuffle<1, 1, 1, 1>(fxyz, fxyz1); + ssef fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyz, fxyz1)); - ssei h1 = hash_sse(shuffle<0>(XYZ), vdy, vdz); // hash directions 000, 001, 010, 011 - ssei h2 = hash_sse(shuffle<0>(XYZ_ofc), vdy, vdz); // hash directions 100, 101, 110, 111 + ssef g1 = grad(h1, shuffle<0>(fxyz), fy, fz); + ssef g2 = grad(h2, shuffle<0>(fxyz1), fy, fz); - ssef fxyz_ofc = fxyz - ssef(1.0f); - ssef vfy = shuffle<1, 1, 1, 1>(fxyz, fxyz_ofc); - ssef vfz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyz, fxyz_ofc)); + return extract<0>(tri_mix(g1, g2, uvw)); +} - ssef g1 = grad_sse(h1, shuffle<0>(fxyz), vfy, vfz); - ssef g2 = grad_sse(h2, shuffle<0>(fxyz_ofc), vfy, vfz); - ssef n1 = nerp_sse(u, g1, g2); +/* We use SSE to compute and interpolate 4 gradients at once. Since we have 16 + * gradients in 4D, we need to compute four sets of gradients at the points: + * + * Point Offset from v0 + * v0 (0, 0, 0, 0) + * v1 (0, 0, 1, 0) + * v2 (0, 1, 0, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1)) + * v3 (0, 1, 1, 0) ^ + * | |________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1) + * | ^ + * |_______________________| + * + * Point Offset from v0 + * v4 (1, 0, 0, 0) + * v5 (1, 0, 1, 0) + * v6 (1, 1, 0, 0) + * v7 (1, 1, 1, 0) + * + * Point Offset from v0 + * v8 (0, 0, 0, 1) + * v9 (0, 0, 1, 1) + * v10 (0, 1, 0, 1) + * v11 (0, 1, 1, 1) + * + * Point Offset from v0 + * v12 (1, 0, 0, 1) + * v13 (1, 0, 1, 1) + * v14 (1, 1, 0, 1) + * v15 (1, 1, 1, 1) + * + */ +ccl_device_noinline float perlin_4d(float x, float y, float z, float w) +{ + ssei XYZW; + ssef fxyzw = floorfrac(ssef(x, y, z, w), &XYZW); + ssef uvws = fade(fxyzw); - ssef n1_half = shuffle<2, 3, 2, 3>(n1); // extract 2 floats to a separate vector - ssef n2 = nerp_sse( - v, n1, n1_half); // process nerp([a, b, _, _], [c, d, _, _]) -> [a', b', _, _] + ssei XYZW1 = XYZW + 1; + ssei Y = shuffle<1, 1, 1, 1>(XYZW, XYZW1); + ssei Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZW, XYZW1)); - ssef n2_second = shuffle<1>(n2); // extract b to a separate vector - ssef result = nerp_sse( - w, n2, n2_second); // process nerp([a', _, _, _], [b', _, _, _]) -> [a'', _, _, _] + ssei h1 = hash_ssei4(shuffle<0>(XYZW), Y, Z, shuffle<3>(XYZW)); + ssei h2 = hash_ssei4(shuffle<0>(XYZW1), Y, Z, shuffle<3>(XYZW)); - ssef r = scale3_sse(result); + ssei h3 = hash_ssei4(shuffle<0>(XYZW), Y, Z, shuffle<3>(XYZW1)); + ssei h4 = hash_ssei4(shuffle<0>(XYZW1), Y, Z, shuffle<3>(XYZW1)); - ssef infmask = cast(ssei(0x7f800000)); - ssef rinfmask = ((r & infmask) == infmask).m128; // 0xffffffff if r is inf/-inf/nan else 0 - ssef rfinite = andnot(rinfmask, r); // 0 if r is inf/-inf/nan else r - return extract<0>(rfinite); + ssef fxyzw1 = fxyzw - 1.0f; + ssef fy = shuffle<1, 1, 1, 1>(fxyzw, fxyzw1); + ssef fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyzw, fxyzw1)); + + ssef g1 = grad(h1, shuffle<0>(fxyzw), fy, fz, shuffle<3>(fxyzw)); + ssef g2 = grad(h2, shuffle<0>(fxyzw1), fy, fz, shuffle<3>(fxyzw)); + + ssef g3 = grad(h3, shuffle<0>(fxyzw), fy, fz, shuffle<3>(fxyzw1)); + ssef g4 = grad(h4, shuffle<0>(fxyzw1), fy, fz, shuffle<3>(fxyzw1)); + + return extract<0>(quad_mix(g1, g2, g3, g4, uvws)); } #endif -/* perlin noise in range 0..1 */ -ccl_device float noise(float3 p) +/* Remap the output of noise to a predictable range [-1, 1]. + * The scale values were computed experimentally by the OSL developers. + */ + +ccl_device_inline float noise_scale1(float result) +{ + return 0.2500f * result; +} + +ccl_device_inline float noise_scale2(float result) +{ + return 0.6616f * result; +} + +ccl_device_inline float noise_scale3(float result) +{ + return 0.9820f * result; +} + +ccl_device_inline float noise_scale4(float result) +{ + return 0.8344f * result; +} + +/* Safe Signed And Unsigned Noise */ + +ccl_device_inline float snoise_1d(float p) +{ + float r = perlin_1d(p); + return isinf(r) ? 0.0f : noise_scale1(r); +} + +ccl_device_inline float noise_1d(float p) +{ + return 0.5f * snoise_1d(p) + 0.5f; +} + +ccl_device_inline float snoise_2d(float2 p) +{ + float r = perlin_2d(p.x, p.y); + return isinf(r) ? 0.0f : noise_scale2(r); +} + +ccl_device_inline float noise_2d(float2 p) +{ + return 0.5f * snoise_2d(p) + 0.5f; +} + +ccl_device_inline float snoise_3d(float3 p) +{ + float r = perlin_3d(p.x, p.y, p.z); + return isinf(r) ? 0.0f : noise_scale3(r); +} + +ccl_device_inline float noise_3d(float3 p) +{ + return 0.5f * snoise_3d(p) + 0.5f; +} + +ccl_device_inline float snoise_4d(float4 p) { - float r = perlin(p.x, p.y, p.z); - return 0.5f * r + 0.5f; + float r = perlin_4d(p.x, p.y, p.z, p.w); + return isinf(r) ? 0.0f : noise_scale4(r); } -/* perlin noise in range -1..1 */ -ccl_device float snoise(float3 p) +ccl_device_inline float noise_4d(float4 p) { - return perlin(p.x, p.y, p.z); + return 0.5f * snoise_4d(p) + 0.5f; } /* cell noise */ @@ -293,7 +613,7 @@ ccl_device float3 cellnoise3(float3 p) ssei ip_yxz = shuffle<1, 0, 2, 3>(ssei(ip.m128)); ssei ip_xyy = shuffle<0, 1, 1, 3>(ssei(ip.m128)); ssei ip_zzx = shuffle<2, 2, 0, 3>(ssei(ip.m128)); - ssei bits = hash_sse(ip_xyy, ip_yxz, ip_zzx); + ssei bits = hash_ssei3(ip_xyy, ip_yxz, ip_zzx); return float3(uint32_to_float(bits) * ssef(1.0f / (float)0xFFFFFFFF)); #endif } diff --git a/intern/cycles/kernel/svm/svm_noisetex.h b/intern/cycles/kernel/svm/svm_noisetex.h index 91dc11691e6..c5a1e43a729 100644 --- a/intern/cycles/kernel/svm/svm_noisetex.h +++ b/intern/cycles/kernel/svm/svm_noisetex.h @@ -16,44 +16,172 @@ CCL_NAMESPACE_BEGIN -/* Noise */ +/* The following offset functions generate random offsets to be added to texture + * coordinates to act as a seed since the noise functions don't have seed values. + * A seed value is needed for generating distortion textures and color outputs. + * The offset's components are in the range [100, 200], not too high to cause + * bad precision and not to small to be noticeable. We use float seed because + * OSL only support float hashes. + */ + +ccl_device_inline float random_float_offset(float seed) +{ + return 100.0f + hash_float_to_float(seed) * 100.0f; +} + +ccl_device_inline float2 random_float2_offset(float seed) +{ + return make_float2(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f, + 100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f); +} -ccl_device void svm_node_tex_noise( - KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) +ccl_device_inline float3 random_float3_offset(float seed) { - uint co_offset, scale_offset, detail_offset, distortion_offset, fac_offset, color_offset; + return make_float3(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f, + 100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f, + 100.0f + hash_float2_to_float(make_float2(seed, 2.0f)) * 100.0f); +} - svm_unpack_node_uchar4(node.y, &co_offset, &scale_offset, &detail_offset, &distortion_offset); - svm_unpack_node_uchar2(node.z, &color_offset, &fac_offset); +ccl_device_inline float4 random_float4_offset(float seed) +{ + return make_float4(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f, + 100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f, + 100.0f + hash_float2_to_float(make_float2(seed, 2.0f)) * 100.0f, + 100.0f + hash_float2_to_float(make_float2(seed, 3.0f)) * 100.0f); +} - uint4 node2 = read_node(kg, offset); +ccl_device void noise_texture_1d( + float co, float detail, float distortion, bool color_is_needed, float *value, float3 *color) +{ + float p = co; + if (distortion != 0.0f) { + p += noise_1d(p + random_float_offset(0.0f)) * distortion; + } + + *value = fractal_noise_1d(p, detail); + if (color_is_needed) { + *color = make_float3(*value, + fractal_noise_1d(p + random_float_offset(1.0f), detail), + fractal_noise_1d(p + random_float_offset(2.0f), detail)); + } +} + +ccl_device void noise_texture_2d( + float2 co, float detail, float distortion, bool color_is_needed, float *value, float3 *color) +{ + float2 p = co; + if (distortion != 0.0f) { + p += make_float2(noise_2d(p + random_float2_offset(0.0f)) * distortion, + noise_2d(p + random_float2_offset(1.0f)) * distortion); + } - float scale = stack_load_float_default(stack, scale_offset, node2.x); - float detail = stack_load_float_default(stack, detail_offset, node2.y); - float distortion = stack_load_float_default(stack, distortion_offset, node2.z); - float3 p = stack_load_float3(stack, co_offset) * scale; - int hard = 0; + *value = fractal_noise_2d(p, detail); + if (color_is_needed) { + *color = make_float3(*value, + fractal_noise_2d(p + random_float2_offset(2.0f), detail), + fractal_noise_2d(p + random_float2_offset(3.0f), detail)); + } +} +ccl_device void noise_texture_3d( + float3 co, float detail, float distortion, bool color_is_needed, float *value, float3 *color) +{ + float3 p = co; if (distortion != 0.0f) { - float3 r, offset = make_float3(13.5f, 13.5f, 13.5f); + p += make_float3(noise_3d(p + random_float3_offset(0.0f)) * distortion, + noise_3d(p + random_float3_offset(1.0f)) * distortion, + noise_3d(p + random_float3_offset(2.0f)) * distortion); + } - r.x = noise(p + offset) * distortion; - r.y = noise(p) * distortion; - r.z = noise(p - offset) * distortion; + *value = fractal_noise_3d(p, detail); + if (color_is_needed) { + *color = make_float3(*value, + fractal_noise_3d(p + random_float3_offset(3.0f), detail), + fractal_noise_3d(p + random_float3_offset(4.0f), detail)); + } +} - p += r; +ccl_device void noise_texture_4d( + float4 co, float detail, float distortion, bool color_is_needed, float *value, float3 *color) +{ + float4 p = co; + if (distortion != 0.0f) { + p += make_float4(noise_4d(p + random_float4_offset(0.0f)) * distortion, + noise_4d(p + random_float4_offset(1.0f)) * distortion, + noise_4d(p + random_float4_offset(2.0f)) * distortion, + noise_4d(p + random_float4_offset(3.0f)) * distortion); } - float f = noise_turbulence(p, detail, hard); + *value = fractal_noise_4d(p, detail); + if (color_is_needed) { + *color = make_float3(*value, + fractal_noise_4d(p + random_float4_offset(4.0f), detail), + fractal_noise_4d(p + random_float4_offset(5.0f), detail)); + } +} + +ccl_device void svm_node_tex_noise(KernelGlobals *kg, + ShaderData *sd, + float *stack, + uint dimensions, + uint offsets1, + uint offsets2, + int *offset) +{ + uint vector_stack_offset, w_stack_offset, scale_stack_offset, detail_stack_offset; + uint distortion_stack_offset, value_stack_offset, color_stack_offset; + + svm_unpack_node_uchar4( + offsets1, &vector_stack_offset, &w_stack_offset, &scale_stack_offset, &detail_stack_offset); + svm_unpack_node_uchar3( + offsets2, &distortion_stack_offset, &value_stack_offset, &color_stack_offset); + + uint4 defaults = read_node(kg, offset); + + float3 vector = stack_load_float3(stack, vector_stack_offset); + float w = stack_load_float_default(stack, w_stack_offset, defaults.x); + float scale = stack_load_float_default(stack, scale_stack_offset, defaults.y); + float detail = stack_load_float_default(stack, detail_stack_offset, defaults.z); + float distortion = stack_load_float_default(stack, distortion_stack_offset, defaults.w); + + vector *= scale; + w *= scale; + + float value; + float3 color; + switch (dimensions) { + case 1: + noise_texture_1d(w, detail, distortion, stack_valid(color_stack_offset), &value, &color); + break; + case 2: + noise_texture_2d(make_float2(vector.x, vector.y), + detail, + distortion, + stack_valid(color_stack_offset), + &value, + &color); + break; + case 3: + noise_texture_3d( + vector, detail, distortion, stack_valid(color_stack_offset), &value, &color); + break; + case 4: + noise_texture_4d(make_float4(vector.x, vector.y, vector.z, w), + detail, + distortion, + stack_valid(color_stack_offset), + &value, + &color); + break; + default: + kernel_assert(0); + } - if (stack_valid(fac_offset)) { - stack_store_float(stack, fac_offset, f); + if (stack_valid(value_stack_offset)) { + stack_store_float(stack, value_stack_offset, value); } - if (stack_valid(color_offset)) { - float3 color = make_float3(f, - noise_turbulence(make_float3(p.y, p.x, p.z), detail, hard), - noise_turbulence(make_float3(p.y, p.z, p.x), detail, hard)); - stack_store_float3(stack, color_offset, color); + if (stack_valid(color_stack_offset)) { + stack_store_float3(stack, color_stack_offset, color); } } diff --git a/intern/cycles/kernel/svm/svm_texture.h b/intern/cycles/kernel/svm/svm_texture.h deleted file mode 100644 index 290aa85c831..00000000000 --- a/intern/cycles/kernel/svm/svm_texture.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2011-2013 Blender Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -CCL_NAMESPACE_BEGIN - -/* Turbulence */ - -ccl_device_noinline float noise_turbulence(float3 p, float octaves, int hard) -{ - float fscale = 1.0f; - float amp = 1.0f; - float sum = 0.0f; - int i, n; - - octaves = clamp(octaves, 0.0f, 16.0f); - n = float_to_int(octaves); - - for (i = 0; i <= n; i++) { - float t = noise(fscale * p); - - if (hard) - t = fabsf(2.0f * t - 1.0f); - - sum += t * amp; - amp *= 0.5f; - fscale *= 2.0f; - } - - float rmd = octaves - floorf(octaves); - - if (rmd != 0.0f) { - float t = noise(fscale * p); - - if (hard) - t = fabsf(2.0f * t - 1.0f); - - float sum2 = sum + t * amp; - - sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); - sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); - - return (1.0f - rmd) * sum + rmd * sum2; - } - else { - sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); - return sum; - } -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/svm_wave.h b/intern/cycles/kernel/svm/svm_wave.h index baaa89ab0cb..402c1c87414 100644 --- a/intern/cycles/kernel/svm/svm_wave.h +++ b/intern/cycles/kernel/svm/svm_wave.h @@ -33,7 +33,7 @@ ccl_device_noinline_cpu float svm_wave(NodeWaveType type, n = len(p) * 20.0f; if (distortion != 0.0f) - n += distortion * noise_turbulence(p * dscale, detail, 0); + n += distortion * fractal_noise_3d(p * dscale, detail); if (profile == NODE_WAVE_PROFILE_SIN) { return 0.5f + 0.5f * sinf(n); diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index bf8185d2b38..24aa9589220 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -893,14 +893,22 @@ NODE_DEFINE(NoiseTextureNode) TEXTURE_MAPPING_DEFINE(NoiseTextureNode); + static NodeEnum dimensions_enum; + dimensions_enum.insert("1D", 1); + dimensions_enum.insert("2D", 2); + dimensions_enum.insert("3D", 3); + dimensions_enum.insert("4D", 4); + SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3); + + SOCKET_IN_POINT( + vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + SOCKET_IN_FLOAT(w, "W", 0.0f); SOCKET_IN_FLOAT(scale, "Scale", 1.0f); SOCKET_IN_FLOAT(detail, "Detail", 2.0f); SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f); - SOCKET_IN_POINT( - vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - SOCKET_OUT_COLOR(color, "Color"); SOCKET_OUT_FLOAT(fac, "Fac"); + SOCKET_OUT_COLOR(color, "Color"); return type; } @@ -911,31 +919,40 @@ NoiseTextureNode::NoiseTextureNode() : TextureNode(node_type) void NoiseTextureNode::compile(SVMCompiler &compiler) { - ShaderInput *distortion_in = input("Distortion"); - ShaderInput *detail_in = input("Detail"); - ShaderInput *scale_in = input("Scale"); ShaderInput *vector_in = input("Vector"); - ShaderOutput *color_out = output("Color"); + ShaderInput *w_in = input("W"); + ShaderInput *scale_in = input("Scale"); + ShaderInput *detail_in = input("Detail"); + ShaderInput *distortion_in = input("Distortion"); ShaderOutput *fac_out = output("Fac"); + ShaderOutput *color_out = output("Color"); - int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in); + int w_stack_offset = compiler.stack_assign_if_linked(w_in); + int scale_stack_offset = compiler.stack_assign_if_linked(scale_in); + int detail_stack_offset = compiler.stack_assign_if_linked(detail_in); + int distortion_stack_offset = compiler.stack_assign_if_linked(distortion_in); + int fac_stack_offset = compiler.stack_assign_if_linked(fac_out); + int color_stack_offset = compiler.stack_assign_if_linked(color_out); - compiler.add_node(NODE_TEX_NOISE, - compiler.encode_uchar4(vector_offset, - compiler.stack_assign_if_linked(scale_in), - compiler.stack_assign_if_linked(detail_in), - compiler.stack_assign_if_linked(distortion_in)), - compiler.encode_uchar4(compiler.stack_assign_if_linked(color_out), - compiler.stack_assign_if_linked(fac_out))); - compiler.add_node(__float_as_int(scale), __float_as_int(detail), __float_as_int(distortion)); + compiler.add_node( + NODE_TEX_NOISE, + dimensions, + compiler.encode_uchar4( + vector_stack_offset, w_stack_offset, scale_stack_offset, detail_stack_offset), + compiler.encode_uchar4(distortion_stack_offset, fac_stack_offset, color_stack_offset)); + compiler.add_node(__float_as_int(w), + __float_as_int(scale), + __float_as_int(detail), + __float_as_int(distortion)); - tex_mapping.compile_end(compiler, vector_in, vector_offset); + tex_mapping.compile_end(compiler, vector_in, vector_stack_offset); } void NoiseTextureNode::compile(OSLCompiler &compiler) { tex_mapping.compile(compiler); - + compiler.parameter(this, "dimensions"); compiler.add(this, "node_noise_texture"); } diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index fbed2ff0ef6..271d60d16b7 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -206,7 +206,8 @@ class NoiseTextureNode : public TextureNode { public: SHADER_NODE_CLASS(NoiseTextureNode) - float scale, detail, distortion; + int dimensions; + float w, scale, detail, distortion; float3 vector; }; diff --git a/intern/cycles/util/util_hash.h b/intern/cycles/util/util_hash.h index 2b1f26de03d..53140e40fc9 100644 --- a/intern/cycles/util/util_hash.h +++ b/intern/cycles/util/util_hash.h @@ -213,6 +213,109 @@ ccl_device_inline float3 hash_float4_to_float3(float4 k) hash_float4_to_float(make_float4(k.w, k.z, k.y, k.x))); } +/* SSE Versions Of Jenkins Lookup3 Hash Functions */ + +#ifdef __KERNEL_SSE2__ +# define rot(x, k) (((x) << (k)) | (srl(x, 32 - (k)))) + +# define mix(a, b, c) \ + { \ + a -= c; \ + a ^= rot(c, 4); \ + c += b; \ + b -= a; \ + b ^= rot(a, 6); \ + a += c; \ + c -= b; \ + c ^= rot(b, 8); \ + b += a; \ + a -= c; \ + a ^= rot(c, 16); \ + c += b; \ + b -= a; \ + b ^= rot(a, 19); \ + a += c; \ + c -= b; \ + c ^= rot(b, 4); \ + b += a; \ + } + +# define final(a, b, c) \ + { \ + c ^= b; \ + c -= rot(b, 14); \ + a ^= c; \ + a -= rot(c, 11); \ + b ^= a; \ + b -= rot(a, 25); \ + c ^= b; \ + c -= rot(b, 16); \ + a ^= c; \ + a -= rot(c, 4); \ + b ^= a; \ + b -= rot(a, 14); \ + c ^= b; \ + c -= rot(b, 24); \ + } + +ccl_device_inline ssei hash_ssei(ssei kx) +{ + ssei a, b, c; + a = b = c = ssei(0xdeadbeef + (1 << 2) + 13); + + a += kx; + final(a, b, c); + + return c; +} + +ccl_device_inline ssei hash_ssei2(ssei kx, ssei ky) +{ + ssei a, b, c; + a = b = c = ssei(0xdeadbeef + (2 << 2) + 13); + + b += ky; + a += kx; + final(a, b, c); + + return c; +} + +ccl_device_inline ssei hash_ssei3(ssei kx, ssei ky, ssei kz) +{ + ssei a, b, c; + a = b = c = ssei(0xdeadbeef + (3 << 2) + 13); + + c += kz; + b += ky; + a += kx; + final(a, b, c); + + return c; +} + +ccl_device_inline ssei hash_ssei4(ssei kx, ssei ky, ssei kz, ssei kw) +{ + ssei a, b, c; + a = b = c = ssei(0xdeadbeef + (4 << 2) + 13); + + a += kx; + b += ky; + c += kz; + mix(a, b, c); + + a += kw; + final(a, b, c); + + return c; +} + +# undef rot +# undef final +# undef mix + +#endif + #ifndef __KERNEL_GPU__ static inline uint hash_string(const char *str) { diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index ebddd56bd40..17bb766445d 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -318,6 +318,12 @@ ccl_device_inline int quick_floor_to_int(float x) return float_to_int(x) - ((x < 0) ? 1 : 0); } +ccl_device_inline float floorfrac(float x, int *i) +{ + *i = quick_floor_to_int(x); + return x - *i; +} + ccl_device_inline int ceil_to_int(float f) { return float_to_int(ceilf(f)); diff --git a/intern/cycles/util/util_ssef.h b/intern/cycles/util/util_ssef.h index e6610dbb197..fa525daf37c 100644 --- a/intern/cycles/util/util_ssef.h +++ b/intern/cycles/util/util_ssef.h @@ -523,13 +523,29 @@ __forceinline ssei truncatei(const ssef &a) return _mm_cvttps_epi32(a.m128); } +/* This is about 25% faster than straightforward floor to integer conversion + * due to better pipelining. + * + * Unsaturated add 0xffffffff (a < 0) is the same as subtract -1. + */ __forceinline ssei floori(const ssef &a) { -# if defined(__KERNEL_SSE41__) - return ssei(floor(a)); -# else - return ssei(a - ssef(0.5f)); -# endif + return truncatei(a) + cast((a < 0.0f).m128); +} + +__forceinline ssef floorfrac(const ssef &x, ssei *i) +{ + *i = floori(x); + return x - ssef(*i); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Common Functions +//////////////////////////////////////////////////////////////////////////////// + +__forceinline ssef mix(const ssef &a, const ssef &b, const ssef &t) +{ + return madd(t, b, (ssef(1.0f) - t) * a); } //////////////////////////////////////////////////////////////////////////////// diff --git a/intern/cycles/util/util_ssei.h b/intern/cycles/util/util_ssei.h index 86429260a0e..e2bf81310cc 100644 --- a/intern/cycles/util/util_ssei.h +++ b/intern/cycles/util/util_ssei.h @@ -310,6 +310,15 @@ __forceinline ssei &operator|=(ssei &a, const int32_t &b) return a = a | b; } +__forceinline ssei &operator^=(ssei &a, const ssei &b) +{ + return a = a ^ b; +} +__forceinline ssei &operator^=(ssei &a, const int32_t &b) +{ + return a = a ^ b; +} + __forceinline ssei &operator<<=(ssei &a, const int32_t &b) { return a = a << b; diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c index a3e9b8dc206..6a99ba2db58 100644 --- a/source/blender/blenloader/intern/versioning_cycles.c +++ b/source/blender/blenloader/intern/versioning_cycles.c @@ -756,6 +756,19 @@ static void update_vector_math_node_average_operator(bNodeTree *ntree) } } +/* The Noise node now have a dimension property. This property should be + * initialized to 3 by default. + */ +static void update_noise_node_dimensions(bNodeTree *ntree) +{ + for (bNode *node = ntree->nodes.first; node; node = node->next) { + if (node->type == SH_NODE_TEX_NOISE) { + NodeTexNoise *tex = (NodeTexNoise *)node->storage; + tex->dimensions = 3; + } + } +} + void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bmain) { /* Particle shape shared with Eevee. */ @@ -928,4 +941,13 @@ void do_versions_after_linking_cycles(Main *bmain) } FOREACH_NODETREE_END; } + + if (!MAIN_VERSION_ATLEAST(bmain, 281, 4)) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_SHADER) { + update_noise_node_dimensions(ntree); + } + } + FOREACH_NODETREE_END; + } } diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index b89f163f579..47433693e7b 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -948,6 +948,11 @@ static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), uiItemR(layout, ptr, "feature", 0, "", ICON_NONE); } +static void node_shader_buts_tex_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "dimensions", 0, "", ICON_NONE); +} + static void node_shader_buts_tex_pointdensity(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1267,6 +1272,9 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_TEX_VORONOI: ntype->draw_buttons = node_shader_buts_tex_voronoi; break; + case SH_NODE_TEX_NOISE: + ntype->draw_buttons = node_shader_buts_tex_noise; + break; case SH_NODE_TEX_POINTDENSITY: ntype->draw_buttons = node_shader_buts_tex_pointdensity; break; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl index 2a925c2a622..701b07b4aae 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl @@ -1,4 +1,89 @@ -float noise_turbulence(vec3 p, float octaves, int hard) +/* The fractal_noise functions are all exactly the same except for the input type. */ +float fractal_noise(float p, float octaves) +{ + float fscale = 1.0; + float amp = 1.0; + float sum = 0.0; + octaves = clamp(octaves, 0.0, 16.0); + int n = int(octaves); + for (int i = 0; i <= n; i++) { + float t = noise(fscale * p); + sum += t * amp; + amp *= 0.5; + fscale *= 2.0; + } + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float t = noise(fscale * p); + float sum2 = sum + t * amp; + sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); + sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1)); + return (1.0 - rmd) * sum + rmd * sum2; + } + else { + sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); + return sum; + } +} + +/* The fractal_noise functions are all exactly the same except for the input type. */ +float fractal_noise(vec2 p, float octaves) +{ + float fscale = 1.0; + float amp = 1.0; + float sum = 0.0; + octaves = clamp(octaves, 0.0, 16.0); + int n = int(octaves); + for (int i = 0; i <= n; i++) { + float t = noise(fscale * p); + sum += t * amp; + amp *= 0.5; + fscale *= 2.0; + } + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float t = noise(fscale * p); + float sum2 = sum + t * amp; + sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); + sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1)); + return (1.0 - rmd) * sum + rmd * sum2; + } + else { + sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); + return sum; + } +} + +/* The fractal_noise functions are all exactly the same except for the input type. */ +float fractal_noise(vec3 p, float octaves) +{ + float fscale = 1.0; + float amp = 1.0; + float sum = 0.0; + octaves = clamp(octaves, 0.0, 16.0); + int n = int(octaves); + for (int i = 0; i <= n; i++) { + float t = noise(fscale * p); + sum += t * amp; + amp *= 0.5; + fscale *= 2.0; + } + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float t = noise(fscale * p); + float sum2 = sum + t * amp; + sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); + sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1)); + return (1.0 - rmd) * sum + rmd * sum2; + } + else { + sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); + return sum; + } +} + +/* The fractal_noise functions are all exactly the same except for the input type. */ +float fractal_noise(vec4 p, float octaves) { float fscale = 1.0; float amp = 1.0; @@ -7,9 +92,6 @@ float noise_turbulence(vec3 p, float octaves, int hard) int n = int(octaves); for (int i = 0; i <= n; i++) { float t = noise(fscale * p); - if (hard != 0) { - t = abs(2.0 * t - 1.0); - } sum += t * amp; amp *= 0.5; fscale *= 2.0; @@ -17,9 +99,6 @@ float noise_turbulence(vec3 p, float octaves, int hard) float rmd = octaves - floor(octaves); if (rmd != 0.0) { float t = noise(fscale * p); - if (hard != 0) { - t = abs(2.0 * t - 1.0); - } float sum2 = sum + t * amp; sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1)); 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 8c6a10e3fe7..c184c61c269 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_noise.glsl @@ -1,16 +1,106 @@ -float noise_fade(float t) +/* Bilinear Interpolation: + * + * v2 v3 + * @ + + + + @ y + * + + ^ + * + + | + * + + | + * @ + + + + @ @------> x + * v0 v1 + * + */ +float bi_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 + */ +float tri_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)); +} + +float quad_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(tri_mix(v0, v1, v2, v3, v4, v5, v6, v7, x, y, z), + tri_mix(v8, v9, v10, v11, v12, v13, v14, v15, x, y, z), + w); +} + +float fade(float t) { return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); } -float noise_scale3(float result) +float negate_if(float value, uint condition) { - return 0.9820 * result; + return (condition != 0u) ? -value : value; } -float noise_nerp(float t, float a, float b) +float noise_grad(uint hash, float x) { - return (1.0 - t) * a + t * b; + uint h = hash & 15u; + float g = 1u + (h & 7u); + return negate_if(g, h & 8u) * x; +} + +float noise_grad(uint hash, float x, float y) +{ + uint 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); } float noise_grad(uint hash, float x, float y, float z) @@ -19,56 +109,186 @@ float noise_grad(uint hash, float x, float y, float z) float u = h < 8u ? x : y; float vt = ((h == 12u) || (h == 14u)) ? x : z; float v = h < 4u ? y : vt; - return (((h & 1u) != 0u) ? -u : u) + (((h & 2u) != 0u) ? -v : v); + return negate_if(u, h & 1u) + negate_if(v, h & 2u); +} + +float noise_grad(uint hash, float x, float y, float z, float w) +{ + uint 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); } -float noise_perlin(float x, float y, float z) +float noise_perlin(float x) { int X; float fx = floorfrac(x, X); + float u = fade(fx); + + float r = mix(noise_grad(hash_int(X), fx), noise_grad(hash_int(X + 1), fx - 1.0), u); + + return r; +} + +float noise_perlin(vec2 vec) +{ + int X; + int Y; + + float fx = floorfrac(vec.x, X); + float fy = floorfrac(vec.y, Y); + + float u = fade(fx); + float v = fade(fy); + + float r = bi_mix(noise_grad(hash_int2(X, Y), fx, fy), + noise_grad(hash_int2(X + 1, Y), fx - 1.0, fy), + noise_grad(hash_int2(X, Y + 1), fx, fy - 1.0), + noise_grad(hash_int2(X + 1, Y + 1), fx - 1.0, fy - 1.0), + u, + v); + + return r; +} + +float noise_perlin(vec3 vec) +{ + int X; int Y; - float fy = floorfrac(y, Y); int Z; - float fz = floorfrac(z, Z); - float u = noise_fade(fx); - float v = noise_fade(fy); - float w = noise_fade(fz); + float fx = floorfrac(vec.x, X); + float fy = floorfrac(vec.y, Y); + float fz = floorfrac(vec.z, Z); + + float u = fade(fx); + float v = fade(fy); + float w = fade(fz); - float noise_u[2], noise_v[2]; + float r = tri_mix(noise_grad(hash_int3(X, Y, Z), fx, fy, fz), + noise_grad(hash_int3(X + 1, Y, Z), fx - 1, fy, fz), + noise_grad(hash_int3(X, Y + 1, Z), fx, fy - 1, fz), + noise_grad(hash_int3(X + 1, Y + 1, Z), fx - 1, fy - 1, fz), + noise_grad(hash_int3(X, Y, Z + 1), fx, fy, fz - 1), + noise_grad(hash_int3(X + 1, Y, Z + 1), fx - 1, fy, fz - 1), + noise_grad(hash_int3(X, Y + 1, Z + 1), fx, fy - 1, fz - 1), + noise_grad(hash_int3(X + 1, Y + 1, Z + 1), fx - 1, fy - 1, fz - 1), + u, + v, + w); - noise_u[0] = noise_nerp(u, - noise_grad(hash_int3(X, Y, Z), fx, fy, fz), - noise_grad(hash_int3(X + 1, Y, Z), fx - 1.0, fy, fz)); + return r; +} - noise_u[1] = noise_nerp(u, - noise_grad(hash_int3(X, Y + 1, Z), fx, fy - 1.0, fz), - noise_grad(hash_int3(X + 1, Y + 1, Z), fx - 1.0, fy - 1.0, fz)); +float noise_perlin(vec4 vec) +{ + int X; + int Y; + int Z; + int W; - noise_v[0] = noise_nerp(v, noise_u[0], noise_u[1]); + float fx = floorfrac(vec.x, X); + float fy = floorfrac(vec.y, Y); + float fz = floorfrac(vec.z, Z); + float fw = floorfrac(vec.w, W); - noise_u[0] = noise_nerp(u, - noise_grad(hash_int3(X, Y, Z + 1), fx, fy, fz - 1.0), - noise_grad(hash_int3(X + 1, Y, Z + 1), fx - 1.0, fy, fz - 1.0)); + float u = fade(fx); + float v = fade(fy); + float t = fade(fz); + float s = fade(fw); - noise_u[1] = noise_nerp( + float r = quad_mix( + noise_grad(hash_int4(X, Y, Z, W), fx, fy, fz, fw), + noise_grad(hash_int4(X + 1, Y, Z, W), fx - 1.0, fy, fz, fw), + noise_grad(hash_int4(X, Y + 1, Z, W), fx, fy - 1.0, fz, fw), + noise_grad(hash_int4(X + 1, Y + 1, Z, W), fx - 1.0, fy - 1.0, fz, fw), + noise_grad(hash_int4(X, Y, Z + 1, W), fx, fy, fz - 1.0, fw), + noise_grad(hash_int4(X + 1, Y, Z + 1, W), fx - 1.0, fy, fz - 1.0, fw), + noise_grad(hash_int4(X, Y + 1, Z + 1, W), fx, fy - 1.0, fz - 1.0, fw), + noise_grad(hash_int4(X + 1, Y + 1, Z + 1, W), fx - 1.0, fy - 1.0, fz - 1.0, fw), + noise_grad(hash_int4(X, Y, Z, W + 1), fx, fy, fz, fw - 1.0), + noise_grad(hash_int4(X + 1, Y, Z, W + 1), fx - 1.0, fy, fz, fw - 1.0), + noise_grad(hash_int4(X, Y + 1, Z, W + 1), fx, fy - 1.0, fz, fw - 1.0), + noise_grad(hash_int4(X + 1, Y + 1, Z, W + 1), fx - 1.0, fy - 1.0, fz, fw - 1.0), + noise_grad(hash_int4(X, Y, Z + 1, W + 1), fx, fy, fz - 1.0, fw - 1.0), + noise_grad(hash_int4(X + 1, Y, Z + 1, W + 1), fx - 1.0, fy, fz - 1.0, fw - 1.0), + noise_grad(hash_int4(X, Y + 1, Z + 1, W + 1), fx, fy - 1.0, fz - 1.0, fw - 1.0), + noise_grad(hash_int4(X + 1, Y + 1, Z + 1, W + 1), fx - 1.0, fy - 1.0, fz - 1.0, fw - 1.0), u, - noise_grad(hash_int3(X, Y + 1, Z + 1), fx, fy - 1.0, fz - 1.0), - noise_grad(hash_int3(X + 1, Y + 1, Z + 1), fx - 1.0, fy - 1.0, fz - 1.0)); + v, + t, + s); - noise_v[1] = noise_nerp(v, noise_u[0], noise_u[1]); + return r; +} - float r = noise_scale3(noise_nerp(w, noise_v[0], noise_v[1])); +/* Remap the output of noise to a predictable range [-1, 1]. + * The scale values were computed experimentally by the OSL developers. + */ +float noise_scale1(float result) +{ + return 0.2500 * result; +} - return (isinf(r)) ? 0.0 : r; +float noise_scale2(float result) +{ + return 0.6616 * result; } -float noise(vec3 p) +float noise_scale3(float result) +{ + return 0.9820 * result; +} + +float noise_scale4(float result) +{ + return 0.8344 * result; +} + +/* Safe Signed And Unsigned Noise */ + +float snoise(float p) +{ + float r = noise_perlin(p); + return (isinf(r)) ? 0.0 : noise_scale1(r); +} + +float noise(float p) +{ + return 0.5 * snoise(p) + 0.5; +} + +float snoise(vec2 p) { - return 0.5 * noise_perlin(p.x, p.y, p.z) + 0.5; + float r = noise_perlin(p); + return (isinf(r)) ? 0.0 : noise_scale2(r); +} + +float noise(vec2 p) +{ + return 0.5 * snoise(p) + 0.5; } float snoise(vec3 p) { - return noise_perlin(p.x, p.y, p.z); + float r = noise_perlin(p); + return (isinf(r)) ? 0.0 : noise_scale3(r); +} + +float noise(vec3 p) +{ + return 0.5 * snoise(p) + 0.5; +} + +float snoise(vec4 p) +{ + float r = noise_perlin(p); + return (isinf(r)) ? 0.0 : noise_scale4(r); +} + +float noise(vec4 p) +{ + return 0.5 * snoise(p) + 0.5; } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl index 30e27da16e8..e56b4a1d135 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl @@ -1,19 +1,99 @@ -void node_tex_noise( - vec3 co, float scale, float detail, float distortion, out vec4 color, out float fac) +/* The following offset functions generate random offsets to be added to texture + * coordinates to act as a seed since the noise functions don't have seed values. + * A seed value is needed for generating distortion textures and color outputs. + * The offset's components are in the range [100, 200], not too high to cause + * bad precision and not to small to be noticeable. We use float seed because + * OSL only support float hashes. + */ + +float random_float_offset(float seed) +{ + return 100.0 + hash_float_to_float(seed) * 100.0; +} + +vec2 random_vec2_offset(float seed) +{ + return vec2(100.0 + hash_vec2_to_float(vec2(seed, 0.0)) * 100.0, + 100.0 + hash_vec2_to_float(vec2(seed, 1.0)) * 100.0); +} + +vec3 random_vec3_offset(float seed) +{ + return vec3(100.0 + hash_vec2_to_float(vec2(seed, 0.0)) * 100.0, + 100.0 + hash_vec2_to_float(vec2(seed, 1.0)) * 100.0, + 100.0 + hash_vec2_to_float(vec2(seed, 2.0)) * 100.0); +} + +vec4 random_vec4_offset(float seed) +{ + return vec4(100.0 + hash_vec2_to_float(vec2(seed, 0.0)) * 100.0, + 100.0 + hash_vec2_to_float(vec2(seed, 1.0)) * 100.0, + 100.0 + hash_vec2_to_float(vec2(seed, 2.0)) * 100.0, + 100.0 + hash_vec2_to_float(vec2(seed, 3.0)) * 100.0); +} + +void node_noise_texture_1d( + vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color) +{ + float p = w * scale; + if (distortion != 0.0) { + p += noise(p + random_float_offset(0.0)) * distortion; + } + + value = fractal_noise(p, detail); + color = vec4(value, + fractal_noise(p + random_float_offset(1.0), detail), + fractal_noise(p + random_float_offset(2.0), detail), + 1.0); +} + +void node_noise_texture_2d( + vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color) +{ + vec2 p = co.xy * scale; + if (distortion != 0.0) { + p += vec2(noise(p + random_vec2_offset(0.0)) * distortion, + noise(p + random_vec2_offset(1.0)) * distortion); + } + + value = fractal_noise(p, detail); + color = vec4(value, + fractal_noise(p + random_vec2_offset(2.0), detail), + fractal_noise(p + random_vec2_offset(3.0), detail), + 1.0); +} + +void node_noise_texture_3d( + vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color) { vec3 p = co * scale; - int hard = 0; if (distortion != 0.0) { - vec3 r, offset = vec3(13.5, 13.5, 13.5); - r.x = noise(p + offset) * distortion; - r.y = noise(p) * distortion; - r.z = noise(p - offset) * distortion; - p += r; + p += vec3(noise(p + random_vec3_offset(0.0)) * distortion, + noise(p + random_vec3_offset(1.0)) * distortion, + noise(p + random_vec3_offset(2.0)) * distortion); + } + + value = fractal_noise(p, detail); + color = vec4(value, + fractal_noise(p + random_vec3_offset(3.0), detail), + fractal_noise(p + random_vec3_offset(4.0), detail), + 1.0); +} + +void node_noise_texture_4d( + vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color) +{ + vec4 p = vec4(co, w) * scale; + if (distortion != 0.0) { + p += vec4(noise(p + random_vec4_offset(0.0)) * distortion, + noise(p + random_vec4_offset(1.0)) * distortion, + noise(p + random_vec4_offset(2.0)) * distortion, + noise(p + random_vec4_offset(3.0)) * distortion); } - fac = noise_turbulence(p, detail, hard); - color = vec4(fac, - noise_turbulence(vec3(p.y, p.x, p.z), detail, hard), - noise_turbulence(vec3(p.y, p.z, p.x), detail, hard), - 1); + value = fractal_noise(p, detail); + color = vec4(value, + fractal_noise(p + random_vec4_offset(4.0), detail), + fractal_noise(p + random_vec4_offset(5.0), detail), + 1.0); } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index af66add01f3..0787f41b810 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -869,6 +869,8 @@ typedef struct NodeTexGradient { typedef struct NodeTexNoise { NodeTexBase base; + int dimensions; + char _pad[4]; } NodeTexNoise; typedef struct NodeTexVoronoi { diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 0909aa42a4d..988533e0f0e 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4346,8 +4346,17 @@ static void def_sh_tex_gradient(StructRNA *srna) static void def_sh_tex_noise(StructRNA *srna) { + PropertyRNA *prop; + RNA_def_struct_sdna_from(srna, "NodeTexNoise", "storage"); def_sh_tex(srna); + + prop = RNA_def_property(srna, "dimensions", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "dimensions"); + RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items); + RNA_def_property_ui_text( + prop, "Dimensions", "The dimensions of the space to evaluate the noise in"); + RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update"); } static void def_sh_tex_checker(StructRNA *srna) @@ -4516,7 +4525,7 @@ static void def_sh_tex_white_noise(StructRNA *srna) RNA_def_property_enum_sdna(prop, NULL, "custom1"); RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items); RNA_def_property_ui_text( - prop, "Dimensions", "The number of dimensions to evaluate the noise in"); + prop, "Dimensions", "The dimensions of the space to evaluate the noise in"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c index 34c4b17f255..8c35591d112 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c @@ -23,6 +23,7 @@ static bNodeSocketTemplate sh_node_tex_noise_in[] = { {SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, + {SOCK_FLOAT, 1, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f}, {SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f}, {SOCK_FLOAT, 1, N_("Detail"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 16.0f}, {SOCK_FLOAT, 1, N_("Distortion"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f}, @@ -30,27 +31,27 @@ static bNodeSocketTemplate sh_node_tex_noise_in[] = { }; static bNodeSocketTemplate sh_node_tex_noise_out[] = { - {SOCK_RGBA, + {SOCK_FLOAT, 0, - N_("Color"), + N_("Fac"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, - PROP_NONE, + PROP_FACTOR, SOCK_NO_INTERNAL_LINK}, - {SOCK_FLOAT, + {SOCK_RGBA, 0, - N_("Fac"), + N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, - PROP_FACTOR, + PROP_NONE, SOCK_NO_INTERNAL_LINK}, {-1, 0, ""}, }; @@ -60,6 +61,7 @@ static void node_shader_init_tex_noise(bNodeTree *UNUSED(ntree), bNode *node) NodeTexNoise *tex = MEM_callocN(sizeof(NodeTexNoise), "NodeTexNoise"); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); + tex->dimensions = 3; node->storage = tex; } @@ -74,10 +76,27 @@ static int node_shader_gpu_tex_noise(GPUMaterial *mat, in[0].link = GPU_attribute(CD_ORCO, ""); GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link); } - node_shader_gpu_tex_mapping(mat, node, in, out); - return GPU_stack_link(mat, node, "node_tex_noise", in, out); + NodeTexNoise *tex = (NodeTexNoise *)node->storage; + static const char *names[] = { + "", + "node_noise_texture_1d", + "node_noise_texture_2d", + "node_noise_texture_3d", + "node_noise_texture_4d", + }; + return GPU_stack_link(mat, node, names[tex->dimensions], in, out); +} + +static void node_shader_update_tex_noise(bNodeTree *UNUSED(ntree), bNode *node) +{ + bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector"); + bNodeSocket *sockW = nodeFindSocket(node, SOCK_IN, "W"); + + NodeTexNoise *tex = (NodeTexNoise *)node->storage; + nodeSetSocketAvailability(sockVector, tex->dimensions != 1); + nodeSetSocketAvailability(sockW, tex->dimensions == 1 || tex->dimensions == 4); } /* node type definition */ @@ -91,6 +110,7 @@ void register_node_type_sh_tex_noise(void) node_type_storage( &ntype, "NodeTexNoise", node_free_standard_storage, node_copy_standard_storage); node_type_gpu(&ntype, node_shader_gpu_tex_noise); + node_type_update(&ntype, node_shader_update_tex_noise); nodeRegisterType(&ntype); } |