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:
authorOmarSquircleArt <omar.squircleart@gmail.com>2019-09-12 14:09:31 +0300
committerOmarSquircleArt <omar.squircleart@gmail.com>2019-09-12 14:09:31 +0300
commit613b37bc2c81202a34346b40465923e8f47cebbf (patch)
treef567f30b59f475744575589f4330c61afc30a5a0 /source/blender
parent013750947657fcdea313782d82ec51cc111f0c06 (diff)
Shading: Add More Features To The Voronoi Node.
This patch allows the Voronoi node to operate in 1D, 2D, and 4D space. It also adds a Randomness input to control the randomness of the texture. Additionally, it adds three new modes of operation: - Smooth F1: A smooth version of F1 Voronoi with no discontinuities. - Distance To Edge: Returns the distance to the edges of the cells. - N-Sphere Radius: Returns the radius of the n-sphere inscribed in the cells. In other words, it is half the distance between the closest feature point and the feature point closest to it. And it removes the following three modes of operation: - F3. - F4. - Cracks. The Distance metric is now called Euclidean, and it computes the actual euclidean distance as opposed to the old method of computing the squared euclidean distance. This breaks backward compatibility in many ways, including the base case. Reviewers: brecht, JacquesLucke Differential Revision: https://developer.blender.org/D5743
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenloader/intern/versioning_cycles.c254
-rw-r--r--source/blender/editors/space_node/drawnode.c8
-rw-r--r--source/blender/gpu/CMakeLists.txt1
-rw-r--r--source/blender/gpu/intern/gpu_material_library.h11
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_cell_noise.glsl17
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl26
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl1130
-rw-r--r--source/blender/makesdna/DNA_node_types.h32
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c52
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c139
11 files changed, 1488 insertions, 184 deletions
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index b9ea85e7a00..89f83c44c11 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -27,7 +27,7 @@
* \note Use #STRINGIFY() rather than defining with quotes.
*/
#define BLENDER_VERSION 281
-#define BLENDER_SUBVERSION 10
+#define BLENDER_SUBVERSION 11
/** Several breakages with 280, e.g. collections vs layers. */
#define BLENDER_MINVERSION 280
#define BLENDER_MINSUBVERSION 0
diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c
index 9c00d829e46..52d62725ef8 100644
--- a/source/blender/blenloader/intern/versioning_cycles.c
+++ b/source/blender/blenloader/intern/versioning_cycles.c
@@ -946,6 +946,238 @@ static void update_musgrave_node_color_output(bNodeTree *ntree)
}
}
+/* The Voronoi node now have a dimension property. This property should be
+ * initialized to 3 by default.
+ */
+static void update_voronoi_node_dimensions(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_VORONOI) {
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ tex->dimensions = 3;
+ }
+ }
+}
+
+/* The F3 and F4 features of the Voronoi node have been removed.
+ * To correct this, we set the feature type to be F2 if it is F3
+ * or F4. The SHD_VORONOI_F3 and SHD_VORONOI_F4 enum values were
+ * 2 and 3 respectively.
+ */
+static void update_voronoi_node_f3_and_f4(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_VORONOI) {
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ if (ELEM(tex->feature, 2, 3)) {
+ tex->feature = SHD_VORONOI_F2;
+ }
+ }
+ }
+}
+
+/* The Fac output of the Voronoi node has been removed. Previously, this
+ * output was the voronoi distance in the Intensity mode and the Cell ID
+ * in the Cell mode. To correct this, we update the identifier and name
+ * of the Fac socket such that it gets mapped to the Distance socket.
+ * This is supposed to work with update_voronoi_node_coloring.
+ */
+static void update_voronoi_node_fac_output(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_VORONOI) {
+ bNodeSocket *facOutput = BLI_findlink(&node->outputs, 1);
+ strcpy(facOutput->identifier, "Distance");
+ strcpy(facOutput->name, "Distance");
+ }
+ }
+}
+
+/* The Crackle feature of the Voronoi node has been removed. Previously,
+ * this feature returned the F2 distance minus the F1 distance. The
+ * crackle feature had an enum value of 4. To fix this we do the
+ * following:
+ *
+ * 1. The node feature is set to F1.
+ * 2. A new Voronoi node is added and its feature is set to F2.
+ * 3. The properties, input values, and connections are copied
+ * from the node to the new Voronoi node so that they match
+ * exactly.
+ * 4. A Subtract node is added.
+ * 5. The outputs of the F1 and F2 voronoi are connected to
+ * the inputs of the subtract node.
+ * 6. The output of the subtract node is connected to the
+ * appropriate sockets.
+ *
+ */
+static void update_voronoi_node_crackle(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_VORONOI) {
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ bNodeSocket *sockDistance = nodeFindSocket(node, SOCK_OUT, "Distance");
+ bNodeSocket *sockColor = nodeFindSocket(node, SOCK_OUT, "Color");
+ if (tex->feature == 4 && (socket_is_used(sockDistance) || socket_is_used(sockColor))) {
+ tex->feature = SHD_VORONOI_F1;
+
+ bNode *voronoiNode = nodeAddStaticNode(NULL, ntree, SH_NODE_TEX_VORONOI);
+ NodeTexVoronoi *texVoronoi = (NodeTexVoronoi *)voronoiNode->storage;
+ texVoronoi->feature = SHD_VORONOI_F2;
+ texVoronoi->distance = tex->distance;
+ texVoronoi->dimensions = 3;
+ voronoiNode->locx = node->locx + node->width + 20.0f;
+ voronoiNode->locy = node->locy;
+
+ bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector");
+ bNodeSocket *sockScale = nodeFindSocket(node, SOCK_IN, "Scale");
+ bNodeSocket *sockExponent = nodeFindSocket(node, SOCK_IN, "Exponent");
+ bNodeSocket *sockVoronoiVector = nodeFindSocket(voronoiNode, SOCK_IN, "Vector");
+ bNodeSocket *sockVoronoiScale = nodeFindSocket(voronoiNode, SOCK_IN, "Scale");
+ bNodeSocket *sockVoronoiExponent = nodeFindSocket(voronoiNode, SOCK_IN, "Exponent");
+ if (sockVector->link) {
+ nodeAddLink(ntree,
+ sockVector->link->fromnode,
+ sockVector->link->fromsock,
+ voronoiNode,
+ sockVoronoiVector);
+ }
+ *cycles_node_socket_float_value(sockVoronoiScale) = *cycles_node_socket_float_value(
+ sockScale);
+ if (sockScale->link) {
+ nodeAddLink(ntree,
+ sockScale->link->fromnode,
+ sockScale->link->fromsock,
+ voronoiNode,
+ sockVoronoiScale);
+ }
+ *cycles_node_socket_float_value(sockVoronoiExponent) = *cycles_node_socket_float_value(
+ sockExponent);
+ if (sockExponent->link) {
+ nodeAddLink(ntree,
+ sockExponent->link->fromnode,
+ sockExponent->link->fromsock,
+ voronoiNode,
+ sockVoronoiExponent);
+ }
+
+ bNode *subtractNode = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
+ subtractNode->custom1 = NODE_MATH_SUBTRACT;
+ subtractNode->locx = voronoiNode->locx + voronoiNode->width + 20.0f;
+ subtractNode->locy = voronoiNode->locy;
+ bNodeSocket *sockSubtractOutValue = nodeFindSocket(subtractNode, SOCK_OUT, "Value");
+
+ LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+ if (link->fromnode == node) {
+ nodeAddLink(ntree, subtractNode, sockSubtractOutValue, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+
+ bNodeSocket *sockDistanceF1 = nodeFindSocket(node, SOCK_OUT, "Distance");
+ bNodeSocket *sockDistanceF2 = nodeFindSocket(voronoiNode, SOCK_OUT, "Distance");
+ bNodeSocket *sockSubtractA = BLI_findlink(&subtractNode->inputs, 0);
+ bNodeSocket *sockSubtractB = BLI_findlink(&subtractNode->inputs, 1);
+
+ nodeAddLink(ntree, node, sockDistanceF1, subtractNode, sockSubtractB);
+ nodeAddLink(ntree, voronoiNode, sockDistanceF2, subtractNode, sockSubtractA);
+
+ need_update = true;
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
+/* The coloring property of the Voronoi node was removed. Previously,
+ * if the coloring enum was set to Intensity (0), the voronoi distance
+ * was returned in all outputs, otherwise, the Cell ID was returned.
+ * Since we remapped the Fac output in update_voronoi_node_fac_output,
+ * then to fix this, we relink the Color output to the Distance
+ * output if coloring was set to 0, and the otherway around otherwise.
+ */
+static void update_voronoi_node_coloring(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+ bNode *node = link->fromnode;
+ if (node && node->type == SH_NODE_TEX_VORONOI) {
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ if (tex->coloring == 0) {
+ bNodeSocket *sockColor = nodeFindSocket(node, SOCK_OUT, "Color");
+ if (link->fromsock == sockColor) {
+ bNodeSocket *sockDistance = nodeFindSocket(node, SOCK_OUT, "Distance");
+ nodeAddLink(ntree, node, sockDistance, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ need_update = true;
+ }
+ }
+ else {
+ bNodeSocket *sockDistance = nodeFindSocket(node, SOCK_OUT, "Distance");
+ if (link->fromsock == sockDistance) {
+ bNodeSocket *sockColor = nodeFindSocket(node, SOCK_OUT, "Color");
+ nodeAddLink(ntree, node, sockColor, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ need_update = true;
+ }
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
+/* Previously, the output euclidean distance was actually the squared
+ * euclidean distance. To fix this, we square the the output distance
+ * socket if the distance metric is set to SHD_VORONOI_EUCLIDEAN.
+ */
+static void update_voronoi_node_square_distance(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_TEX_VORONOI) {
+ NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
+ bNodeSocket *sockDistance = nodeFindSocket(node, SOCK_OUT, "Distance");
+ if (tex->distance == SHD_VORONOI_EUCLIDEAN &&
+ (tex->feature == SHD_VORONOI_F1 || tex->feature == SHD_VORONOI_F2) &&
+ socket_is_used(sockDistance)) {
+ bNode *multiplyNode = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
+ multiplyNode->custom1 = NODE_MATH_MULTIPLY;
+ multiplyNode->locx = node->locx + node->width + 20.0f;
+ multiplyNode->locy = node->locy;
+
+ bNodeSocket *sockValue = nodeFindSocket(multiplyNode, SOCK_OUT, "Value");
+ LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+ if (link->fromsock == sockDistance) {
+ nodeAddLink(ntree, multiplyNode, sockValue, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+
+ bNodeSocket *sockMultiplyA = BLI_findlink(&multiplyNode->inputs, 0);
+ bNodeSocket *sockMultiplyB = BLI_findlink(&multiplyNode->inputs, 1);
+
+ nodeAddLink(ntree, node, sockDistance, multiplyNode, sockMultiplyA);
+ nodeAddLink(ntree, node, sockDistance, multiplyNode, sockMultiplyB);
+
+ need_update = true;
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bmain)
{
/* Particle shape shared with Eevee. */
@@ -996,6 +1228,16 @@ void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bm
}
FOREACH_NODETREE_END;
}
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 11)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_voronoi_node_f3_and_f4(ntree);
+ update_voronoi_node_fac_output(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
}
void do_versions_after_linking_cycles(Main *bmain)
@@ -1154,4 +1396,16 @@ void do_versions_after_linking_cycles(Main *bmain)
}
FOREACH_NODETREE_END;
}
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 281, 11)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_voronoi_node_dimensions(ntree);
+ update_voronoi_node_crackle(ntree);
+ update_voronoi_node_coloring(ntree);
+ update_voronoi_node_square_distance(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
}
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index c707a1eed92..6055a503b7b 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -914,9 +914,13 @@ static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C),
static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "coloring", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "distance", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "voronoi_dimensions", 0, "", ICON_NONE);
uiItemR(layout, ptr, "feature", 0, "", ICON_NONE);
+ int feature = RNA_enum_get(ptr, "feature");
+ if (!ELEM(feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS) &&
+ RNA_enum_get(ptr, "voronoi_dimensions") != 1) {
+ uiItemR(layout, ptr, "distance", 0, "", ICON_NONE);
+ }
}
static void node_shader_buts_tex_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index f11dcc9bcf0..aea96dac2e3 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -243,7 +243,6 @@ data_to_c_simple(shaders/material/gpu_shader_material_blackbody.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_bright_contrast.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_bump.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_camera.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_cell_noise.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_clamp.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_color_ramp.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_color_util.glsl SRC)
diff --git a/source/blender/gpu/intern/gpu_material_library.h b/source/blender/gpu/intern/gpu_material_library.h
index 9c0cf3e6bea..06544d27af9 100644
--- a/source/blender/gpu/intern/gpu_material_library.h
+++ b/source/blender/gpu/intern/gpu_material_library.h
@@ -44,7 +44,6 @@ extern char datatoc_gpu_shader_material_blackbody_glsl[];
extern char datatoc_gpu_shader_material_bright_contrast_glsl[];
extern char datatoc_gpu_shader_material_bump_glsl[];
extern char datatoc_gpu_shader_material_camera_glsl[];
-extern char datatoc_gpu_shader_material_cell_noise_glsl[];
extern char datatoc_gpu_shader_material_clamp_glsl[];
extern char datatoc_gpu_shader_material_color_ramp_glsl[];
extern char datatoc_gpu_shader_material_color_util_glsl[];
@@ -149,13 +148,6 @@ static GPUMaterialLibrary gpu_shader_material_fractal_noise_library = {
.dependencies = {&gpu_shader_material_noise_library, NULL},
};
-static GPUMaterialLibrary gpu_shader_material_cell_noise_library = {
- .code = datatoc_gpu_shader_material_cell_noise_glsl,
- .dependencies = {&gpu_shader_material_math_util_library,
- &gpu_shader_material_hash_library,
- NULL},
-};
-
static GPUMaterialLibrary gpu_shader_material_add_shader_library = {
.code = datatoc_gpu_shader_material_add_shader_glsl,
.dependencies = {NULL},
@@ -481,7 +473,7 @@ static GPUMaterialLibrary gpu_shader_material_texture_coordinates_library = {
static GPUMaterialLibrary gpu_shader_material_tex_voronoi_library = {
.code = datatoc_gpu_shader_material_tex_voronoi_glsl,
.dependencies = {&gpu_shader_material_math_util_library,
- &gpu_shader_material_cell_noise_library,
+ &gpu_shader_material_hash_library,
NULL},
};
@@ -571,7 +563,6 @@ static GPUMaterialLibrary *gpu_material_libraries[] = {
&gpu_shader_material_hash_library,
&gpu_shader_material_noise_library,
&gpu_shader_material_fractal_noise_library,
- &gpu_shader_material_cell_noise_library,
&gpu_shader_material_add_shader_library,
&gpu_shader_material_ambient_occlusion_library,
&gpu_shader_material_glossy_library,
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_cell_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_cell_noise.glsl
deleted file mode 100644
index 881f2386cd4..00000000000
--- a/source/blender/gpu/shaders/material/gpu_shader_material_cell_noise.glsl
+++ /dev/null
@@ -1,17 +0,0 @@
-float cellnoise(vec3 p)
-{
- int ix = quick_floor(p.x);
- int iy = quick_floor(p.y);
- int iz = quick_floor(p.z);
-
- return hash_uint3_to_float(uint(ix), uint(iy), uint(iz));
-}
-
-vec3 cellnoise_color(vec3 p)
-{
- float r = cellnoise(p.xyz);
- float g = cellnoise(p.yxz);
- float b = cellnoise(p.yzx);
-
- return vec3(r, g, b);
-}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
index fd9aaf4ae86..d4f7866b206 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
@@ -57,11 +57,37 @@ float floorfrac(float x, out int i)
/* Vector Math */
+vec2 safe_divide(vec2 a, vec2 b)
+{
+ return vec2(safe_divide(a.x, b.x), safe_divide(a.y, b.y));
+}
+
vec3 safe_divide(vec3 a, vec3 b)
{
return vec3(safe_divide(a.x, b.x), safe_divide(a.y, b.y), safe_divide(a.z, b.z));
}
+vec4 safe_divide(vec4 a, vec4 b)
+{
+ return vec4(
+ safe_divide(a.x, b.x), safe_divide(a.y, b.y), safe_divide(a.z, b.z), safe_divide(a.w, b.w));
+}
+
+vec2 safe_divide(vec2 a, float b)
+{
+ return (b != 0.0) ? a / b : vec2(0.0);
+}
+
+vec3 safe_divide(vec3 a, float b)
+{
+ return (b != 0.0) ? a / b : vec3(0.0);
+}
+
+vec4 safe_divide(vec4 a, float b)
+{
+ return (b != 0.0) ? a / b : vec4(0.0);
+}
+
vec3 c_mod(vec3 a, vec3 b)
{
return vec3(c_mod(a.x, b.x), c_mod(a.y, b.y), c_mod(a.z, b.z));
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
index 018b74fd1a5..0d8847176c9 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
@@ -1,116 +1,1064 @@
-void node_tex_voronoi(vec3 co,
- float scale,
- float exponent,
- float coloring,
- float metric,
- float feature,
- out vec4 color,
- out float fac)
-{
- vec3 p = co * scale;
- int xx, yy, zz, xi, yi, zi;
- vec4 da = vec4(1e10);
- vec3 pa[4] = vec3[4](vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0));
-
- xi = floor_to_int(p[0]);
- yi = floor_to_int(p[1]);
- zi = floor_to_int(p[2]);
-
- for (xx = xi - 1; xx <= xi + 1; xx++) {
- for (yy = yi - 1; yy <= yi + 1; yy++) {
- for (zz = zi - 1; zz <= zi + 1; zz++) {
- vec3 ip = vec3(xx, yy, zz);
- vec3 vp = cellnoise_color(ip);
- vec3 pd = p - (vp + ip);
-
- float d = 0.0;
- if (metric == 0.0) { /* SHD_VORONOI_DISTANCE 0 */
- d = dot(pd, pd);
- }
- else if (metric == 1.0) { /* SHD_VORONOI_MANHATTAN 1 */
- d = abs(pd[0]) + abs(pd[1]) + abs(pd[2]);
- }
- else if (metric == 2.0) { /* SHD_VORONOI_CHEBYCHEV 2 */
- d = max(abs(pd[0]), max(abs(pd[1]), abs(pd[2])));
- }
- else if (metric == 3.0) { /* SHD_VORONOI_MINKOWSKI 3 */
- d = pow(pow(abs(pd[0]), exponent) + pow(abs(pd[1]), exponent) +
- pow(abs(pd[2]), exponent),
- 1.0 / exponent);
- }
+/*
+ * Smooth Voronoi:
+ *
+ * - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
+ *
+ * Distance To Edge:
+ *
+ * - https://www.shadertoy.com/view/llG3zy
+ *
+ */
- vp += vec3(xx, yy, zz);
- if (d < da[0]) {
- da.yzw = da.xyz;
- da[0] = d;
+/* **** 1D Voronoi **** */
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = pa[0];
- pa[0] = vp;
- }
- else if (d < da[1]) {
- da.zw = da.yz;
- da[1] = d;
+float voronoi_distance(float a, float b, float metric, float exponent)
+{
+ return distance(a, b);
+}
+
+void node_tex_voronoi_f1_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ float targetOffset, targetPosition;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ outDistance = minDistance;
+ outColor.xyz = hash_float_to_vec3(cellPosition + targetOffset);
+ outW = safe_divide(targetPosition + cellPosition, scale);
+}
+
+void node_tex_voronoi_smooth_f1_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+ smoothness = clamp(smoothness / 2.0, 0, 0.5);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float smoothDistance = 8.0;
+ float smoothPosition = 0.0;
+ vec3 smoothColor = vec3(0.0);
+ for (int i = -2; i <= 2; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0 - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0 + 3.0 * smoothness;
+ vec3 cellColor = hash_float_to_vec3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ outDistance = smoothDistance;
+ outColor.xyz = smoothColor;
+ outW = safe_divide(cellPosition + smoothPosition, scale);
+}
+
+void node_tex_voronoi_f2_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ float offsetF1 = 0.0;
+ float positionF1 = 0.0;
+ float offsetF2, positionF2;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ outDistance = distanceF2;
+ outColor.xyz = hash_float_to_vec3(cellPosition + offsetF2);
+ outW = safe_divide(positionF2 + cellPosition, scale);
+}
+
+void node_tex_voronoi_distance_to_edge_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ minDistance = min(distanceToPoint, minDistance);
+ }
+ outDistance = minDistance;
+}
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = vp;
+void node_tex_voronoi_n_sphere_radius_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float closestPoint;
+ float closestPointOffset;
+ float minDistance = 8.0;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+
+ minDistance = 8.0;
+ float closestPointToClosestPoint;
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0) {
+ continue;
+ }
+ float cellOffset = float(i) + closestPointOffset;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 2D Voronoi **** */
+
+float voronoi_distance(vec2 a, vec2 b, float metric, float exponent)
+{
+ if (metric == 0.0) // SHD_VORONOI_EUCLIDEAN
+ {
+ return distance(a, b);
+ }
+ else if (metric == 1.0) // SHD_VORONOI_MANHATTAN
+ {
+ return abs(a.x - b.x) + abs(a.y - b.y);
+ }
+ else if (metric == 2.0) // SHD_VORONOI_CHEBYCHEV
+ {
+ return max(abs(a.x - b.x), abs(a.y - b.y));
+ }
+ else if (metric == 3.0) // SHD_VORONOI_MINKOWSKI
+ {
+ return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent), 1.0 / exponent);
+ }
+ else {
+ return 0.0;
+ }
+}
+
+void node_tex_voronoi_f1_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ vec2 targetOffset, targetPosition;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor.xyz = hash_vec2_to_vec3(cellPosition + targetOffset);
+ outPosition = vec3(safe_divide(targetPosition + cellPosition, scale), 0.0);
+}
+
+void node_tex_voronoi_smooth_f1_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+ smoothness = clamp(smoothness / 2.0, 0, 0.5);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ float smoothDistance = 8.0;
+ vec3 smoothColor = vec3(0.0);
+ vec2 smoothPosition = vec2(0.0);
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0 - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0 + 3.0 * smoothness;
+ vec3 cellColor = hash_vec2_to_vec3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ outDistance = smoothDistance;
+ outColor.xyz = smoothColor;
+ outPosition = vec3(safe_divide(cellPosition + smoothPosition, scale), 0.0);
+}
+
+void node_tex_voronoi_f2_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vec2 offsetF1 = vec2(0.0);
+ vec2 positionF1 = vec2(0.0);
+ vec2 offsetF2, positionF2;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ outDistance = distanceF2;
+ outColor.xyz = hash_vec2_to_vec3(cellPosition + offsetF2);
+ outPosition = vec3(safe_divide(positionF2 + cellPosition, scale), 0.0);
+}
+
+void node_tex_voronoi_distance_to_edge_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ vec2 vectorToClosest;
+ float minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 vectorToPoint = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 vectorToPoint = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ vec2 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ outDistance = minDistance;
+}
+
+void node_tex_voronoi_n_sphere_radius_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ vec2 closestPoint;
+ vec2 closestPointOffset;
+ float minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ vec2 closestPointToClosestPoint;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0) {
+ continue;
+ }
+ vec2 cellOffset = vec2(i, j) + closestPointOffset;
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 3D Voronoi **** */
+
+float voronoi_distance(vec3 a, vec3 b, float metric, float exponent)
+{
+ if (metric == 0.0) // SHD_VORONOI_EUCLIDEAN
+ {
+ return distance(a, b);
+ }
+ else if (metric == 1.0) // SHD_VORONOI_MANHATTAN
+ {
+ return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z);
+ }
+ else if (metric == 2.0) // SHD_VORONOI_CHEBYCHEV
+ {
+ return max(abs(a.x - b.x), max(abs(a.y - b.y), abs(a.z - b.z)));
+ }
+ else if (metric == 3.0) // SHD_VORONOI_MINKOWSKI
+ {
+ return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent) +
+ pow(abs(a.z - b.z), exponent),
+ 1.0 / exponent);
+ }
+ else {
+ return 0.0;
+ }
+}
+
+void node_tex_voronoi_f1_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ vec3 targetOffset, targetPosition;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 pointPosition = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
}
- else if (d < da[2]) {
- da[3] = da[2];
- da[2] = d;
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor.xyz = hash_vec3_to_vec3(cellPosition + targetOffset);
+ outPosition = safe_divide(targetPosition + cellPosition, scale);
+}
- pa[3] = pa[2];
- pa[2] = vp;
+void node_tex_voronoi_smooth_f1_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+ smoothness = clamp(smoothness / 2.0, 0, 0.5);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ float smoothDistance = 8.0;
+ vec3 smoothColor = vec3(0.0);
+ vec3 smoothPosition = vec3(0.0);
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 pointPosition = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0 - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0 + 3.0 * smoothness;
+ vec3 cellColor = hash_vec3_to_vec3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
+ outDistance = smoothDistance;
+ outColor.xyz = smoothColor;
+ outPosition = safe_divide(cellPosition + smoothPosition, scale);
+}
+
+void node_tex_voronoi_f2_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vec3 offsetF1 = vec3(0.0);
+ vec3 positionF1 = vec3(0.0);
+ vec3 offsetF2, positionF2;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 pointPosition = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
}
- else if (d < da[3]) {
- da[3] = d;
- pa[3] = vp;
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
}
}
}
}
+ outDistance = distanceF2;
+ outColor.xyz = hash_vec3_to_vec3(cellPosition + offsetF2);
+ outPosition = safe_divide(positionF2 + cellPosition, scale);
+}
- if (coloring == 0.0) {
- /* Intensity output */
- if (feature == 0.0) { /* F1 */
- fac = abs(da[0]);
- }
- else if (feature == 1.0) { /* F2 */
- fac = abs(da[1]);
+void node_tex_voronoi_distance_to_edge_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ vec3 vectorToClosest;
+ float minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 vectorToPoint = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
}
- else if (feature == 2.0) { /* F3 */
- fac = abs(da[2]);
+ }
+
+ minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 vectorToPoint = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ vec3 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
}
- else if (feature == 3.0) { /* F4 */
- fac = abs(da[3]);
+ }
+ outDistance = minDistance;
+}
+
+void node_tex_voronoi_n_sphere_radius_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ vec3 closestPoint;
+ vec3 closestPointOffset;
+ float minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 pointPosition = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
}
- else if (feature == 4.0) { /* F2F1 */
- fac = abs(da[1] - da[0]);
+ }
+
+ minDistance = 8.0;
+ vec3 closestPointToClosestPoint;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0) {
+ continue;
+ }
+ vec3 cellOffset = vec3(i, j, k) + closestPointOffset;
+ vec3 pointPosition = cellOffset +
+ hash_vec3_to_vec3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
}
- color = vec4(fac, fac, fac, 1.0);
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 4D Voronoi **** */
+
+float voronoi_distance(vec4 a, vec4 b, float metric, float exponent)
+{
+ if (metric == 0.0) // SHD_VORONOI_EUCLIDEAN
+ {
+ return distance(a, b);
+ }
+ else if (metric == 1.0) // SHD_VORONOI_MANHATTAN
+ {
+ return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z) + abs(a.w - b.w);
+ }
+ else if (metric == 2.0) // SHD_VORONOI_CHEBYCHEV
+ {
+ return max(abs(a.x - b.x), max(abs(a.y - b.y), max(abs(a.z - b.z), abs(a.w - b.w))));
+ }
+ else if (metric == 3.0) // SHD_VORONOI_MINKOWSKI
+ {
+ return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent) +
+ pow(abs(a.z - b.z), exponent) + pow(abs(a.w - b.w), exponent),
+ 1.0 / exponent);
}
else {
- /* Color output */
- vec3 col = vec3(fac, fac, fac);
- if (feature == 0.0) { /* F1 */
- col = pa[0];
+ return 0.0;
+ }
+}
+
+void node_tex_voronoi_f1_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ vec4 targetOffset, targetPosition;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 pointPosition = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
}
- else if (feature == 1.0) { /* F2 */
- col = pa[1];
+ }
+ outDistance = minDistance;
+ outColor.xyz = hash_vec4_to_vec3(cellPosition + targetOffset);
+ vec4 p = safe_divide(targetPosition + cellPosition, scale);
+ outPosition = p.xyz;
+ outW = p.w;
+}
+
+void node_tex_voronoi_smooth_f1_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+ smoothness = clamp(smoothness / 2.0, 0, 0.5);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ float smoothDistance = 8.0;
+ vec3 smoothColor = vec3(0.0);
+ vec4 smoothPosition = vec4(0.0);
+ for (int u = -2; u <= 2; u++) {
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 pointPosition = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0 - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0 + 3.0 * smoothness;
+ vec3 cellColor = hash_vec4_to_vec3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
}
- else if (feature == 2.0) { /* F3 */
- col = pa[2];
+ }
+ outDistance = smoothDistance;
+ outColor.xyz = smoothColor;
+ vec4 p = safe_divide(cellPosition + smoothPosition, scale);
+ outPosition = p.xyz;
+ outW = p.w;
+}
+
+void node_tex_voronoi_f2_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vec4 offsetF1 = vec4(0.0);
+ vec4 positionF1 = vec4(0.0);
+ vec4 offsetF2, positionF2;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 pointPosition = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
}
- else if (feature == 3.0) { /* F4 */
- col = pa[3];
+ }
+ outDistance = distanceF2;
+ outColor.xyz = hash_vec4_to_vec3(cellPosition + offsetF2);
+ vec4 p = safe_divide(positionF2 + cellPosition, scale);
+ outPosition = p.xyz;
+ outW = p.w;
+}
+
+void node_tex_voronoi_distance_to_edge_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ vec4 vectorToClosest;
+ float minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 vectorToPoint = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 vectorToPoint = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness -
+ localPosition;
+ vec4 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
}
- else if (feature == 4.0) { /* F2F1 */
- col = abs(pa[1] - pa[0]);
+ }
+ outDistance = minDistance;
+}
+
+void node_tex_voronoi_n_sphere_radius_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float randomness,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ randomness = clamp(randomness, 0.0, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ vec4 closestPoint;
+ vec4 closestPointOffset;
+ float minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 pointPosition = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
}
+ }
- color = vec4(cellnoise_color(col), 1.0);
- fac = (color.x + color.y + color.z) * (1.0 / 3.0);
+ minDistance = 8.0;
+ vec4 closestPointToClosestPoint;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0 && u == 0) {
+ continue;
+ }
+ vec4 cellOffset = vec4(i, j, k, u) + closestPointOffset;
+ vec4 pointPosition = cellOffset +
+ hash_vec4_to_vec4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
}
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
}
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index b4e12484bdc..6b46c5887b4 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -876,10 +876,10 @@ typedef struct NodeTexNoise {
typedef struct NodeTexVoronoi {
NodeTexBase base;
- int coloring;
- int distance;
+ int dimensions;
int feature;
- char _pad[4];
+ int distance;
+ int coloring DNA_DEPRECATED;
} NodeTexVoronoi;
typedef struct NodeTexMusgrave {
@@ -1098,20 +1098,22 @@ typedef struct NodeDenoise {
#define SHD_NOISE_SOFT 0
#define SHD_NOISE_HARD 1
-/* voronoi texture */
-#define SHD_VORONOI_DISTANCE 0
-#define SHD_VORONOI_MANHATTAN 1
-#define SHD_VORONOI_CHEBYCHEV 2
-#define SHD_VORONOI_MINKOWSKI 3
+/* Voronoi Texture */
-#define SHD_VORONOI_INTENSITY 0
-#define SHD_VORONOI_CELLS 1
+enum {
+ SHD_VORONOI_EUCLIDEAN = 0,
+ SHD_VORONOI_MANHATTAN = 1,
+ SHD_VORONOI_CHEBYCHEV = 2,
+ SHD_VORONOI_MINKOWSKI = 3,
+};
-#define SHD_VORONOI_F1 0
-#define SHD_VORONOI_F2 1
-#define SHD_VORONOI_F3 2
-#define SHD_VORONOI_F4 3
-#define SHD_VORONOI_F2F1 4
+enum {
+ SHD_VORONOI_F1 = 0,
+ SHD_VORONOI_F2 = 1,
+ SHD_VORONOI_SMOOTH_F1 = 2,
+ SHD_VORONOI_DISTANCE_TO_EDGE = 3,
+ SHD_VORONOI_N_SPHERE_RADIUS = 4,
+};
/* musgrave texture */
#define SHD_MUSGRAVE_MULTIFRACTAL 0
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index c2c937a75f8..3d90d566315 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -4404,25 +4404,39 @@ static void def_sh_tex_musgrave(StructRNA *srna)
static void def_sh_tex_voronoi(StructRNA *srna)
{
- static const EnumPropertyItem prop_coloring_items[] = {
- {SHD_VORONOI_INTENSITY, "INTENSITY", 0, "Intensity", "Only calculate intensity"},
- {SHD_VORONOI_CELLS, "CELLS", 0, "Cells", "Color cells by position"},
- {0, NULL, 0, NULL, NULL},
- };
-
static EnumPropertyItem prop_distance_items[] = {
- {SHD_VORONOI_DISTANCE, "DISTANCE", 0, "Distance", "Distance"},
- {SHD_VORONOI_MANHATTAN, "MANHATTAN", 0, "Manhattan", "Manhattan (city block) distance"},
+ {SHD_VORONOI_EUCLIDEAN, "EUCLIDEAN", 0, "Euclidean", "Euclidean distance"},
+ {SHD_VORONOI_MANHATTAN, "MANHATTAN", 0, "Manhattan", "Manhattan distance"},
{SHD_VORONOI_CHEBYCHEV, "CHEBYCHEV", 0, "Chebychev", "Chebychev distance"},
{SHD_VORONOI_MINKOWSKI, "MINKOWSKI", 0, "Minkowski", "Minkowski distance"},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem prop_feature_items[] = {
- {SHD_VORONOI_F1, "F1", 0, "Closest", "Closest point"},
- {SHD_VORONOI_F2, "F2", 0, "2nd Closest", "2nd closest point"},
- {SHD_VORONOI_F3, "F3", 0, "3rd Closest", "3rd closest point"},
- {SHD_VORONOI_F4, "F4", 0, "4th Closest", "4th closest point"},
- {SHD_VORONOI_F2F1, "F2F1", 0, "Crackle", "Difference between 2nd and 1st closest point"},
+ {SHD_VORONOI_F1,
+ "F1",
+ 0,
+ "F1",
+ "Computes the distance to the closest point as well as its position and color"},
+ {SHD_VORONOI_F2,
+ "F2",
+ 0,
+ "F2",
+ "Computes the distance to the second closest point as well as its position and color"},
+ {SHD_VORONOI_SMOOTH_F1,
+ "SMOOTH_F1",
+ 0,
+ "Smooth F1",
+ "Smoothed version of F1. Weighted sum of neighbour voronoi cells"},
+ {SHD_VORONOI_DISTANCE_TO_EDGE,
+ "DISTANCE_TO_EDGE",
+ 0,
+ "Distance To Edge",
+ "Computes the distance to the edge of the vornoi cell"},
+ {SHD_VORONOI_N_SPHERE_RADIUS,
+ "N_SPHERE_RADIUS",
+ 0,
+ "N-Sphere Radius",
+ "Computes the radius of the n-sphere inscribed in the voronoi cell"},
{0, NULL, 0, NULL, NULL}};
PropertyRNA *prop;
@@ -4430,11 +4444,11 @@ static void def_sh_tex_voronoi(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "NodeTexVoronoi", "storage");
def_sh_tex(srna);
- prop = RNA_def_property(srna, "coloring", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "coloring");
- RNA_def_property_enum_items(prop, prop_coloring_items);
- RNA_def_property_ui_text(prop, "Coloring", "");
- RNA_def_property_update(prop, 0, "rna_Node_update");
+ prop = RNA_def_property(srna, "voronoi_dimensions", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "dimensions");
+ RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
+ RNA_def_property_ui_text(prop, "Dimensions", "");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "distance", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "distance");
@@ -4446,7 +4460,7 @@ static void def_sh_tex_voronoi(StructRNA *srna)
RNA_def_property_enum_sdna(prop, NULL, "feature");
RNA_def_property_enum_items(prop, prop_feature_items);
RNA_def_property_ui_text(prop, "Feature Output", "");
- RNA_def_property_update(prop, 0, "rna_Node_update");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
}
static void def_sh_tex_wave(StructRNA *srna)
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
index 7000a8a6dae..adcb93d7775 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
@@ -23,12 +23,26 @@
static bNodeSocketTemplate sh_node_tex_voronoi_in[] = {
{SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {SOCK_FLOAT, 1, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
+ {SOCK_FLOAT, 1, N_("Smoothness"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{SOCK_FLOAT, 1, N_("Exponent"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 32.0f},
+ {SOCK_FLOAT, 1, N_("Randomness"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{-1, 0, ""},
};
static bNodeSocketTemplate sh_node_tex_voronoi_out[] = {
+ {SOCK_FLOAT,
+ 0,
+ N_("Distance"),
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ PROP_NONE,
+ SOCK_NO_INTERNAL_LINK},
{SOCK_RGBA,
0,
N_("Color"),
@@ -40,16 +54,28 @@ static bNodeSocketTemplate sh_node_tex_voronoi_out[] = {
1.0f,
PROP_NONE,
SOCK_NO_INTERNAL_LINK},
+ {SOCK_VECTOR,
+ 0,
+ N_("Position"),
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ PROP_NONE,
+ SOCK_NO_INTERNAL_LINK},
+ {SOCK_FLOAT, 0, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
{SOCK_FLOAT,
0,
- N_("Fac"),
+ N_("Radius"),
0.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
- PROP_FACTOR,
+ PROP_NONE,
SOCK_NO_INTERNAL_LINK},
{-1, 0, ""},
};
@@ -59,8 +85,8 @@ static void node_shader_init_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
NodeTexVoronoi *tex = MEM_callocN(sizeof(NodeTexVoronoi), "NodeTexVoronoi");
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
- tex->coloring = SHD_VORONOI_INTENSITY;
- tex->distance = SHD_VORONOI_DISTANCE;
+ tex->dimensions = 3;
+ tex->distance = SHD_VORONOI_EUCLIDEAN;
tex->feature = SHD_VORONOI_F1;
node->storage = tex;
@@ -75,39 +101,96 @@ static int node_shader_gpu_tex_voronoi(GPUMaterial *mat,
node_shader_gpu_default_tex_coord(mat, node, &in[0].link);
node_shader_gpu_tex_mapping(mat, node, in, out);
+ static const char *names[][5] = {
+ [SHD_VORONOI_F1] =
+ {
+ "",
+ "node_tex_voronoi_f1_1d",
+ "node_tex_voronoi_f1_2d",
+ "node_tex_voronoi_f1_3d",
+ "node_tex_voronoi_f1_4d",
+ },
+ [SHD_VORONOI_F2] =
+ {
+ "",
+ "node_tex_voronoi_f2_1d",
+ "node_tex_voronoi_f2_2d",
+ "node_tex_voronoi_f2_3d",
+ "node_tex_voronoi_f2_4d",
+ },
+ [SHD_VORONOI_SMOOTH_F1] =
+ {
+ "",
+ "node_tex_voronoi_smooth_f1_1d",
+ "node_tex_voronoi_smooth_f1_2d",
+ "node_tex_voronoi_smooth_f1_3d",
+ "node_tex_voronoi_smooth_f1_4d",
+ },
+ [SHD_VORONOI_DISTANCE_TO_EDGE] =
+ {
+ "",
+ "node_tex_voronoi_distance_to_edge_1d",
+ "node_tex_voronoi_distance_to_edge_2d",
+ "node_tex_voronoi_distance_to_edge_3d",
+ "node_tex_voronoi_distance_to_edge_4d",
+ },
+ [SHD_VORONOI_N_SPHERE_RADIUS] =
+ {
+ "",
+ "node_tex_voronoi_n_sphere_radius_1d",
+ "node_tex_voronoi_n_sphere_radius_2d",
+ "node_tex_voronoi_n_sphere_radius_3d",
+ "node_tex_voronoi_n_sphere_radius_4d",
+ },
+ };
+
NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
- float coloring = tex->coloring;
float metric = tex->distance;
- float feature = tex->feature;
-
- return GPU_stack_link(mat,
- node,
- "node_tex_voronoi",
- in,
- out,
- GPU_constant(&coloring),
- GPU_constant(&metric),
- GPU_constant(&feature));
+
+ BLI_assert(tex->feature >= 0 && tex->feature < 5);
+ BLI_assert(tex->dimensions > 0 && tex->dimensions < 5);
+
+ return GPU_stack_link(
+ mat, node, names[tex->feature][tex->dimensions], in, out, GPU_constant(&metric));
}
static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
{
+ bNodeSocket *inVectorSock = nodeFindSocket(node, SOCK_IN, "Vector");
+ bNodeSocket *inWSock = nodeFindSocket(node, SOCK_IN, "W");
+ bNodeSocket *inSmoothnessSock = nodeFindSocket(node, SOCK_IN, "Smoothness");
+ bNodeSocket *inExponentSock = nodeFindSocket(node, SOCK_IN, "Exponent");
+
+ bNodeSocket *outDistanceSock = nodeFindSocket(node, SOCK_OUT, "Distance");
+ bNodeSocket *outColorSock = nodeFindSocket(node, SOCK_OUT, "Color");
+ bNodeSocket *outPositionSock = nodeFindSocket(node, SOCK_OUT, "Position");
+ bNodeSocket *outWSock = nodeFindSocket(node, SOCK_OUT, "W");
+ bNodeSocket *outRadiusSock = nodeFindSocket(node, SOCK_OUT, "Radius");
+
NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
- bNodeSocket *sock;
-
- for (sock = node->inputs.first; sock; sock = sock->next) {
- if (STREQ(sock->name, "Exponent")) {
- if (tex->distance == SHD_VORONOI_MINKOWSKI) {
- sock->flag &= ~SOCK_UNAVAIL;
- }
- else {
- sock->flag |= SOCK_UNAVAIL;
- }
- }
- }
+
+ nodeSetSocketAvailability(inWSock, tex->dimensions == 1 || tex->dimensions == 4);
+ nodeSetSocketAvailability(inVectorSock, tex->dimensions != 1);
+ nodeSetSocketAvailability(
+ inExponentSock,
+ 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 &&
+ tex->feature != SHD_VORONOI_N_SPHERE_RADIUS);
+ nodeSetSocketAvailability(outPositionSock,
+ tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ tex->feature != SHD_VORONOI_N_SPHERE_RADIUS &&
+ tex->dimensions != 1);
+ nodeSetSocketAvailability(outWSock,
+ tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ tex->feature != SHD_VORONOI_N_SPHERE_RADIUS &&
+ (tex->dimensions == 1 || tex->dimensions == 4));
+ nodeSetSocketAvailability(outRadiusSock, tex->feature == SHD_VORONOI_N_SPHERE_RADIUS);
}
-/* node type definition */
void register_node_type_sh_tex_voronoi(void)
{
static bNodeType ntype;