From 729b2d026d1379de92908b16e7492a509721c796 Mon Sep 17 00:00:00 2001 From: Charlie Jolly Date: Mon, 18 Oct 2021 10:12:22 +0100 Subject: Geometry Nodes: Add shader Musgrave texture node Port shader node musgrave texture Differential Revision: https://developer.blender.org/D12701 --- release/scripts/startup/nodeitems_builtins.py | 1 + source/blender/blenlib/BLI_noise.hh | 99 +++ source/blender/blenlib/intern/noise.cc | 718 +++++++++++++++++++++ .../nodes/shader/nodes/node_shader_tex_musgrave.cc | 410 +++++++++++- 4 files changed, 1226 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 68dc7103f3a..8087f64c5ab 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -722,6 +722,7 @@ geometry_node_categories = [ ]), GeometryNodeCategory("GEO_TEXTURE", "Texture", items=[ NodeItem("ShaderNodeTexGradient"), + NodeItem("ShaderNodeTexMusgrave"), NodeItem("ShaderNodeTexNoise"), NodeItem("ShaderNodeTexVoronoi"), NodeItem("ShaderNodeTexWhiteNoise"), diff --git a/source/blender/blenlib/BLI_noise.hh b/source/blender/blenlib/BLI_noise.hh index 93980e3569e..a7af69f42a9 100644 --- a/source/blender/blenlib/BLI_noise.hh +++ b/source/blender/blenlib/BLI_noise.hh @@ -112,6 +112,105 @@ float3 perlin_float3_fractal_distorted(float4 position, /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Musgrave Multi Fractal + * \{ */ + +float musgrave_ridged_multi_fractal(const float co, + const float H, + const float lacunarity, + const float octaves, + const float offset, + const float gain); +float musgrave_ridged_multi_fractal(const float2 co, + const float H, + const float lacunarity, + const float octaves, + const float offset, + const float gain); +float musgrave_ridged_multi_fractal(const float3 co, + const float H, + const float lacunarity, + const float octaves, + const float offset, + const float gain); +float musgrave_ridged_multi_fractal(const float4 co, + const float H, + const float lacunarity, + const float octaves, + const float offset, + const float gain); + +float musgrave_hybrid_multi_fractal(const float co, + const float H, + const float lacunarity, + const float octaves, + const float offset, + const float gain); +float musgrave_hybrid_multi_fractal(const float2 co, + const float H, + const float lacunarity, + const float octaves, + const float offset, + const float gain); +float musgrave_hybrid_multi_fractal(const float3 co, + const float H, + const float lacunarity, + const float octaves, + const float offset, + const float gain); +float musgrave_hybrid_multi_fractal(const float4 co, + const float H, + const float lacunarity, + const float octaves, + const float offset, + const float gain); + +float musgrave_fBm(const float co, const float H, const float lacunarity, const float octaves); +float musgrave_fBm(const float2 co, const float H, const float lacunarity, const float octaves); +float musgrave_fBm(const float3 co, const float H, const float lacunarity, const float octaves); +float musgrave_fBm(const float4 co, const float H, const float lacunarity, const float octaves); + +float musgrave_multi_fractal(const float co, + const float H, + const float lacunarity, + const float octaves); +float musgrave_multi_fractal(const float2 co, + const float H, + const float lacunarity, + const float octaves); +float musgrave_multi_fractal(const float3 co, + const float H, + const float lacunarity, + const float octaves); +float musgrave_multi_fractal(const float4 co, + const float H, + const float lacunarity, + const float octaves); + +float musgrave_hetero_terrain(const float co, + const float H, + const float lacunarity, + const float octaves, + const float offset); +float musgrave_hetero_terrain(const float2 co, + const float H, + const float lacunarity, + const float octaves, + const float offset); +float musgrave_hetero_terrain(const float3 co, + const float H, + const float lacunarity, + const float octaves, + const float offset); +float musgrave_hetero_terrain(const float4 co, + const float H, + const float lacunarity, + const float octaves, + const float offset); + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Voronoi Noise * \{ */ diff --git a/source/blender/blenlib/intern/noise.cc b/source/blender/blenlib/intern/noise.cc index a6c3377b71f..812e6ddd181 100644 --- a/source/blender/blenlib/intern/noise.cc +++ b/source/blender/blenlib/intern/noise.cc @@ -756,6 +756,724 @@ float3 perlin_float3_fractal_distorted(float4 position, perlin_fractal(position + random_float4_offset(5.0f), octaves, roughness)); } +/* -------------- + * Musgrave Noise + * -------------- + */ + +/* 1D Musgrave fBm + * + * H: fractal increment parameter + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * + * from "Texturing and Modelling: A procedural approach" + */ + +float musgrave_fBm(const float co, const float H, const float lacunarity, const float octaves) +{ + float p = co; + float value = 0.0f; + float pwr = 1.0f; + const float pwHL = powf(lacunarity, -H); + + for (int i = 0; i < (int)octaves; i++) { + value += perlin_signed(p) * pwr; + pwr *= pwHL; + p *= lacunarity; + } + + float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + value += rmd * perlin_signed(p) * pwr; + } + + return value; +} + +/* 1D Musgrave Multifractal + * + * H: highest fractal dimension + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + */ + +float musgrave_multi_fractal(const float co, + const float H, + const float lacunarity, + const float octaves) +{ + float p = co; + float value = 1.0f; + float pwr = 1.0f; + const float pwHL = powf(lacunarity, -H); + + for (int i = 0; i < (int)octaves; i++) { + value *= (pwr * perlin_signed(p) + 1.0f); + pwr *= pwHL; + p *= lacunarity; + } + + const float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + value *= (rmd * pwr * perlin_signed(p) + 1.0f); /* correct? */ + } + + return value; +} + +/* 1D Musgrave Heterogeneous Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float musgrave_hetero_terrain( + const float co, const float H, const float lacunarity, const float octaves, const float offset) +{ + float p = co; + const float pwHL = powf(lacunarity, -H); + float pwr = pwHL; + + /* first unscaled octave of function; later octaves are scaled */ + float value = offset + perlin_signed(p); + p *= lacunarity; + + for (int i = 1; i < (int)octaves; i++) { + float increment = (perlin_signed(p) + offset) * pwr * value; + value += increment; + pwr *= pwHL; + p *= lacunarity; + } + + const float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + float increment = (perlin_signed(p) + offset) * pwr * value; + value += rmd * increment; + } + + return value; +} + +/* 1D Hybrid Additive/Multiplicative Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float musgrave_hybrid_multi_fractal(const float co, + const float H, + const float lacunarity, + const float octaves, + const float offset, + const float gain) +{ + float p = co; + const float pwHL = powf(lacunarity, -H); + float pwr = pwHL; + + float value = perlin_signed(p) + offset; + float weight = gain * value; + p *= lacunarity; + + for (int i = 1; (weight > 0.001f) && (i < (int)octaves); i++) { + if (weight > 1.0f) { + weight = 1.0f; + } + + float signal = (perlin_signed(p) + offset) * pwr; + pwr *= pwHL; + value += weight * signal; + weight *= gain * signal; + p *= lacunarity; + } + + const float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + value += rmd * ((perlin_signed(p) + offset) * pwr); + } + + return value; +} + +/* 1D Ridged Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float musgrave_ridged_multi_fractal(const float co, + const float H, + const float lacunarity, + const float octaves, + const float offset, + const float gain) +{ + float p = co; + const float pwHL = powf(lacunarity, -H); + float pwr = pwHL; + + float signal = offset - fabsf(perlin_signed(p)); + signal *= signal; + float value = signal; + float weight = 1.0f; + + for (int i = 1; i < (int)octaves; i++) { + p *= lacunarity; + weight = CLAMPIS(signal * gain, 0.0f, 1.0f); + signal = offset - fabsf(perlin_signed(p)); + signal *= signal; + signal *= weight; + value += signal * pwr; + pwr *= pwHL; + } + + return value; +} + +/* 2D Musgrave fBm + * + * H: fractal increment parameter + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * + * from "Texturing and Modelling: A procedural approach" + */ + +float musgrave_fBm(const float2 co, const float H, const float lacunarity, const float octaves) +{ + float2 p = co; + float value = 0.0f; + float pwr = 1.0f; + const float pwHL = powf(lacunarity, -H); + + for (int i = 0; i < (int)octaves; i++) { + value += perlin_signed(p) * pwr; + pwr *= pwHL; + p *= lacunarity; + } + + const float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + value += rmd * perlin_signed(p) * pwr; + } + + return value; +} + +/* 2D Musgrave Multifractal + * + * H: highest fractal dimension + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + */ + +float musgrave_multi_fractal(const float2 co, + const float H, + const float lacunarity, + const float octaves) +{ + float2 p = co; + float value = 1.0f; + float pwr = 1.0f; + const float pwHL = powf(lacunarity, -H); + + for (int i = 0; i < (int)octaves; i++) { + value *= (pwr * perlin_signed(p) + 1.0f); + pwr *= pwHL; + p *= lacunarity; + } + + const float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + value *= (rmd * pwr * perlin_signed(p) + 1.0f); /* correct? */ + } + + return value; +} + +/* 2D Musgrave Heterogeneous Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float musgrave_hetero_terrain(const float2 co, + const float H, + const float lacunarity, + const float octaves, + const float offset) +{ + float2 p = co; + const float pwHL = powf(lacunarity, -H); + float pwr = pwHL; + + /* first unscaled octave of function; later octaves are scaled */ + float value = offset + perlin_signed(p); + p *= lacunarity; + + for (int i = 1; i < (int)octaves; i++) { + float increment = (perlin_signed(p) + offset) * pwr * value; + value += increment; + pwr *= pwHL; + p *= lacunarity; + } + + const float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + float increment = (perlin_signed(p) + offset) * pwr * value; + value += rmd * increment; + } + + return value; +} + +/* 2D Hybrid Additive/Multiplicative Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float musgrave_hybrid_multi_fractal(const float2 co, + const float H, + const float lacunarity, + const float octaves, + const float offset, + const float gain) +{ + float2 p = co; + const float pwHL = powf(lacunarity, -H); + float pwr = pwHL; + + float value = perlin_signed(p) + offset; + float weight = gain * value; + p *= lacunarity; + + for (int i = 1; (weight > 0.001f) && (i < (int)octaves); i++) { + if (weight > 1.0f) { + weight = 1.0f; + } + + float signal = (perlin_signed(p) + offset) * pwr; + pwr *= pwHL; + value += weight * signal; + weight *= gain * signal; + p *= lacunarity; + } + + const float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + value += rmd * ((perlin_signed(p) + offset) * pwr); + } + + return value; +} + +/* 2D Ridged Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float musgrave_ridged_multi_fractal(const float2 co, + const float H, + const float lacunarity, + const float octaves, + const float offset, + const float gain) +{ + float2 p = co; + const float pwHL = powf(lacunarity, -H); + float pwr = pwHL; + + float signal = offset - fabsf(perlin_signed(p)); + signal *= signal; + float value = signal; + float weight = 1.0f; + + for (int i = 1; i < (int)octaves; i++) { + p *= lacunarity; + weight = CLAMPIS(signal * gain, 0.0f, 1.0f); + signal = offset - fabsf(perlin_signed(p)); + signal *= signal; + signal *= weight; + value += signal * pwr; + pwr *= pwHL; + } + + return value; +} + +/* 3D Musgrave fBm + * + * H: fractal increment parameter + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * + * from "Texturing and Modelling: A procedural approach" + */ + +float musgrave_fBm(const float3 co, const float H, const float lacunarity, const float octaves) +{ + float3 p = co; + float value = 0.0f; + float pwr = 1.0f; + const float pwHL = powf(lacunarity, -H); + + for (int i = 0; i < (int)octaves; i++) { + value += perlin_signed(p) * pwr; + pwr *= pwHL; + p *= lacunarity; + } + + const float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + value += rmd * perlin_signed(p) * pwr; + } + + return value; +} + +/* 3D Musgrave Multifractal + * + * H: highest fractal dimension + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + */ + +float musgrave_multi_fractal(const float3 co, + const float H, + const float lacunarity, + const float octaves) +{ + float3 p = co; + float value = 1.0f; + float pwr = 1.0f; + const float pwHL = powf(lacunarity, -H); + + for (int i = 0; i < (int)octaves; i++) { + value *= (pwr * perlin_signed(p) + 1.0f); + pwr *= pwHL; + p *= lacunarity; + } + + const float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + value *= (rmd * pwr * perlin_signed(p) + 1.0f); /* correct? */ + } + + return value; +} + +/* 3D Musgrave Heterogeneous Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float musgrave_hetero_terrain(const float3 co, + const float H, + const float lacunarity, + const float octaves, + const float offset) +{ + float3 p = co; + const float pwHL = powf(lacunarity, -H); + float pwr = pwHL; + + /* first unscaled octave of function; later octaves are scaled */ + float value = offset + perlin_signed(p); + p *= lacunarity; + + for (int i = 1; i < (int)octaves; i++) { + float increment = (perlin_signed(p) + offset) * pwr * value; + value += increment; + pwr *= pwHL; + p *= lacunarity; + } + + const float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + float increment = (perlin_signed(p) + offset) * pwr * value; + value += rmd * increment; + } + + return value; +} + +/* 3D Hybrid Additive/Multiplicative Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float musgrave_hybrid_multi_fractal(const float3 co, + const float H, + const float lacunarity, + const float octaves, + const float offset, + const float gain) +{ + float3 p = co; + const float pwHL = powf(lacunarity, -H); + float pwr = pwHL; + + float value = perlin_signed(p) + offset; + float weight = gain * value; + p *= lacunarity; + + for (int i = 1; (weight > 0.001f) && (i < (int)octaves); i++) { + if (weight > 1.0f) { + weight = 1.0f; + } + + float signal = (perlin_signed(p) + offset) * pwr; + pwr *= pwHL; + value += weight * signal; + weight *= gain * signal; + p *= lacunarity; + } + + const float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + value += rmd * ((perlin_signed(p) + offset) * pwr); + } + + return value; +} + +/* 3D Ridged Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float musgrave_ridged_multi_fractal(const float3 co, + const float H, + const float lacunarity, + const float octaves, + const float offset, + const float gain) +{ + float3 p = co; + const float pwHL = powf(lacunarity, -H); + float pwr = pwHL; + + float signal = offset - fabsf(perlin_signed(p)); + signal *= signal; + float value = signal; + float weight = 1.0f; + + for (int i = 1; i < (int)octaves; i++) { + p *= lacunarity; + weight = CLAMPIS(signal * gain, 0.0f, 1.0f); + signal = offset - fabsf(perlin_signed(p)); + signal *= signal; + signal *= weight; + value += signal * pwr; + pwr *= pwHL; + } + + return value; +} + +/* 4D Musgrave fBm + * + * H: fractal increment parameter + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * + * from "Texturing and Modelling: A procedural approach" + */ + +float musgrave_fBm(const float4 co, const float H, const float lacunarity, const float octaves) +{ + float4 p = co; + float value = 0.0f; + float pwr = 1.0f; + const float pwHL = powf(lacunarity, -H); + + for (int i = 0; i < (int)octaves; i++) { + value += perlin_signed(p) * pwr; + pwr *= pwHL; + p *= lacunarity; + } + + const float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + value += rmd * perlin_signed(p) * pwr; + } + + return value; +} + +/* 4D Musgrave Multifractal + * + * H: highest fractal dimension + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + */ + +float musgrave_multi_fractal(const float4 co, + const float H, + const float lacunarity, + const float octaves) +{ + float4 p = co; + float value = 1.0f; + float pwr = 1.0f; + const float pwHL = powf(lacunarity, -H); + + for (int i = 0; i < (int)octaves; i++) { + value *= (pwr * perlin_signed(p) + 1.0f); + pwr *= pwHL; + p *= lacunarity; + } + + const float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + value *= (rmd * pwr * perlin_signed(p) + 1.0f); /* correct? */ + } + + return value; +} + +/* 4D Musgrave Heterogeneous Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float musgrave_hetero_terrain(const float4 co, + const float H, + const float lacunarity, + const float octaves, + const float offset) +{ + float4 p = co; + const float pwHL = powf(lacunarity, -H); + float pwr = pwHL; + + /* first unscaled octave of function; later octaves are scaled */ + float value = offset + perlin_signed(p); + p *= lacunarity; + + for (int i = 1; i < (int)octaves; i++) { + float increment = (perlin_signed(p) + offset) * pwr * value; + value += increment; + pwr *= pwHL; + p *= lacunarity; + } + + const float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + float increment = (perlin_signed(p) + offset) * pwr * value; + value += rmd * increment; + } + + return value; +} + +/* 4D Hybrid Additive/Multiplicative Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float musgrave_hybrid_multi_fractal(const float4 co, + const float H, + const float lacunarity, + const float octaves, + const float offset, + const float gain) +{ + float4 p = co; + const float pwHL = powf(lacunarity, -H); + float pwr = pwHL; + + float value = perlin_signed(p) + offset; + float weight = gain * value; + p *= lacunarity; + + for (int i = 1; (weight > 0.001f) && (i < (int)octaves); i++) { + if (weight > 1.0f) { + weight = 1.0f; + } + + float signal = (perlin_signed(p) + offset) * pwr; + pwr *= pwHL; + value += weight * signal; + weight *= gain * signal; + p *= lacunarity; + } + + const float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + value += rmd * ((perlin_signed(p) + offset) * pwr); + } + + return value; +} + +/* 4D Ridged Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +float musgrave_ridged_multi_fractal(const float4 co, + const float H, + const float lacunarity, + const float octaves, + const float offset, + const float gain) +{ + float4 p = co; + const float pwHL = powf(lacunarity, -H); + float pwr = pwHL; + + float signal = offset - fabsf(perlin_signed(p)); + signal *= signal; + float value = signal; + float weight = 1.0f; + + for (int i = 1; i < (int)octaves; i++) { + p *= lacunarity; + weight = CLAMPIS(signal * gain, 0.0f, 1.0f); + signal = offset - fabsf(perlin_signed(p)); + signal *= signal; + signal *= weight; + value += signal * pwr; + pwr *= pwHL; + } + + return value; +} + /* * Voronoi: Ported from Cycles code. * diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc index 23f150d8135..61c26d07e2f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc @@ -19,12 +19,14 @@ #include "../node_shader_util.h" +#include "BLI_noise.hh" + namespace blender::nodes { static void sh_node_tex_musgrave_declare(NodeDeclarationBuilder &b) { b.is_function_node(); - b.add_input("Vector").hide_value(); + b.add_input("Vector").hide_value().implicit_field(); b.add_input("W").min(-1000.0f).max(1000.0f); b.add_input("Scale").min(-1000.0f).max(1000.0f).default_value(5.0f); b.add_input("Detail").min(0.0f).max(16.0f).default_value(2.0f); @@ -124,11 +126,414 @@ static void node_shader_update_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *nod node_sock_label(outFacSock, "Height"); } +namespace blender::nodes { + +class MusgraveFunction : public fn::MultiFunction { + private: + const int dimensions_; + const int musgrave_type_; + + public: + MusgraveFunction(const int dimensions, const int musgrave_type) + : dimensions_(dimensions), musgrave_type_(musgrave_type) + { + BLI_assert(dimensions >= 1 && dimensions <= 4); + BLI_assert(musgrave_type >= 0 && musgrave_type <= 4); + static std::array signatures{ + create_signature(1, SHD_MUSGRAVE_MULTIFRACTAL), + create_signature(2, SHD_MUSGRAVE_MULTIFRACTAL), + create_signature(3, SHD_MUSGRAVE_MULTIFRACTAL), + create_signature(4, SHD_MUSGRAVE_MULTIFRACTAL), + + create_signature(1, SHD_MUSGRAVE_FBM), + create_signature(2, SHD_MUSGRAVE_FBM), + create_signature(3, SHD_MUSGRAVE_FBM), + create_signature(4, SHD_MUSGRAVE_FBM), + + create_signature(1, SHD_MUSGRAVE_HYBRID_MULTIFRACTAL), + create_signature(2, SHD_MUSGRAVE_HYBRID_MULTIFRACTAL), + create_signature(3, SHD_MUSGRAVE_HYBRID_MULTIFRACTAL), + create_signature(4, SHD_MUSGRAVE_HYBRID_MULTIFRACTAL), + + create_signature(1, SHD_MUSGRAVE_RIDGED_MULTIFRACTAL), + create_signature(2, SHD_MUSGRAVE_RIDGED_MULTIFRACTAL), + create_signature(3, SHD_MUSGRAVE_RIDGED_MULTIFRACTAL), + create_signature(4, SHD_MUSGRAVE_RIDGED_MULTIFRACTAL), + + create_signature(1, SHD_MUSGRAVE_HETERO_TERRAIN), + create_signature(2, SHD_MUSGRAVE_HETERO_TERRAIN), + create_signature(3, SHD_MUSGRAVE_HETERO_TERRAIN), + create_signature(4, SHD_MUSGRAVE_HETERO_TERRAIN), + }; + this->set_signature(&signatures[dimensions + musgrave_type * 4 - 1]); + } + + static fn::MFSignature create_signature(const int dimensions, const int musgrave_type) + { + fn::MFSignatureBuilder signature{"Musgrave"}; + + if (ELEM(dimensions, 2, 3, 4)) { + signature.single_input("Vector"); + } + if (ELEM(dimensions, 1, 4)) { + signature.single_input("W"); + } + signature.single_input("Scale"); + signature.single_input("Detail"); + signature.single_input("Dimension"); + signature.single_input("Lacunarity"); + if (ELEM(musgrave_type, + SHD_MUSGRAVE_RIDGED_MULTIFRACTAL, + SHD_MUSGRAVE_HYBRID_MULTIFRACTAL, + SHD_MUSGRAVE_HETERO_TERRAIN)) { + signature.single_input("Offset"); + } + if (ELEM(musgrave_type, SHD_MUSGRAVE_RIDGED_MULTIFRACTAL, SHD_MUSGRAVE_HYBRID_MULTIFRACTAL)) { + signature.single_input("Gain"); + } + + signature.single_output("Fac"); + + return signature.build(); + } + + void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override + { + auto get_vector = [&](int param_index) -> const VArray & { + return params.readonly_single_input(param_index, "Vector"); + }; + auto get_w = [&](int param_index) -> const VArray & { + return params.readonly_single_input(param_index, "W"); + }; + auto get_scale = [&](int param_index) -> const VArray & { + return params.readonly_single_input(param_index, "Scale"); + }; + auto get_detail = [&](int param_index) -> const VArray & { + return params.readonly_single_input(param_index, "Detail"); + }; + auto get_dimension = [&](int param_index) -> const VArray & { + return params.readonly_single_input(param_index, "Dimension"); + }; + auto get_lacunarity = [&](int param_index) -> const VArray & { + return params.readonly_single_input(param_index, "Lacunarity"); + }; + auto get_offset = [&](int param_index) -> const VArray & { + return params.readonly_single_input(param_index, "Offset"); + }; + auto get_gain = [&](int param_index) -> const VArray & { + return params.readonly_single_input(param_index, "Gain"); + }; + + auto get_r_factor = [&](int param_index) -> MutableSpan { + return params.uninitialized_single_output_if_required(param_index, "Fac"); + }; + + int param = ELEM(dimensions_, 2, 3, 4) + ELEM(dimensions_, 1, 4); + const VArray &scale = get_scale(param++); + const VArray &detail = get_detail(param++); + const VArray &dimension = get_dimension(param++); + const VArray &lacunarity = get_lacunarity(param++); + + switch (musgrave_type_) { + case SHD_MUSGRAVE_MULTIFRACTAL: { + MutableSpan r_factor = get_r_factor(param++); + const bool compute_factor = !r_factor.is_empty(); + switch (dimensions_) { + case 1: { + const VArray &w = get_w(0); + if (compute_factor) { + for (int64_t i : mask) { + const float position = w[i] * scale[i]; + r_factor[i] = noise::musgrave_multi_fractal( + position, dimension[i], lacunarity[i], detail[i]); + } + } + break; + } + case 2: { + const VArray &vector = get_vector(0); + if (compute_factor) { + for (int64_t i : mask) { + const float3 pxyz = vector[i] * scale[i]; + const float2 position = float2(pxyz[0], pxyz[1]); + r_factor[i] = noise::musgrave_multi_fractal( + position, dimension[i], lacunarity[i], detail[i]); + } + } + break; + } + case 3: { + const VArray &vector = get_vector(0); + if (compute_factor) { + for (int64_t i : mask) { + const float3 position = vector[i] * scale[i]; + r_factor[i] = noise::musgrave_multi_fractal( + position, dimension[i], lacunarity[i], detail[i]); + } + } + break; + } + case 4: { + const VArray &vector = get_vector(0); + const VArray &w = get_w(1); + if (compute_factor) { + for (int64_t i : mask) { + const float3 pxyz = vector[i] * scale[i]; + const float pw = w[i] * scale[i]; + const float4 position{pxyz[0], pxyz[1], pxyz[2], pw}; + r_factor[i] = noise::musgrave_multi_fractal( + position, dimension[i], lacunarity[i], detail[i]); + } + } + break; + } + } + break; + } + case SHD_MUSGRAVE_RIDGED_MULTIFRACTAL: { + const VArray &offset = get_offset(param++); + const VArray &gain = get_gain(param++); + MutableSpan r_factor = get_r_factor(param++); + const bool compute_factor = !r_factor.is_empty(); + switch (dimensions_) { + case 1: { + const VArray &w = get_w(0); + if (compute_factor) { + for (int64_t i : mask) { + const float position = w[i] * scale[i]; + r_factor[i] = noise::musgrave_ridged_multi_fractal( + position, dimension[i], lacunarity[i], detail[i], offset[i], gain[i]); + } + } + break; + } + case 2: { + const VArray &vector = get_vector(0); + if (compute_factor) { + for (int64_t i : mask) { + const float3 pxyz = vector[i] * scale[i]; + const float2 position = float2(pxyz[0], pxyz[1]); + r_factor[i] = noise::musgrave_ridged_multi_fractal( + position, dimension[i], lacunarity[i], detail[i], offset[i], gain[i]); + } + } + break; + } + case 3: { + const VArray &vector = get_vector(0); + if (compute_factor) { + for (int64_t i : mask) { + const float3 position = vector[i] * scale[i]; + r_factor[i] = noise::musgrave_ridged_multi_fractal( + position, dimension[i], lacunarity[i], detail[i], offset[i], gain[i]); + } + } + break; + } + case 4: { + const VArray &vector = get_vector(0); + const VArray &w = get_w(1); + if (compute_factor) { + for (int64_t i : mask) { + const float3 pxyz = vector[i] * scale[i]; + const float pw = w[i] * scale[i]; + const float4 position{pxyz[0], pxyz[1], pxyz[2], pw}; + r_factor[i] = noise::musgrave_ridged_multi_fractal( + position, dimension[i], lacunarity[i], detail[i], offset[i], gain[i]); + } + } + break; + } + } + break; + } + case SHD_MUSGRAVE_HYBRID_MULTIFRACTAL: { + const VArray &offset = get_offset(param++); + const VArray &gain = get_gain(param++); + MutableSpan r_factor = get_r_factor(param++); + const bool compute_factor = !r_factor.is_empty(); + switch (dimensions_) { + case 1: { + const VArray &w = get_w(0); + if (compute_factor) { + for (int64_t i : mask) { + const float position = w[i] * scale[i]; + r_factor[i] = noise::musgrave_hybrid_multi_fractal( + position, dimension[i], lacunarity[i], detail[i], offset[i], gain[i]); + } + } + break; + } + case 2: { + const VArray &vector = get_vector(0); + if (compute_factor) { + for (int64_t i : mask) { + const float3 pxyz = vector[i] * scale[i]; + const float2 position = float2(pxyz[0], pxyz[1]); + r_factor[i] = noise::musgrave_hybrid_multi_fractal( + position, dimension[i], lacunarity[i], detail[i], offset[i], gain[i]); + } + } + break; + } + case 3: { + const VArray &vector = get_vector(0); + if (compute_factor) { + for (int64_t i : mask) { + const float3 position = vector[i] * scale[i]; + r_factor[i] = noise::musgrave_hybrid_multi_fractal( + position, dimension[i], lacunarity[i], detail[i], offset[i], gain[i]); + } + } + break; + } + case 4: { + const VArray &vector = get_vector(0); + const VArray &w = get_w(1); + if (compute_factor) { + for (int64_t i : mask) { + const float3 pxyz = vector[i] * scale[i]; + const float pw = w[i] * scale[i]; + const float4 position{pxyz[0], pxyz[1], pxyz[2], pw}; + r_factor[i] = noise::musgrave_hybrid_multi_fractal( + position, dimension[i], lacunarity[i], detail[i], offset[i], gain[i]); + } + } + break; + } + } + break; + } + case SHD_MUSGRAVE_FBM: { + MutableSpan r_factor = get_r_factor(param++); + const bool compute_factor = !r_factor.is_empty(); + switch (dimensions_) { + case 1: { + const VArray &w = get_w(0); + if (compute_factor) { + for (int64_t i : mask) { + const float position = w[i] * scale[i]; + r_factor[i] = noise::musgrave_fBm( + position, dimension[i], lacunarity[i], detail[i]); + } + } + break; + } + case 2: { + const VArray &vector = get_vector(0); + if (compute_factor) { + for (int64_t i : mask) { + const float3 pxyz = vector[i] * scale[i]; + const float2 position = float2(pxyz[0], pxyz[1]); + r_factor[i] = noise::musgrave_fBm( + position, dimension[i], lacunarity[i], detail[i]); + } + } + break; + } + case 3: { + const VArray &vector = get_vector(0); + if (compute_factor) { + for (int64_t i : mask) { + const float3 position = vector[i] * scale[i]; + r_factor[i] = noise::musgrave_fBm( + position, dimension[i], lacunarity[i], detail[i]); + } + } + break; + } + case 4: { + const VArray &vector = get_vector(0); + const VArray &w = get_w(1); + if (compute_factor) { + for (int64_t i : mask) { + const float3 pxyz = vector[i] * scale[i]; + const float pw = w[i] * scale[i]; + const float4 position{pxyz[0], pxyz[1], pxyz[2], pw}; + r_factor[i] = noise::musgrave_fBm( + position, dimension[i], lacunarity[i], detail[i]); + } + } + break; + } + } + break; + } + case SHD_MUSGRAVE_HETERO_TERRAIN: { + const VArray &offset = get_offset(param++); + MutableSpan r_factor = get_r_factor(param++); + const bool compute_factor = !r_factor.is_empty(); + switch (dimensions_) { + case 1: { + const VArray &w = get_w(0); + if (compute_factor) { + for (int64_t i : mask) { + const float position = w[i] * scale[i]; + r_factor[i] = noise::musgrave_hetero_terrain( + position, dimension[i], lacunarity[i], detail[i], offset[i]); + } + } + break; + } + case 2: { + const VArray &vector = get_vector(0); + if (compute_factor) { + for (int64_t i : mask) { + const float3 pxyz = vector[i] * scale[i]; + const float2 position = float2(pxyz[0], pxyz[1]); + r_factor[i] = noise::musgrave_hetero_terrain( + position, dimension[i], lacunarity[i], detail[i], offset[i]); + } + } + break; + } + case 3: { + const VArray &vector = get_vector(0); + if (compute_factor) { + for (int64_t i : mask) { + const float3 position = vector[i] * scale[i]; + r_factor[i] = noise::musgrave_hetero_terrain( + position, dimension[i], lacunarity[i], detail[i], offset[i]); + } + } + break; + } + case 4: { + const VArray &vector = get_vector(0); + const VArray &w = get_w(1); + if (compute_factor) { + for (int64_t i : mask) { + const float3 pxyz = vector[i] * scale[i]; + const float pw = w[i] * scale[i]; + const float4 position{pxyz[0], pxyz[1], pxyz[2], pw}; + r_factor[i] = noise::musgrave_hetero_terrain( + position, dimension[i], lacunarity[i], detail[i], offset[i]); + } + } + break; + } + } + break; + } + } + } +}; // namespace blender::nodes + +static void sh_node_musgrave_build_multi_function( + blender::nodes::NodeMultiFunctionBuilder &builder) +{ + bNode &node = builder.node(); + NodeTexMusgrave *tex = (NodeTexMusgrave *)node.storage; + builder.construct_and_set_matching_fn(tex->dimensions, tex->musgrave_type); +} + +} // namespace blender::nodes + void register_node_type_sh_tex_musgrave(void) { static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_TEX_MUSGRAVE, "Musgrave Texture", NODE_CLASS_TEXTURE, 0); + sh_fn_node_type_base(&ntype, SH_NODE_TEX_MUSGRAVE, "Musgrave Texture", NODE_CLASS_TEXTURE, 0); ntype.declare = blender::nodes::sh_node_tex_musgrave_declare; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_init(&ntype, node_shader_init_tex_musgrave); @@ -136,6 +541,7 @@ void register_node_type_sh_tex_musgrave(void) &ntype, "NodeTexMusgrave", node_free_standard_storage, node_copy_standard_storage); node_type_gpu(&ntype, node_shader_gpu_tex_musgrave); node_type_update(&ntype, node_shader_update_tex_musgrave); + ntype.build_multi_function = blender::nodes::sh_node_musgrave_build_multi_function; nodeRegisterType(&ntype); } -- cgit v1.2.3