diff options
author | Charlie Jolly <charlie> | 2021-10-15 17:27:16 +0300 |
---|---|---|
committer | Charlie Jolly <mistajolly@gmail.com> | 2021-10-15 17:28:20 +0300 |
commit | 104887800c0f221fbcffa84bb360dd9ff001d7f1 (patch) | |
tree | 743a308c6eda1918e4e97df0d8ba32b7046bedf7 /source/blender/nodes/shader | |
parent | 6e4ab5b761b03b52177985ecbeb2c2f576159c74 (diff) |
Geometry Nodes: Add Voronoi Texture
Port shader Voronoi to GN
Reviewed By: JacquesLucke
Differential Revision: https://developer.blender.org/D12725
Diffstat (limited to 'source/blender/nodes/shader')
-rw-r--r-- | source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc | 911 |
1 files changed, 909 insertions, 2 deletions
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc index e12e5724e8e..07904123ace 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc @@ -19,12 +19,14 @@ #include "../node_shader_util.h" +#include "BLI_noise.hh" + namespace blender::nodes { static void sh_node_tex_voronoi_declare(NodeDeclarationBuilder &b) { b.is_function_node(); - b.add_input<decl::Vector>("Vector").hide_value(); + b.add_input<decl::Vector>("Vector").hide_value().implicit_field(); b.add_input<decl::Float>("W").min(-1000.0f).max(1000.0f); b.add_input<decl::Float>("Scale").min(-1000.0f).max(1000.0f).default_value(5.0f); b.add_input<decl::Float>("Smoothness") @@ -143,6 +145,7 @@ static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node tex->distance == SHD_VORONOI_MINKOWSKI && tex->dimensions != 1 && !ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS)); nodeSetSocketAvailability(inSmoothnessSock, tex->feature == SHD_VORONOI_SMOOTH_F1); + nodeSetSocketAvailability(outDistanceSock, tex->feature != SHD_VORONOI_N_SPHERE_RADIUS); nodeSetSocketAvailability(outColorSock, tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE && @@ -158,17 +161,921 @@ static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node nodeSetSocketAvailability(outRadiusSock, tex->feature == SHD_VORONOI_N_SPHERE_RADIUS); } +namespace blender::nodes { + +class VoronoiMinowskiFunction : public fn::MultiFunction { + private: + int dimensions_; + int feature_; + + public: + VoronoiMinowskiFunction(int dimensions, int feature) : dimensions_(dimensions), feature_(feature) + { + BLI_assert(dimensions >= 2 && dimensions <= 4); + BLI_assert(feature >= 0 && feature <= 2); + static std::array<fn::MFSignature, 9> signatures{ + create_signature(2, SHD_VORONOI_F1), + create_signature(3, SHD_VORONOI_F1), + create_signature(4, SHD_VORONOI_F1), + + create_signature(2, SHD_VORONOI_F2), + create_signature(3, SHD_VORONOI_F2), + create_signature(4, SHD_VORONOI_F2), + + create_signature(2, SHD_VORONOI_SMOOTH_F1), + create_signature(3, SHD_VORONOI_SMOOTH_F1), + create_signature(4, SHD_VORONOI_SMOOTH_F1), + }; + this->set_signature(&signatures[(dimensions - 1) + feature * 3 - 1]); + } + + static fn::MFSignature create_signature(int dimensions, int feature) + { + fn::MFSignatureBuilder signature{"voronoi_minowski"}; + + if (ELEM(dimensions, 2, 3, 4)) { + signature.single_input<float3>("Vector"); + } + if (ELEM(dimensions, 1, 4)) { + signature.single_input<float>("W"); + } + signature.single_input<float>("Scale"); + if (feature == SHD_VORONOI_SMOOTH_F1) { + signature.single_input<float>("Smoothness"); + } + signature.single_input<float>("Exponent"); + signature.single_input<float>("Randomness"); + signature.single_output<float>("Distance"); + signature.single_output<ColorGeometry4f>("Color"); + + if (dimensions != 1) { + signature.single_output<float3>("Position"); + } + if ((dimensions == 1 || dimensions == 4)) { + signature.single_output<float>("W"); + } + + return signature.build(); + } + + void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override + { + auto get_vector = [&](int param_index) -> const VArray<float3> & { + return params.readonly_single_input<float3>(param_index, "Vector"); + }; + auto get_w = [&](int param_index) -> const VArray<float> & { + return params.readonly_single_input<float>(param_index, "W"); + }; + auto get_scale = [&](int param_index) -> const VArray<float> & { + return params.readonly_single_input<float>(param_index, "Scale"); + }; + auto get_smoothness = [&](int param_index) -> const VArray<float> & { + return params.readonly_single_input<float>(param_index, "Smoothness"); + }; + auto get_exponent = [&](int param_index) -> const VArray<float> & { + return params.readonly_single_input<float>(param_index, "Exponent"); + }; + auto get_randomness = [&](int param_index) -> const VArray<float> & { + return params.readonly_single_input<float>(param_index, "Randomness"); + }; + auto get_r_distance = [&](int param_index) -> MutableSpan<float> { + return params.uninitialized_single_output<float>(param_index, "Distance"); + }; + auto get_r_color = [&](int param_index) -> MutableSpan<ColorGeometry4f> { + return params.uninitialized_single_output<ColorGeometry4f>(param_index, "Color"); + }; + auto get_r_position = [&](int param_index) -> MutableSpan<float3> { + return params.uninitialized_single_output<float3>(param_index, "Position"); + }; + auto get_r_w = [&](int param_index) -> MutableSpan<float> { + return params.uninitialized_single_output<float>(param_index, "W"); + }; + + int param = 0; + switch (dimensions_) { + case 2: { + switch (feature_) { + case SHD_VORONOI_F1: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &exponent = get_exponent(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + float3 col; + float2 pos; + noise::voronoi_f1(float2(vector[i].x, vector[i].y) * scale[i], + exponent[i], + rand, + SHD_VORONOI_MINKOWSKI, + &r_distance[i], + &col, + &pos); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + pos = float2::safe_divide(pos, scale[i]); + r_position[i] = float3(pos.x, pos.y, 0.0f); + } + break; + } + case SHD_VORONOI_F2: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &exponent = get_exponent(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + float3 col; + float2 pos; + noise::voronoi_f2(float2(vector[i].x, vector[i].y) * scale[i], + exponent[i], + rand, + SHD_VORONOI_MINKOWSKI, + &r_distance[i], + &col, + &pos); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + pos = float2::safe_divide(pos, scale[i]); + r_position[i] = float3(pos.x, pos.y, 0.0f); + } + break; + } + case SHD_VORONOI_SMOOTH_F1: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &smoothness = get_smoothness(param++); + const VArray<float> &exponent = get_exponent(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + for (int64_t i : mask) { + const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f); + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + float3 col; + float2 pos; + noise::voronoi_smooth_f1(float2(vector[i].x, vector[i].y) * scale[i], + smth, + exponent[i], + rand, + SHD_VORONOI_MINKOWSKI, + &r_distance[i], + &col, + &pos); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + pos = float2::safe_divide(pos, scale[i]); + r_position[i] = float3(pos.x, pos.y, 0.0f); + } + break; + } + } + break; + } + case 3: { + switch (feature_) { + case SHD_VORONOI_F1: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &exponent = get_exponent(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + float3 col; + noise::voronoi_f1(vector[i] * scale[i], + exponent[i], + rand, + SHD_VORONOI_MINKOWSKI, + &r_distance[i], + &col, + &r_position[i]); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + r_position[i] = float3::safe_divide(r_position[i], scale[i]); + } + break; + } + case SHD_VORONOI_F2: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &exponent = get_exponent(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + float3 col; + noise::voronoi_f2(vector[i] * scale[i], + exponent[i], + rand, + SHD_VORONOI_MINKOWSKI, + &r_distance[i], + &col, + &r_position[i]); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + r_position[i] = float3::safe_divide(r_position[i], scale[i]); + } + break; + } + case SHD_VORONOI_SMOOTH_F1: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &smoothness = get_smoothness(param++); + const VArray<float> &exponent = get_exponent(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + for (int64_t i : mask) { + const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f); + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + float3 col; + noise::voronoi_smooth_f1(vector[i] * scale[i], + smth, + exponent[i], + rand, + SHD_VORONOI_MINKOWSKI, + &r_distance[i], + &col, + &r_position[i]); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + r_position[i] = float3::safe_divide(r_position[i], scale[i]); + } + break; + } + } + break; + } + case 4: { + switch (feature_) { + case SHD_VORONOI_F1: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &w = get_w(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &exponent = get_exponent(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + MutableSpan<float> r_w = get_r_w(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i]; + float3 col; + float4 pos; + noise::voronoi_f1(p, exponent[i], rand, SHD_VORONOI_F1, &r_distance[i], &col, &pos); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + pos = float4::safe_divide(pos, scale[i]); + r_position[i] = float3(pos.x, pos.y, pos.z); + r_w[i] = pos.w; + } + break; + } + case SHD_VORONOI_F2: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &w = get_w(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &exponent = get_exponent(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + MutableSpan<float> r_w = get_r_w(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i]; + float3 col; + float4 pos; + noise::voronoi_f2( + p, exponent[i], rand, SHD_VORONOI_MINKOWSKI, &r_distance[i], &col, &pos); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + pos = float4::safe_divide(pos, scale[i]); + r_position[i] = float3(pos.x, pos.y, pos.z); + r_w[i] = pos.w; + } + break; + } + case SHD_VORONOI_SMOOTH_F1: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &w = get_w(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &smoothness = get_smoothness(param++); + const VArray<float> &exponent = get_exponent(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + MutableSpan<float> r_w = get_r_w(param++); + for (int64_t i : mask) { + const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f); + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i]; + float3 col; + float4 pos; + noise::voronoi_smooth_f1( + p, smth, exponent[i], rand, SHD_VORONOI_MINKOWSKI, &r_distance[i], &col, &pos); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + pos = float4::safe_divide(pos, scale[i]); + r_position[i] = float3(pos.x, pos.y, pos.z); + r_w[i] = pos.w; + } + break; + } + } + break; + } + } + } +}; + +class VoronoiMetricFunction : public fn::MultiFunction { + private: + int dimensions_; + int feature_; + int metric_; + + public: + VoronoiMetricFunction(int dimensions, int feature, int metric) + : dimensions_(dimensions), feature_(feature), metric_(metric) + { + BLI_assert(dimensions >= 1 && dimensions <= 4); + BLI_assert(feature >= 0 && feature <= 4); + static std::array<fn::MFSignature, 12> signatures{ + create_signature(1, SHD_VORONOI_F1), + create_signature(2, SHD_VORONOI_F1), + create_signature(3, SHD_VORONOI_F1), + create_signature(4, SHD_VORONOI_F1), + + create_signature(1, SHD_VORONOI_F2), + create_signature(2, SHD_VORONOI_F2), + create_signature(3, SHD_VORONOI_F2), + create_signature(4, SHD_VORONOI_F2), + + create_signature(1, SHD_VORONOI_SMOOTH_F1), + create_signature(2, SHD_VORONOI_SMOOTH_F1), + create_signature(3, SHD_VORONOI_SMOOTH_F1), + create_signature(4, SHD_VORONOI_SMOOTH_F1), + }; + this->set_signature(&signatures[dimensions + feature * 4 - 1]); + } + + static fn::MFSignature create_signature(int dimensions, int feature) + { + fn::MFSignatureBuilder signature{"voronoi_metric"}; + + if (ELEM(dimensions, 2, 3, 4)) { + signature.single_input<float3>("Vector"); + } + if (ELEM(dimensions, 1, 4)) { + signature.single_input<float>("W"); + } + signature.single_input<float>("Scale"); + if (feature == SHD_VORONOI_SMOOTH_F1) { + signature.single_input<float>("Smoothness"); + } + signature.single_input<float>("Randomness"); + signature.single_output<float>("Distance"); + signature.single_output<ColorGeometry4f>("Color"); + + if (dimensions != 1) { + signature.single_output<float3>("Position"); + } + if ((dimensions == 1 || dimensions == 4)) { + signature.single_output<float>("W"); + } + + return signature.build(); + } + + void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override + { + auto get_vector = [&](int param_index) -> const VArray<float3> & { + return params.readonly_single_input<float3>(param_index, "Vector"); + }; + auto get_w = [&](int param_index) -> const VArray<float> & { + return params.readonly_single_input<float>(param_index, "W"); + }; + auto get_scale = [&](int param_index) -> const VArray<float> & { + return params.readonly_single_input<float>(param_index, "Scale"); + }; + auto get_smoothness = [&](int param_index) -> const VArray<float> & { + return params.readonly_single_input<float>(param_index, "Smoothness"); + }; + auto get_randomness = [&](int param_index) -> const VArray<float> & { + return params.readonly_single_input<float>(param_index, "Randomness"); + }; + auto get_r_distance = [&](int param_index) -> MutableSpan<float> { + return params.uninitialized_single_output<float>(param_index, "Distance"); + }; + auto get_r_color = [&](int param_index) -> MutableSpan<ColorGeometry4f> { + return params.uninitialized_single_output<ColorGeometry4f>(param_index, "Color"); + }; + auto get_r_position = [&](int param_index) -> MutableSpan<float3> { + return params.uninitialized_single_output<float3>(param_index, "Position"); + }; + auto get_r_w = [&](int param_index) -> MutableSpan<float> { + return params.uninitialized_single_output<float>(param_index, "W"); + }; + + int param = 0; + switch (dimensions_) { + case 1: { + switch (feature_) { + case SHD_VORONOI_F1: { + const VArray<float> &w = get_w(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float> r_w = get_r_w(param++); + for (int64_t i : mask) { + const float p = w[i] * scale[i]; + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + float3 col; + noise::voronoi_f1(p, rand, &r_distance[i], &col, &r_w[i]); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + r_w[i] = safe_divide(r_w[i], scale[i]); + } + break; + } + case SHD_VORONOI_F2: { + const VArray<float> &w = get_w(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float> r_w = get_r_w(param++); + for (int64_t i : mask) { + const float p = w[i] * scale[i]; + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + float3 col; + noise::voronoi_f2(p, rand, &r_distance[i], &col, &r_w[i]); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + r_w[i] = safe_divide(r_w[i], scale[i]); + } + break; + } + case SHD_VORONOI_SMOOTH_F1: { + const VArray<float> &w = get_w(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &smoothness = get_smoothness(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float> r_w = get_r_w(param++); + for (int64_t i : mask) { + const float p = w[i] * scale[i]; + const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f); + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + float3 col; + noise::voronoi_smooth_f1(p, smth, rand, &r_distance[i], &col, &r_w[i]); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + r_w[i] = safe_divide(r_w[i], scale[i]); + } + break; + } + } + break; + } + case 2: { + switch (feature_) { + case SHD_VORONOI_F1: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + float3 col; + float2 pos; + noise::voronoi_f1(float2(vector[i].x, vector[i].y) * scale[i], + 0.0f, + rand, + metric_, + &r_distance[i], + &col, + &pos); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + pos = float2::safe_divide(pos, scale[i]); + r_position[i] = float3(pos.x, pos.y, 0.0f); + } + break; + } + case SHD_VORONOI_F2: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + float3 col; + float2 pos; + noise::voronoi_f2(float2(vector[i].x, vector[i].y) * scale[i], + 0.0f, + rand, + metric_, + &r_distance[i], + &col, + &pos); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + pos = float2::safe_divide(pos, scale[i]); + r_position[i] = float3(pos.x, pos.y, 0.0f); + } + break; + } + case SHD_VORONOI_SMOOTH_F1: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &smoothness = get_smoothness(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + for (int64_t i : mask) { + const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f); + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + float3 col; + float2 pos; + noise::voronoi_smooth_f1(float2(vector[i].x, vector[i].y) * scale[i], + smth, + 0.0f, + rand, + metric_, + &r_distance[i], + &col, + &pos); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + pos = float2::safe_divide(pos, scale[i]); + r_position[i] = float3(pos.x, pos.y, 0.0f); + } + break; + } + } + break; + } + case 3: { + switch (feature_) { + case SHD_VORONOI_F1: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + float3 col; + noise::voronoi_f1( + vector[i] * scale[i], 0.0f, rand, metric_, &r_distance[i], &col, &r_position[i]); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + r_position[i] = float3::safe_divide(r_position[i], scale[i]); + } + break; + } + case SHD_VORONOI_F2: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + float3 col; + noise::voronoi_f2( + vector[i] * scale[i], 0.0f, rand, metric_, &r_distance[i], &col, &r_position[i]); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + r_position[i] = float3::safe_divide(r_position[i], scale[i]); + } + break; + } + case SHD_VORONOI_SMOOTH_F1: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &smoothness = get_smoothness(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + for (int64_t i : mask) { + const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f); + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + float3 col; + noise::voronoi_smooth_f1(vector[i] * scale[i], + smth, + 0.0f, + rand, + metric_, + &r_distance[i], + &col, + &r_position[i]); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + r_position[i] = float3::safe_divide(r_position[i], scale[i]); + } + break; + } + } + break; + } + case 4: { + switch (feature_) { + case SHD_VORONOI_F1: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &w = get_w(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + MutableSpan<float> r_w = get_r_w(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i]; + float3 col; + float4 pos; + noise::voronoi_f1(p, 0.0f, rand, metric_, &r_distance[i], &col, &pos); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + pos = float4::safe_divide(pos, scale[i]); + r_position[i] = float3(pos.x, pos.y, pos.z); + r_w[i] = pos.w; + } + break; + } + case SHD_VORONOI_F2: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &w = get_w(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + MutableSpan<float> r_w = get_r_w(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i]; + float3 col; + float4 pos; + noise::voronoi_f2(p, 0.0f, rand, metric_, &r_distance[i], &col, &pos); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + pos = float4::safe_divide(pos, scale[i]); + r_position[i] = float3(pos.x, pos.y, pos.z); + r_w[i] = pos.w; + } + break; + } + case SHD_VORONOI_SMOOTH_F1: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &w = get_w(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &smoothness = get_smoothness(param++); + const VArray<float> &randomness = get_randomness(param++); + MutableSpan<float> r_distance = get_r_distance(param++); + MutableSpan<ColorGeometry4f> r_color = get_r_color(param++); + MutableSpan<float3> r_position = get_r_position(param++); + MutableSpan<float> r_w = get_r_w(param++); + for (int64_t i : mask) { + const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f); + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i]; + float3 col; + float4 pos; + noise::voronoi_smooth_f1(p, smth, 0.0f, rand, metric_, &r_distance[i], &col, &pos); + r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f); + pos = float4::safe_divide(pos, scale[i]); + r_position[i] = float3(pos.x, pos.y, pos.z); + r_w[i] = pos.w; + } + break; + } + } + break; + } + } + } +}; + +class VoronoiEdgeFunction : public fn::MultiFunction { + private: + int dimensions_; + int feature_; + + public: + VoronoiEdgeFunction(int dimensions, int feature) : dimensions_(dimensions), feature_(feature) + { + BLI_assert(dimensions >= 1 && dimensions <= 4); + BLI_assert(feature >= 3 && feature <= 4); + static std::array<fn::MFSignature, 8> signatures{ + create_signature(1, SHD_VORONOI_DISTANCE_TO_EDGE), + create_signature(2, SHD_VORONOI_DISTANCE_TO_EDGE), + create_signature(3, SHD_VORONOI_DISTANCE_TO_EDGE), + create_signature(4, SHD_VORONOI_DISTANCE_TO_EDGE), + + create_signature(1, SHD_VORONOI_N_SPHERE_RADIUS), + create_signature(2, SHD_VORONOI_N_SPHERE_RADIUS), + create_signature(3, SHD_VORONOI_N_SPHERE_RADIUS), + create_signature(4, SHD_VORONOI_N_SPHERE_RADIUS), + }; + this->set_signature(&signatures[dimensions + (feature - 3) * 4 - 1]); + } + + static fn::MFSignature create_signature(int dimensions, int feature) + { + fn::MFSignatureBuilder signature{"voronoi_edge"}; + + if (ELEM(dimensions, 2, 3, 4)) { + signature.single_input<float3>("Vector"); + } + if (ELEM(dimensions, 1, 4)) { + signature.single_input<float>("W"); + } + signature.single_input<float>("Scale"); + signature.single_input<float>("Randomness"); + + if (feature == SHD_VORONOI_DISTANCE_TO_EDGE) { + signature.single_output<float>("Distance"); + } + if (feature == SHD_VORONOI_N_SPHERE_RADIUS) { + signature.single_output<float>("Radius"); + } + + return signature.build(); + } + + void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override + { + auto get_vector = [&](int param_index) -> const VArray<float3> & { + return params.readonly_single_input<float3>(param_index, "Vector"); + }; + auto get_w = [&](int param_index) -> const VArray<float> & { + return params.readonly_single_input<float>(param_index, "W"); + }; + auto get_scale = [&](int param_index) -> const VArray<float> & { + return params.readonly_single_input<float>(param_index, "Scale"); + }; + auto get_randomness = [&](int param_index) -> const VArray<float> & { + return params.readonly_single_input<float>(param_index, "Randomness"); + }; + auto get_r_distance = [&](int param_index) -> MutableSpan<float> { + return params.uninitialized_single_output<float>(param_index, "Distance"); + }; + auto get_r_radius = [&](int param_index) -> MutableSpan<float> { + return params.uninitialized_single_output<float>(param_index, "Radius"); + }; + + int param = 0; + switch (dimensions_) { + case 1: { + const VArray<float> &w = get_w(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &randomness = get_randomness(param++); + switch (feature_) { + case SHD_VORONOI_DISTANCE_TO_EDGE: { + MutableSpan<float> r_distance = get_r_distance(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + const float p = w[i] * scale[i]; + noise::voronoi_distance_to_edge(p, rand, &r_distance[i]); + } + break; + } + case SHD_VORONOI_N_SPHERE_RADIUS: { + MutableSpan<float> r_radius = get_r_radius(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + const float p = w[i] * scale[i]; + noise::voronoi_n_sphere_radius(p, rand, &r_radius[i]); + } + break; + } + } + break; + } + case 2: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &randomness = get_randomness(param++); + switch (feature_) { + case SHD_VORONOI_DISTANCE_TO_EDGE: { + MutableSpan<float> r_distance = get_r_distance(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + const float2 p = float2(vector[i].x, vector[i].y) * scale[i]; + noise::voronoi_distance_to_edge(p, rand, &r_distance[i]); + } + break; + } + case SHD_VORONOI_N_SPHERE_RADIUS: { + MutableSpan<float> r_radius = get_r_radius(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + const float2 p = float2(vector[i].x, vector[i].y) * scale[i]; + noise::voronoi_n_sphere_radius(p, rand, &r_radius[i]); + } + break; + } + } + break; + } + case 3: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &randomness = get_randomness(param++); + switch (feature_) { + case SHD_VORONOI_DISTANCE_TO_EDGE: { + MutableSpan<float> r_distance = get_r_distance(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + noise::voronoi_distance_to_edge(vector[i] * scale[i], rand, &r_distance[i]); + } + break; + } + case SHD_VORONOI_N_SPHERE_RADIUS: { + MutableSpan<float> r_radius = get_r_radius(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + noise::voronoi_n_sphere_radius(vector[i] * scale[i], rand, &r_radius[i]); + } + break; + } + } + break; + } + case 4: { + const VArray<float3> &vector = get_vector(param++); + const VArray<float> &w = get_w(param++); + const VArray<float> &scale = get_scale(param++); + const VArray<float> &randomness = get_randomness(param++); + switch (feature_) { + case SHD_VORONOI_DISTANCE_TO_EDGE: { + MutableSpan<float> r_distance = get_r_distance(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i]; + noise::voronoi_distance_to_edge(p, rand, &r_distance[i]); + } + break; + } + case SHD_VORONOI_N_SPHERE_RADIUS: { + MutableSpan<float> r_radius = get_r_radius(param++); + for (int64_t i : mask) { + const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f); + const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i]; + noise::voronoi_n_sphere_radius(p, rand, &r_radius[i]); + } + break; + } + } + break; + } + } + }; +}; + +static void sh_node_voronoi_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder) +{ + bNode &node = builder.node(); + NodeTexVoronoi *tex = (NodeTexVoronoi *)node.storage; + bool minowski = (tex->distance == SHD_VORONOI_MINKOWSKI && tex->dimensions != 1 && + !ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS)); + bool dist_radius = (tex->feature == SHD_VORONOI_DISTANCE_TO_EDGE || + tex->feature == SHD_VORONOI_N_SPHERE_RADIUS); + if (dist_radius) { + builder.construct_and_set_matching_fn<VoronoiEdgeFunction>(tex->dimensions, tex->feature); + } + else if (minowski) { + builder.construct_and_set_matching_fn<VoronoiMinowskiFunction>(tex->dimensions, tex->feature); + } + else { + builder.construct_and_set_matching_fn<VoronoiMetricFunction>( + tex->dimensions, tex->feature, tex->distance); + } +} + +} // namespace blender::nodes + void register_node_type_sh_tex_voronoi(void) { static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_TEX_VORONOI, "Voronoi Texture", NODE_CLASS_TEXTURE, 0); + sh_fn_node_type_base(&ntype, SH_NODE_TEX_VORONOI, "Voronoi Texture", NODE_CLASS_TEXTURE, 0); ntype.declare = blender::nodes::sh_node_tex_voronoi_declare; node_type_init(&ntype, node_shader_init_tex_voronoi); node_type_storage( &ntype, "NodeTexVoronoi", node_free_standard_storage, node_copy_standard_storage); node_type_gpu(&ntype, node_shader_gpu_tex_voronoi); node_type_update(&ntype, node_shader_update_tex_voronoi); + ntype.build_multi_function = blender::nodes::sh_node_voronoi_build_multi_function; nodeRegisterType(&ntype); } |