Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Jolly <charlie>2021-10-15 17:27:16 +0300
committerCharlie Jolly <mistajolly@gmail.com>2021-10-15 17:28:20 +0300
commit104887800c0f221fbcffa84bb360dd9ff001d7f1 (patch)
tree743a308c6eda1918e4e97df0d8ba32b7046bedf7 /source/blender/nodes/shader
parent6e4ab5b761b03b52177985ecbeb2c2f576159c74 (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.cc911
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);
}