Blender V5.0
node_shader_tex_voronoi.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "node_shader_util.hh"
6#include "node_util.hh"
7
8#include "BKE_texture.h"
9
10#include "BLI_noise.hh"
11
12#include "NOD_multi_function.hh"
13
14#include "RNA_access.hh"
15
17#include "UI_resources.hh"
18
20
22
24{
25 b.is_function_node();
26 b.add_input<decl::Vector>("Vector").hide_value().implicit_field(
28 b.add_input<decl::Float>("W").min(-1000.0f).max(1000.0f).make_available([](bNode &node) {
29 /* Default to 1 instead of 4, because it is much faster. */
30 node_storage(node).dimensions = 1;
31 });
32 b.add_input<decl::Float>("Scale").min(-1000.0f).max(1000.0f).default_value(5.0f);
33 b.add_input<decl::Float>("Detail")
34 .min(0.0f)
35 .max(15.0f)
36 .default_value(0.0f)
37 .make_available([](bNode &node) { node_storage(node).feature = SHD_VORONOI_F1; })
38 .description("The number of Voronoi layers to sum");
39 b.add_input<decl::Float>("Roughness")
40 .min(0.0f)
41 .max(1.0f)
42 .default_value(0.5f)
43 .subtype(PROP_FACTOR)
44 .make_available([](bNode &node) { node_storage(node).feature = SHD_VORONOI_F1; })
45 .description("The influence of a Voronoi layer relative to that of the previous layer");
46 b.add_input<decl::Float>("Lacunarity")
47 .min(0.0f)
48 .max(1000.0f)
49 .default_value(2.0f)
50 .make_available([](bNode &node) { node_storage(node).feature = SHD_VORONOI_F1; })
51 .description("The scale of a Voronoi layer relative to that of the previous layer");
52 b.add_input<decl::Float>("Smoothness")
53 .min(0.0f)
54 .max(1.0f)
55 .default_value(1.0f)
56 .subtype(PROP_FACTOR)
57 .make_available([](bNode &node) { node_storage(node).feature = SHD_VORONOI_SMOOTH_F1; });
58 b.add_input<decl::Float>("Exponent")
59 .min(0.0f)
60 .max(32.0f)
61 .default_value(0.5f)
62 .make_available([](bNode &node) { node_storage(node).distance = SHD_VORONOI_MINKOWSKI; });
63 b.add_input<decl::Float>("Randomness")
64 .min(0.0f)
65 .max(1.0f)
66 .default_value(1.0f)
67 .subtype(PROP_FACTOR);
68 b.add_output<decl::Float>("Distance").no_muted_links();
69 b.add_output<decl::Color>("Color").no_muted_links();
70 b.add_output<decl::Vector>("Position").no_muted_links();
71 b.add_output<decl::Float>("W").no_muted_links().make_available([](bNode &node) {
72 /* Default to 1 instead of 4, because it is much faster. */
73 node_storage(node).dimensions = 1;
74 });
75 b.add_output<decl::Float>("Radius").no_muted_links().make_available(
76 [](bNode &node) { node_storage(node).feature = SHD_VORONOI_N_SPHERE_RADIUS; });
77}
78
80{
81 layout->prop(ptr, "voronoi_dimensions", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
82 layout->prop(ptr, "feature", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
83 int feature = RNA_enum_get(ptr, "feature");
85 RNA_enum_get(ptr, "voronoi_dimensions") != 1)
86 {
87 layout->prop(ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
88 }
89 if (!ELEM(feature, SHD_VORONOI_N_SPHERE_RADIUS)) {
90 layout->prop(ptr, "normalize", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
91 }
92}
93
94static void node_shader_init_tex_voronoi(bNodeTree * /*ntree*/, bNode *node)
95{
99 tex->dimensions = 3;
101 tex->feature = SHD_VORONOI_F1;
102 tex->normalize = false;
103
104 node->storage = tex;
105}
106
107static const char *gpu_shader_get_name(const int feature, const int dimensions)
108{
109 BLI_assert(feature >= 0 && feature < 5);
110 BLI_assert(dimensions > 0 && dimensions < 5);
111
112 switch (feature) {
113 case SHD_VORONOI_F1:
114 return std::array{
115 "node_tex_voronoi_f1_1d",
116 "node_tex_voronoi_f1_2d",
117 "node_tex_voronoi_f1_3d",
118 "node_tex_voronoi_f1_4d",
119 }[dimensions - 1];
120 case SHD_VORONOI_F2:
121 return std::array{
122 "node_tex_voronoi_f2_1d",
123 "node_tex_voronoi_f2_2d",
124 "node_tex_voronoi_f2_3d",
125 "node_tex_voronoi_f2_4d",
126 }[dimensions - 1];
128 return std::array{
129 "node_tex_voronoi_smooth_f1_1d",
130 "node_tex_voronoi_smooth_f1_2d",
131 "node_tex_voronoi_smooth_f1_3d",
132 "node_tex_voronoi_smooth_f1_4d",
133 }[dimensions - 1];
135 return std::array{
136 "node_tex_voronoi_distance_to_edge_1d",
137 "node_tex_voronoi_distance_to_edge_2d",
138 "node_tex_voronoi_distance_to_edge_3d",
139 "node_tex_voronoi_distance_to_edge_4d",
140 }[dimensions - 1];
142 return std::array{
143 "node_tex_voronoi_n_sphere_radius_1d",
144 "node_tex_voronoi_n_sphere_radius_2d",
145 "node_tex_voronoi_n_sphere_radius_3d",
146 "node_tex_voronoi_n_sphere_radius_4d",
147 }[dimensions - 1];
148 }
149 return nullptr;
150}
151
153 bNode *node,
154 bNodeExecData * /*execdata*/,
157{
158 node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
160
161 NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
162 float metric = tex->distance;
163 float normalize = tex->normalize;
164
165 const char *name = gpu_shader_get_name(tex->feature, tex->dimensions);
166
167 return GPU_stack_link(mat, node, name, in, out, GPU_constant(&metric), GPU_constant(&normalize));
168}
169
171{
172 bNodeSocket *inVectorSock = bke::node_find_socket(*node, SOCK_IN, "Vector");
173 bNodeSocket *inWSock = bke::node_find_socket(*node, SOCK_IN, "W");
174 bNodeSocket *inDetailSock = bke::node_find_socket(*node, SOCK_IN, "Detail");
175 bNodeSocket *inRoughnessSock = bke::node_find_socket(*node, SOCK_IN, "Roughness");
176 bNodeSocket *inLacunaritySock = bke::node_find_socket(*node, SOCK_IN, "Lacunarity");
177 bNodeSocket *inSmoothnessSock = bke::node_find_socket(*node, SOCK_IN, "Smoothness");
178 bNodeSocket *inExponentSock = bke::node_find_socket(*node, SOCK_IN, "Exponent");
179
180 bNodeSocket *outDistanceSock = bke::node_find_socket(*node, SOCK_OUT, "Distance");
181 bNodeSocket *outColorSock = bke::node_find_socket(*node, SOCK_OUT, "Color");
182 bNodeSocket *outPositionSock = bke::node_find_socket(*node, SOCK_OUT, "Position");
183 bNodeSocket *outWSock = bke::node_find_socket(*node, SOCK_OUT, "W");
184 bNodeSocket *outRadiusSock = bke::node_find_socket(*node, SOCK_OUT, "Radius");
185
186 const NodeTexVoronoi &storage = node_storage(*node);
187
189 *ntree, *inWSock, storage.dimensions == 1 || storage.dimensions == 4);
190 bke::node_set_socket_availability(*ntree, *inVectorSock, storage.dimensions != 1);
192 *ntree,
193 *inExponentSock,
194 storage.distance == SHD_VORONOI_MINKOWSKI && storage.dimensions != 1 &&
197 *ntree, *inDetailSock, storage.feature != SHD_VORONOI_N_SPHERE_RADIUS);
199 *ntree, *inRoughnessSock, storage.feature != SHD_VORONOI_N_SPHERE_RADIUS);
201 *ntree, *inLacunaritySock, storage.feature != SHD_VORONOI_N_SPHERE_RADIUS);
203 *ntree, *inSmoothnessSock, storage.feature == SHD_VORONOI_SMOOTH_F1);
204
206 *ntree, *outDistanceSock, storage.feature != SHD_VORONOI_N_SPHERE_RADIUS);
208 *outColorSock,
212 *outPositionSock,
215 storage.dimensions != 1);
217 *outWSock,
220 ELEM(storage.dimensions, 1, 4));
222 *ntree, *outRadiusSock, storage.feature == SHD_VORONOI_N_SPHERE_RADIUS);
223}
224
225static mf::MultiFunction::ExecutionHints voronoi_execution_hints{50, false};
226
227class VoronoiMetricFunction : public mf::MultiFunction {
228 private:
229 int dimensions_;
230 int feature_;
231 int metric_;
232 bool normalize_;
233
234 public:
235 VoronoiMetricFunction(int dimensions, int feature, int metric, bool normalize)
236 : dimensions_(dimensions), feature_(feature), metric_(metric), normalize_(normalize)
237 {
238 BLI_assert(dimensions >= 1 && dimensions <= 4);
239 BLI_assert(feature >= 0 && feature <= 4);
240 if (ELEM(metric_, SHD_VORONOI_MINKOWSKI)) {
241 static std::array<mf::Signature, 12> signatures{
246
251
256 };
257 this->set_signature(&signatures[dimensions + feature * 4 - 1]);
258 }
259 else {
260 static std::array<mf::Signature, 12> signatures{
265
270
275 };
276 this->set_signature(&signatures[dimensions + feature * 4 - 1]);
277 }
278 }
279
280 static mf::Signature create_signature(int dimensions, int feature, int metric)
281 {
282 mf::Signature signature;
283 mf::SignatureBuilder builder{"voronoi_metric", signature};
284
285 if (ELEM(dimensions, 2, 3, 4)) {
286 builder.single_input<float3>("Vector");
287 }
288 if (ELEM(dimensions, 1, 4)) {
289 builder.single_input<float>("W");
290 }
291 builder.single_input<float>("Scale");
292 builder.single_input<float>("Detail");
293 builder.single_input<float>("Roughness");
294 builder.single_input<float>("Lacunarity");
295 if (feature == SHD_VORONOI_SMOOTH_F1) {
296 builder.single_input<float>("Smoothness");
297 }
298 if ((dimensions != 1) && (metric == SHD_VORONOI_MINKOWSKI)) {
299 builder.single_input<float>("Exponent");
300 }
301 builder.single_input<float>("Randomness");
302
303 builder.single_output<float>("Distance", mf::ParamFlag::SupportsUnusedOutput);
304 builder.single_output<ColorGeometry4f>("Color", mf::ParamFlag::SupportsUnusedOutput);
305 if (dimensions != 1) {
306 builder.single_output<float3>("Position", mf::ParamFlag::SupportsUnusedOutput);
307 }
308 if (ELEM(dimensions, 1, 4)) {
309 builder.single_output<float>("W", mf::ParamFlag::SupportsUnusedOutput);
310 }
311
312 return signature;
313 }
314
315 void call(const IndexMask &mask, mf::Params mf_params, mf::Context /*context*/) const override
316 {
317 auto get_vector = [&](int param_index) -> VArray<float3> {
318 return mf_params.readonly_single_input<float3>(param_index, "Vector");
319 };
320 auto get_w = [&](int param_index) -> VArray<float> {
321 return mf_params.readonly_single_input<float>(param_index, "W");
322 };
323 auto get_scale = [&](int param_index) -> VArray<float> {
324 return mf_params.readonly_single_input<float>(param_index, "Scale");
325 };
326 auto get_detail = [&](int param_index) -> VArray<float> {
327 return mf_params.readonly_single_input<float>(param_index, "Detail");
328 };
329 auto get_roughness = [&](int param_index) -> VArray<float> {
330 return mf_params.readonly_single_input<float>(param_index, "Roughness");
331 };
332 auto get_lacunarity = [&](int param_index) -> VArray<float> {
333 return mf_params.readonly_single_input<float>(param_index, "Lacunarity");
334 };
335 auto get_smoothness = [&](int param_index) -> VArray<float> {
336 return mf_params.readonly_single_input<float>(param_index, "Smoothness");
337 };
338 auto get_exponent = [&](int param_index) -> VArray<float> {
339 return mf_params.readonly_single_input<float>(param_index, "Exponent");
340 };
341 auto get_randomness = [&](int param_index) -> VArray<float> {
342 return mf_params.readonly_single_input<float>(param_index, "Randomness");
343 };
344 auto get_r_distance = [&](int param_index) -> MutableSpan<float> {
345 return mf_params.uninitialized_single_output_if_required<float>(param_index, "Distance");
346 };
347 auto get_r_color = [&](int param_index) -> MutableSpan<ColorGeometry4f> {
348 return mf_params.uninitialized_single_output_if_required<ColorGeometry4f>(param_index,
349 "Color");
350 };
351 auto get_r_position = [&](int param_index) -> MutableSpan<float3> {
352 return mf_params.uninitialized_single_output_if_required<float3>(param_index, "Position");
353 };
354 auto get_r_w = [&](int param_index) -> MutableSpan<float> {
355 return mf_params.uninitialized_single_output_if_required<float>(param_index, "W");
356 };
357
358 int param = 0;
359
360 const VArray<float3> &vector = !ELEM(dimensions_, 1) ? get_vector(param++) : VArray<float3>{};
361 const VArray<float> &w = ELEM(dimensions_, 1, 4) ? get_w(param++) : VArray<float>{};
362 const VArray<float> &scale = get_scale(param++);
363 const VArray<float> &detail = get_detail(param++);
364 const VArray<float> &roughness = get_roughness(param++);
365 const VArray<float> &lacunarity = get_lacunarity(param++);
366 const VArray<float> &smoothness = ELEM(feature_, SHD_VORONOI_SMOOTH_F1) ?
367 get_smoothness(param++) :
369 const VArray<float> &exponent = ELEM(metric_, SHD_VORONOI_MINKOWSKI) && !ELEM(dimensions_, 1) ?
370 get_exponent(param++) :
372 const VArray<float> &randomness = get_randomness(param++);
373 MutableSpan<float> r_distance = get_r_distance(param++);
374 MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
375 MutableSpan<float3> r_position = !ELEM(dimensions_, 1) ? get_r_position(param++) :
377 MutableSpan<float> r_w = ELEM(dimensions_, 1, 4) ? get_r_w(param++) : MutableSpan<float>{};
378 const bool calc_distance = !r_distance.is_empty();
379 const bool calc_color = !r_color.is_empty();
380 const bool calc_position = !r_position.is_empty();
381 const bool calc_w = !r_w.is_empty();
382
384 params.feature = feature_;
385 params.metric = metric_;
386 params.normalize = normalize_;
387
389 switch (dimensions_) {
390 case 1: {
391 mask.foreach_index([&](const int64_t i) {
392 params.scale = scale[i];
393 params.detail = detail[i];
394 params.roughness = roughness[i];
395 params.lacunarity = lacunarity[i];
396 params.smoothness = ELEM(feature_, SHD_VORONOI_SMOOTH_F1) ?
397 std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f) :
398 0.0f;
399 params.exponent = 0.0f;
400 params.randomness = std::min(std::max(randomness[i], 0.0f), 1.0f);
401 params.max_distance = (0.5f + 0.5f * params.randomness) *
402 ((params.feature == SHD_VORONOI_F2) ? 2.0f : 1.0f);
403
404 output = noise::fractal_voronoi_x_fx<float>(params, w[i] * params.scale, calc_color);
405 if (calc_distance) {
406 r_distance[i] = output.distance;
407 }
408 if (calc_color) {
409 r_color[i] = ColorGeometry4f(output.color.x, output.color.y, output.color.z, 1.0f);
410 }
411 if (calc_w) {
412 r_w[i] = output.position.w;
413 }
414 });
415 break;
416 }
417 case 2: {
418 mask.foreach_index([&](const int64_t i) {
419 params.scale = scale[i];
420 params.detail = detail[i];
421 params.roughness = roughness[i];
422 params.lacunarity = lacunarity[i];
423 params.smoothness = ELEM(feature_, SHD_VORONOI_SMOOTH_F1) ?
424 std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f) :
425 0.0f;
426 params.exponent = ELEM(metric_, SHD_VORONOI_MINKOWSKI) && !ELEM(dimensions_, 1) ?
427 exponent[i] :
428 0.0f;
429 params.randomness = std::min(std::max(randomness[i], 0.0f), 1.0f);
430 params.max_distance = noise::voronoi_distance(float2{0.0f, 0.0f},
431 float2(0.5f + 0.5f * params.randomness,
432 0.5f + 0.5f * params.randomness),
433 params) *
434 ((params.feature == SHD_VORONOI_F2) ? 2.0f : 1.0f);
435
437 params, float2{vector[i].x, vector[i].y} * params.scale, calc_color);
438 if (calc_distance) {
439 r_distance[i] = output.distance;
440 }
441 if (calc_color) {
442 r_color[i] = ColorGeometry4f(output.color.x, output.color.y, output.color.z, 1.0f);
443 }
444 if (calc_position) {
445 r_position[i] = float3{output.position.x, output.position.y, 0.0f};
446 }
447 });
448 break;
449 }
450 case 3: {
451 mask.foreach_index([&](const int64_t i) {
452 params.scale = scale[i];
453 params.detail = detail[i];
454 params.roughness = roughness[i];
455 params.lacunarity = lacunarity[i];
456 params.smoothness = ELEM(feature_, SHD_VORONOI_SMOOTH_F1) ?
457 std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f) :
458 0.0f;
459 params.exponent = ELEM(metric_, SHD_VORONOI_MINKOWSKI) && !ELEM(dimensions_, 1) ?
460 exponent[i] :
461 0.0f;
462 params.randomness = std::min(std::max(randomness[i], 0.0f), 1.0f);
463 params.max_distance = noise::voronoi_distance(float3{0.0f, 0.0f, 0.0f},
464 float3(0.5f + 0.5f * params.randomness,
465 0.5f + 0.5f * params.randomness,
466 0.5f + 0.5f * params.randomness),
467 params) *
468 ((params.feature == SHD_VORONOI_F2) ? 2.0f : 1.0f);
469
471 params, vector[i] * params.scale, calc_color);
472 if (calc_distance) {
473 r_distance[i] = output.distance;
474 }
475 if (calc_color) {
476 r_color[i] = ColorGeometry4f(output.color.x, output.color.y, output.color.z, 1.0f);
477 }
478 if (calc_position) {
479 r_position[i] = float3{output.position.x, output.position.y, output.position.z};
480 }
481 });
482 break;
483 }
484 case 4: {
485 mask.foreach_index([&](const int64_t i) {
486 params.scale = scale[i];
487 params.detail = detail[i];
488 params.roughness = roughness[i];
489 params.lacunarity = lacunarity[i];
490 params.smoothness = ELEM(feature_, SHD_VORONOI_SMOOTH_F1) ?
491 std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f) :
492 0.0f;
493 params.exponent = ELEM(metric_, SHD_VORONOI_MINKOWSKI) && !ELEM(dimensions_, 1) ?
494 exponent[i] :
495 0.0f;
496 params.randomness = std::min(std::max(randomness[i], 0.0f), 1.0f);
497 params.max_distance = noise::voronoi_distance(float4{0.0f, 0.0f, 0.0f, 0.0f},
498 float4(0.5f + 0.5f * params.randomness,
499 0.5f + 0.5f * params.randomness,
500 0.5f + 0.5f * params.randomness,
501 0.5f + 0.5f * params.randomness),
502 params) *
503 ((params.feature == SHD_VORONOI_F2) ? 2.0f : 1.0f);
504
506 params,
507 float4{vector[i].x, vector[i].y, vector[i].z, w[i]} * params.scale,
508 calc_color);
509 if (calc_distance) {
510 r_distance[i] = output.distance;
511 }
512 if (calc_color) {
513 r_color[i] = ColorGeometry4f(output.color.x, output.color.y, output.color.z, 1.0f);
514 }
515 if (calc_position) {
516 r_position[i] = float3{output.position.x, output.position.y, output.position.z};
517 }
518 if (calc_w) {
519 r_w[i] = output.position.w;
520 }
521 });
522 break;
523 }
524 }
525 }
526
528 {
530 }
531};
532
533class VoronoiDistToEdgeFunction : public mf::MultiFunction {
534 private:
535 int dimensions_;
536 bool normalize_;
537
538 public:
540 : dimensions_(dimensions), normalize_(normalize)
541 {
542 BLI_assert(dimensions >= 1 && dimensions <= 4);
543 static std::array<mf::Signature, 4> signatures{
548 };
549 this->set_signature(&signatures[dimensions - 1]);
550 }
551
552 static mf::Signature create_signature(int dimensions)
553 {
554 mf::Signature signature;
555 mf::SignatureBuilder builder{"voronoi_dist_to_edge", signature};
556
557 if (ELEM(dimensions, 2, 3, 4)) {
558 builder.single_input<float3>("Vector");
559 }
560 if (ELEM(dimensions, 1, 4)) {
561 builder.single_input<float>("W");
562 }
563 builder.single_input<float>("Scale");
564 builder.single_input<float>("Detail");
565 builder.single_input<float>("Roughness");
566 builder.single_input<float>("Lacunarity");
567 builder.single_input<float>("Randomness");
568
569 builder.single_output<float>("Distance");
570
571 return signature;
572 }
573
574 void call(const IndexMask &mask, mf::Params mf_params, mf::Context /*context*/) const override
575 {
576 auto get_vector = [&](int param_index) -> VArray<float3> {
577 return mf_params.readonly_single_input<float3>(param_index, "Vector");
578 };
579 auto get_w = [&](int param_index) -> VArray<float> {
580 return mf_params.readonly_single_input<float>(param_index, "W");
581 };
582 auto get_scale = [&](int param_index) -> VArray<float> {
583 return mf_params.readonly_single_input<float>(param_index, "Scale");
584 };
585 auto get_detail = [&](int param_index) -> VArray<float> {
586 return mf_params.readonly_single_input<float>(param_index, "Detail");
587 };
588 auto get_roughness = [&](int param_index) -> VArray<float> {
589 return mf_params.readonly_single_input<float>(param_index, "Roughness");
590 };
591 auto get_lacunarity = [&](int param_index) -> VArray<float> {
592 return mf_params.readonly_single_input<float>(param_index, "Lacunarity");
593 };
594 auto get_randomness = [&](int param_index) -> VArray<float> {
595 return mf_params.readonly_single_input<float>(param_index, "Randomness");
596 };
597 auto get_r_distance = [&](int param_index) -> MutableSpan<float> {
598 return mf_params.uninitialized_single_output<float>(param_index, "Distance");
599 };
600
601 int param = 0;
602
603 const VArray<float3> &vector = !ELEM(dimensions_, 1) ? get_vector(param++) : VArray<float3>{};
604 const VArray<float> &w = ELEM(dimensions_, 1, 4) ? get_w(param++) : VArray<float>{};
605 const VArray<float> &scale = get_scale(param++);
606 const VArray<float> &detail = get_detail(param++);
607 const VArray<float> &roughness = get_roughness(param++);
608 const VArray<float> &lacunarity = get_lacunarity(param++);
609 const VArray<float> &randomness = get_randomness(param++);
610 MutableSpan<float> r_distance = get_r_distance(param++);
611
613 params.normalize = normalize_;
614
615 switch (dimensions_) {
616 case 1: {
617 mask.foreach_index([&](const int64_t i) {
618 params.scale = scale[i];
619 params.detail = detail[i];
620 params.roughness = roughness[i];
621 params.lacunarity = lacunarity[i];
622 params.randomness = std::min(std::max(randomness[i], 0.0f), 1.0f);
623 params.max_distance = 0.5f + 0.5f * params.randomness;
624
626 w[i] * params.scale);
627 });
628 break;
629 }
630 case 2: {
631 mask.foreach_index([&](const int64_t i) {
632 params.scale = scale[i];
633 params.detail = detail[i];
634 params.roughness = roughness[i];
635 params.lacunarity = lacunarity[i];
636 params.randomness = std::min(std::max(randomness[i], 0.0f), 1.0f);
637 params.max_distance = 0.5f + 0.5f * params.randomness;
638
640 params, float2{vector[i].x, vector[i].y} * params.scale);
641 });
642 break;
643 }
644 case 3: {
645 mask.foreach_index([&](const int64_t i) {
646 params.scale = scale[i];
647 params.detail = detail[i];
648 params.roughness = roughness[i];
649 params.lacunarity = lacunarity[i];
650 params.randomness = std::min(std::max(randomness[i], 0.0f), 1.0f);
651 params.max_distance = 0.5f + 0.5f * params.randomness;
652
654 params, vector[i] * params.scale);
655 });
656 break;
657 }
658 case 4: {
659 mask.foreach_index([&](const int64_t i) {
660 params.scale = scale[i];
661 params.detail = detail[i];
662 params.roughness = roughness[i];
663 params.lacunarity = lacunarity[i];
664 params.randomness = std::min(std::max(randomness[i], 0.0f), 1.0f);
665 params.max_distance = 0.5f + 0.5f * params.randomness;
666
668 params, float4{vector[i].x, vector[i].y, vector[i].z, w[i]} * params.scale);
669 });
670 break;
671 }
672 }
673 }
674
676 {
678 }
679};
680
681class VoronoiNSphereFunction : public mf::MultiFunction {
682 private:
683 int dimensions_;
684
685 public:
686 VoronoiNSphereFunction(int dimensions) : dimensions_(dimensions)
687 {
688 BLI_assert(dimensions >= 1 && dimensions <= 4);
689 static std::array<mf::Signature, 4> signatures{
694 };
695 this->set_signature(&signatures[dimensions - 1]);
696 }
697
698 static mf::Signature create_signature(int dimensions)
699 {
700 mf::Signature signature;
701 mf::SignatureBuilder builder{"voronoi_n_sphere", signature};
702
703 if (ELEM(dimensions, 2, 3, 4)) {
704 builder.single_input<float3>("Vector");
705 }
706 if (ELEM(dimensions, 1, 4)) {
707 builder.single_input<float>("W");
708 }
709 builder.single_input<float>("Scale");
710 builder.single_input<float>("Randomness");
711
712 builder.single_output<float>("Radius");
713
714 return signature;
715 }
716
717 void call(const IndexMask &mask, mf::Params mf_params, mf::Context /*context*/) const override
718 {
719 auto get_vector = [&](int param_index) -> VArray<float3> {
720 return mf_params.readonly_single_input<float3>(param_index, "Vector");
721 };
722 auto get_w = [&](int param_index) -> VArray<float> {
723 return mf_params.readonly_single_input<float>(param_index, "W");
724 };
725 auto get_scale = [&](int param_index) -> VArray<float> {
726 return mf_params.readonly_single_input<float>(param_index, "Scale");
727 };
728 auto get_randomness = [&](int param_index) -> VArray<float> {
729 return mf_params.readonly_single_input<float>(param_index, "Randomness");
730 };
731 auto get_r_radius = [&](int param_index) -> MutableSpan<float> {
732 return mf_params.uninitialized_single_output<float>(param_index, "Radius");
733 };
734
735 int param = 0;
736
737 const VArray<float3> &vector = !ELEM(dimensions_, 1) ? get_vector(param++) : VArray<float3>{};
738 const VArray<float> &w = ELEM(dimensions_, 1, 4) ? get_w(param++) : VArray<float>{};
739 const VArray<float> &scale = get_scale(param++);
740 const VArray<float> &randomness = get_randomness(param++);
741 MutableSpan<float> r_radius = get_r_radius(param++);
742
744
745 switch (dimensions_) {
746 case 1: {
747 mask.foreach_index([&](const int64_t i) {
748 params.scale = scale[i];
749 params.randomness = std::min(std::max(randomness[i], 0.0f), 1.0f);
750
751 r_radius[i] = noise::voronoi_n_sphere_radius(params, w[i] * params.scale);
752 });
753 break;
754 }
755 case 2: {
756 mask.foreach_index([&](const int64_t i) {
757 params.scale = scale[i];
758 params.randomness = std::min(std::max(randomness[i], 0.0f), 1.0f);
759
761 params, float2{vector[i].x, vector[i].y} * params.scale);
762 });
763 break;
764 }
765 case 3: {
766 mask.foreach_index([&](const int64_t i) {
767 params.scale = scale[i];
768 params.randomness = std::min(std::max(randomness[i], 0.0f), 1.0f);
769
770 r_radius[i] = noise::voronoi_n_sphere_radius(params, vector[i] * params.scale);
771 });
772 break;
773 }
774 case 4: {
775 mask.foreach_index([&](const int64_t i) {
776 params.scale = scale[i];
777 params.randomness = std::min(std::max(randomness[i], 0.0f), 1.0f);
778
780 params, float4{vector[i].x, vector[i].y, vector[i].z, w[i]} * params.scale);
781 });
782 break;
783 }
784 }
785 }
786
788 {
790 }
791};
792
794{
795 const NodeTexVoronoi &storage = node_storage(builder.node());
796 switch (storage.feature) {
799 storage.normalize);
800 break;
801 }
804 break;
805 }
806 default: {
808 storage.dimensions, storage.feature, storage.distance, storage.normalize);
809 break;
810 }
811 }
812}
813
814} // namespace blender::nodes::node_shader_tex_voronoi_cc
815
817{
819
820 static blender::bke::bNodeType ntype;
821
822 common_node_type_base(&ntype, "ShaderNodeTexVoronoi", SH_NODE_TEX_VORONOI);
823 ntype.ui_name = "Voronoi Texture";
824 ntype.ui_description =
825 "Generate Worley noise based on the distance to random points. Typically used to generate "
826 "textures such as stones, water, or biological cells";
827 ntype.enum_name_legacy = "TEX_VORONOI";
829 ntype.declare = file_ns::sh_node_tex_voronoi_declare;
830 ntype.draw_buttons = file_ns::node_shader_buts_tex_voronoi;
831 ntype.initfunc = file_ns::node_shader_init_tex_voronoi;
834 ntype.gpu_fn = file_ns::node_shader_gpu_tex_voronoi;
835 ntype.updatefunc = file_ns::node_shader_update_tex_voronoi;
836 ntype.build_multi_function = file_ns::sh_node_voronoi_build_multi_function;
838
840}
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1240
constexpr int NODE_DEFAULT_MAX_WIDTH
Definition BKE_node.hh:1250
#define NODE_CLASS_TEXTURE
Definition BKE_node.hh:457
#define SH_NODE_TEX_VORONOI
void BKE_texture_mapping_default(struct TexMapping *texmap, int type)
Definition texture.cc:234
void BKE_texture_colormapping_default(struct ColorMapping *colormap)
Definition texture.cc:337
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ELEM(...)
@ NODE_DEFAULT_INPUT_POSITION_FIELD
@ SHD_VORONOI_EUCLIDEAN
@ SHD_VORONOI_MINKOWSKI
@ SHD_VORONOI_F2
@ SHD_VORONOI_SMOOTH_F1
@ SHD_VORONOI_DISTANCE_TO_EDGE
@ SHD_VORONOI_F1
@ SHD_VORONOI_N_SPHERE_RADIUS
@ SOCK_OUT
@ SOCK_IN
@ TEXMAP_TYPE_POINT
bool GPU_stack_link(GPUMaterial *mat, const bNode *node, const char *name, GPUNodeStack *in, GPUNodeStack *out,...)
GPUNodeLink * GPU_constant(const float *num)
@ PROP_FACTOR
Definition RNA_types.hh:251
@ UI_ITEM_R_SPLIT_EMPTY_NAME
long long int int64_t
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
constexpr bool is_empty() const
Definition BLI_span.hh:509
void set_signature(const Signature *signature)
void call(const IndexMask &mask, mf::Params mf_params, mf::Context) const override
void call(const IndexMask &mask, mf::Params mf_params, mf::Context) const override
static mf::Signature create_signature(int dimensions, int feature, int metric)
VoronoiMetricFunction(int dimensions, int feature, int metric, bool normalize)
void call(const IndexMask &mask, mf::Params mf_params, mf::Context) const override
#define in
#define out
#define output
VecBase< float, D > normalize(VecOp< float, D >) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:2532
void node_type_size(bNodeType &ntype, int width, int minwidth, int maxwidth)
Definition node.cc:5384
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
void node_set_socket_availability(bNodeTree &ntree, bNodeSocket &sock, bool is_available)
Definition node.cc:4739
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:5414
static const char * gpu_shader_get_name(const int feature, const int dimensions)
static void sh_node_tex_voronoi_declare(NodeDeclarationBuilder &b)
static mf::MultiFunction::ExecutionHints voronoi_execution_hints
static void sh_node_voronoi_build_multi_function(NodeMultiFunctionBuilder &builder)
static void node_shader_update_tex_voronoi(bNodeTree *ntree, bNode *node)
static int node_shader_gpu_tex_voronoi(GPUMaterial *mat, bNode *node, bNodeExecData *, GPUNodeStack *in, GPUNodeStack *out)
static void node_shader_init_tex_voronoi(bNodeTree *, bNode *node)
static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *, PointerRNA *ptr)
template VoronoiOutput fractal_voronoi_x_fx< float4 >(const VoronoiParams &params, const float4 coord, const bool calc_color)
template float fractal_voronoi_distance_to_edge< float >(const VoronoiParams &params, const float coord)
float voronoi_n_sphere_radius(const VoronoiParams &params, const float coord)
Definition noise.cc:1370
template VoronoiOutput fractal_voronoi_x_fx< float3 >(const VoronoiParams &params, const float3 coord, const bool calc_color)
float voronoi_distance(const float a, const float b)
Definition noise.cc:1166
template VoronoiOutput fractal_voronoi_x_fx< float >(const VoronoiParams &params, const float coord, const bool calc_color)
template float fractal_voronoi_distance_to_edge< float3 >(const VoronoiParams &params, const float3 coord)
template VoronoiOutput fractal_voronoi_x_fx< float2 >(const VoronoiParams &params, const float2 coord, const bool calc_color)
template float fractal_voronoi_distance_to_edge< float4 >(const VoronoiParams &params, const float4 coord)
template float fractal_voronoi_distance_to_edge< float2 >(const VoronoiParams &params, const float2 coord)
VecBase< float, 4 > float4
VecBase< float, 2 > float2
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
VecBase< float, 3 > float3
void register_node_type_sh_tex_voronoi()
void node_shader_gpu_tex_mapping(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *)
void node_shader_gpu_default_tex_coord(GPUMaterial *mat, bNode *node, GPUNodeLink **link)
void common_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:42
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:54
const char * name
int RNA_enum_get(PointerRNA *ptr, const char *name)
TexMapping tex_mapping
ColorMapping color_mapping
void * storage
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:289
NodeGPUExecFunction gpu_fn
Definition BKE_node.hh:342
NodeMultiFunctionBuildFunction build_multi_function
Definition BKE_node.hh:351
const char * enum_name_legacy
Definition BKE_node.hh:247
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:259
NodeDeclareFunction declare
Definition BKE_node.hh:362
void(* updatefunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:281
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
PointerRNA * ptr
Definition wm_files.cc:4238