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
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
-rw-r--r--intern/cycles/blender/blender_shader.cpp4
-rw-r--r--intern/cycles/kernel/closure/bsdf_util.h14
-rw-r--r--intern/cycles/kernel/shaders/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/shaders/node_hash.h81
-rw-r--r--intern/cycles/kernel/shaders/node_voronoi_texture.osl1065
-rw-r--r--intern/cycles/kernel/svm/svm.h2
-rw-r--r--intern/cycles/kernel/svm/svm_noise.h24
-rw-r--r--intern/cycles/kernel/svm/svm_types.h15
-rw-r--r--intern/cycles/kernel/svm/svm_voronoi.h1217
-rw-r--r--intern/cycles/render/nodes.cpp104
-rw-r--r--intern/cycles/render/nodes.h4
-rw-r--r--intern/cycles/util/util_math.h15
-rw-r--r--intern/cycles/util/util_math_float2.h31
-rw-r--r--intern/cycles/util/util_math_float3.h12
-rw-r--r--intern/cycles/util/util_math_float4.h42
-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
26 files changed, 3779 insertions, 524 deletions
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index db01167cc2a..257c799a3e0 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -733,9 +733,9 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
VoronoiTextureNode *voronoi = new VoronoiTextureNode();
- voronoi->coloring = (NodeVoronoiColoring)b_voronoi_node.coloring();
- voronoi->metric = (NodeVoronoiDistanceMetric)b_voronoi_node.distance();
+ voronoi->dimensions = b_voronoi_node.voronoi_dimensions();
voronoi->feature = (NodeVoronoiFeature)b_voronoi_node.feature();
+ voronoi->metric = (NodeVoronoiDistanceMetric)b_voronoi_node.distance();
BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping());
get_tex_mapping(&voronoi->tex_mapping, b_texture_mapping);
node = voronoi;
diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h
index 3bce47caedb..a73dee1b045 100644
--- a/intern/cycles/kernel/closure/bsdf_util.h
+++ b/intern/cycles/kernel/closure/bsdf_util.h
@@ -134,20 +134,6 @@ ccl_device float schlick_fresnel(float u)
return m2 * m2 * m; // pow(m, 5)
}
-ccl_device float smooth_step(float edge0, float edge1, float x)
-{
- float result;
- if (x < edge0)
- result = 0.0f;
- else if (x >= edge1)
- result = 1.0f;
- else {
- float t = (x - edge0) / (edge1 - edge0);
- result = (3.0f - 2.0f * t) * (t * t);
- }
- return result;
-}
-
/* Calculate the fresnel color which is a blend between white and the F0 color (cspec0) */
ccl_device_forceinline float3
interpolate_fresnel_color(float3 L, float3 H, float ior, float F0, float3 cspec0)
diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt
index a45c43e01ed..38ba113a184 100644
--- a/intern/cycles/kernel/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/shaders/CMakeLists.txt
@@ -97,6 +97,7 @@ set(SRC_OSL
set(SRC_OSL_HEADERS
node_color.h
node_fresnel.h
+ node_hash.h
node_noise.h
node_ramp_util.h
stdosl.h
diff --git a/intern/cycles/kernel/shaders/node_hash.h b/intern/cycles/kernel/shaders/node_hash.h
new file mode 100644
index 00000000000..7affe432bf2
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_hash.h
@@ -0,0 +1,81 @@
+#include "stdosl.h"
+#include "vector2.h"
+#include "vector4.h"
+
+#define vector3 point
+
+/* **** Hash a float or vector[234] into a float [0, 1] **** */
+
+float hash_float_to_float(float k)
+{
+ return hashnoise(k);
+}
+
+float hash_vector2_to_float(vector2 k)
+{
+ return hashnoise(k.x, k.y);
+}
+
+float hash_vector3_to_float(vector3 k)
+{
+ return hashnoise(k);
+}
+
+float hash_vector4_to_float(vector4 k)
+{
+ return hashnoise(vector3(k.x, k.y, k.z), k.w);
+}
+
+/* **** Hash a vector[234] into a vector[234] [0, 1] **** */
+
+vector2 hash_vector2_to_vector2(vector2 k)
+{
+ return vector2(hash_vector2_to_float(k), hash_vector3_to_float(vector3(k.x, k.y, 1.0)));
+}
+
+vector3 hash_vector3_to_vector3(vector3 k)
+{
+ return vector3(hash_vector3_to_float(k),
+ hash_vector4_to_float(vector4(k[0], k[1], k[2], 1.0)),
+ hash_vector4_to_float(vector4(k[0], k[1], k[2], 2.0)));
+}
+
+vector4 hash_vector4_to_vector4(vector4 k)
+{
+ return vector4(hash_vector4_to_float(k),
+ hash_vector4_to_float(vector4(k.w, k.x, k.y, k.z)),
+ hash_vector4_to_float(vector4(k.z, k.w, k.x, k.y)),
+ hash_vector4_to_float(vector4(k.y, k.z, k.w, k.x)));
+}
+
+/* **** Hash a float or a vec[234] into a color [0, 1] **** */
+
+color hash_float_to_color(float k)
+{
+ return color(hash_float_to_float(k),
+ hash_vector2_to_float(vector2(k, 1.0)),
+ hash_vector2_to_float(vector2(k, 2.0)));
+}
+
+color hash_vector2_to_color(vector2 k)
+{
+ return color(hash_vector2_to_float(k),
+ hash_vector3_to_float(vector3(k.x, k.y, 1.0)),
+ hash_vector3_to_float(vector3(k.x, k.y, 2.0)));
+}
+
+color hash_vector3_to_color(vector3 k)
+{
+ return color(hash_vector3_to_float(k),
+ hash_vector4_to_float(vector4(k[0], k[1], k[2], 1.0)),
+ hash_vector4_to_float(vector4(k[0], k[1], k[2], 2.0)));
+}
+
+color hash_vector4_to_color(vector4 k)
+{
+ return color(hash_vector4_to_float(k),
+ hash_vector4_to_float(vector4(k.z, k.x, k.w, k.y)),
+ hash_vector4_to_float(vector4(k.w, k.z, k.y, k.x)));
+}
+
+#undef vector3
diff --git a/intern/cycles/kernel/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/shaders/node_voronoi_texture.osl
index 0d547b4b615..5de4aeef943 100644
--- a/intern/cycles/kernel/shaders/node_voronoi_texture.osl
+++ b/intern/cycles/kernel/shaders/node_voronoi_texture.osl
@@ -15,158 +15,1013 @@
*/
#include "stdosl.h"
+#include "vector2.h"
+#include "vector4.h"
+#include "node_hash.h"
-color cellnoise_color(point p)
+#define vector3 point
+
+/* **** Distance Functions **** */
+
+float distance(float a, float b)
+{
+ return abs(a - b);
+}
+
+float distance(vector2 a, vector2 b)
+{
+ return length(a - b);
+}
+
+float distance(vector4 a, vector4 b)
+{
+ return length(a - b);
+}
+
+/* **** Safe Division **** */
+
+vector2 safe_divide(vector2 a, float b)
+{
+ return vector2((b != 0.0) ? a.x / b : 0.0, (b != 0.0) ? a.y / b : 0.0);
+}
+
+vector4 safe_divide(vector4 a, float b)
{
- float r = cellnoise(p);
- float g = cellnoise(point(p[1], p[0], p[2]));
- float b = cellnoise(point(p[1], p[2], p[0]));
+ return vector4((b != 0.0) ? a.x / b : 0.0,
+ (b != 0.0) ? a.y / b : 0.0,
+ (b != 0.0) ? a.z / b : 0.0,
+ (b != 0.0) ? a.w / b : 0.0);
+}
+
+/*
+ * Smooth Voronoi:
+ *
+ * - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
+ *
+ * Distance To Edge:
+ *
+ * - https://www.shadertoy.com/view/llG3zy
+ *
+ */
- return color(r, g, b);
+/* **** 1D Voronoi **** */
+
+float voronoi_distance(float a, float b, string metric, float exponent)
+{
+ return abs(a - b);
}
-void voronoi_m(point p, string metric, float e, float da[4], point pa[4])
+void voronoi_f1_1d(float w,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output float outW)
{
- /* Compute the distance to and the position of the four closest neighbors to p.
- *
- * The neighbors are randomly placed, 1 each in a 3x3x3 grid (Worley pattern).
- * The distances and points are returned in ascending order, i.e. da[0] and pa[0] will
- * contain the distance to the closest point and its coordinates respectively.
- */
- int xx, yy, zz, xi, yi, zi;
+ float cellPosition = floor(w);
+ float localPosition = w - cellPosition;
- xi = (int)floor(p[0]);
- yi = (int)floor(p[1]);
- zi = (int)floor(p[2]);
+ 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 = hash_float_to_color(cellPosition + targetOffset);
+ outW = targetPosition + cellPosition;
+}
- da[0] = 1e10;
- da[1] = 1e10;
- da[2] = 1e10;
- da[3] = 1e10;
+void voronoi_smooth_f1_1d(float w,
+ float smoothness,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output float outW)
+{
+ float cellPosition = floor(w);
+ float localPosition = w - cellPosition;
- for (xx = xi - 1; xx <= xi + 1; xx++) {
- for (yy = yi - 1; yy <= yi + 1; yy++) {
- for (zz = zi - 1; zz <= zi + 1; zz++) {
- point ip = point(xx, yy, zz);
- point vp = (point)cellnoise_color(ip);
- point pd = p - (vp + ip);
+ float smoothDistance = 8.0;
+ float smoothPosition = 0.0;
+ color smoothColor = color(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;
+ color cellColor = hash_float_to_color(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ outDistance = smoothDistance;
+ outColor = smoothColor;
+ outW = cellPosition + smoothPosition;
+}
+
+void voronoi_f2_1d(float w,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output float outW)
+{
+ float cellPosition = floor(w);
+ float localPosition = w - 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 = hash_float_to_color(cellPosition + offsetF2);
+ outW = positionF2 + cellPosition;
+}
+
+void voronoi_distance_to_edge_1d(float w, float randomness, output float outDistance)
+{
+ float cellPosition = floor(w);
+ float localPosition = w - 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 = distance(pointPosition, localPosition);
+ minDistance = min(distanceToPoint, minDistance);
+ }
+ outDistance = minDistance;
+}
+
+void voronoi_n_sphere_radius_1d(float w, float randomness, output float outRadius)
+{
+ float cellPosition = floor(w);
+ float localPosition = w - 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(vector2 a, vector2 b, string metric, float exponent)
+{
+ if (metric == "euclidean") {
+ return distance(a, b);
+ }
+ else if (metric == "manhattan") {
+ return abs(a.x - b.x) + abs(a.y - b.y);
+ }
+ else if (metric == "chebychev") {
+ return max(abs(a.x - b.x), abs(a.y - b.y));
+ }
+ else if (metric == "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 voronoi_f1_2d(vector2 coord,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector2 outPosition)
+{
+ vector2 cellPosition = floor(coord);
+ vector2 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0;
+ vector2 targetOffset, targetPosition;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 pointPosition = cellOffset +
+ hash_vector2_to_vector2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor = hash_vector2_to_color(cellPosition + targetOffset);
+ outPosition = targetPosition + cellPosition;
+}
+
+void voronoi_smooth_f1_2d(vector2 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector2 outPosition)
+{
+ vector2 cellPosition = floor(coord);
+ vector2 localPosition = coord - cellPosition;
+
+ float smoothDistance = 8.0;
+ color smoothColor = color(0.0);
+ vector2 smoothPosition = vector2(0.0, 0.0);
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 pointPosition = cellOffset +
+ hash_vector2_to_vector2(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;
+ color cellColor = hash_vector2_to_color(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ outDistance = smoothDistance;
+ outColor = smoothColor;
+ outPosition = cellPosition + smoothPosition;
+}
+
+void voronoi_f2_2d(vector2 coord,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector2 outPosition)
+{
+ vector2 cellPosition = floor(coord);
+ vector2 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vector2 offsetF1 = vector2(0.0, 0.0);
+ vector2 positionF1 = vector2(0.0, 0.0);
+ vector2 offsetF2, positionF2;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 pointPosition = cellOffset +
+ hash_vector2_to_vector2(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 = hash_vector2_to_color(cellPosition + offsetF2);
+ outPosition = positionF2 + cellPosition;
+}
+
+void voronoi_distance_to_edge_2d(vector2 coord, float randomness, output float outDistance)
+{
+ vector2 cellPosition = floor(coord);
+ vector2 localPosition = coord - cellPosition;
+
+ vector2 vectorToClosest;
+ float minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 vectorToPoint = cellOffset +
+ hash_vector2_to_vector2(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++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 vectorToPoint = cellOffset +
+ hash_vector2_to_vector2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ vector2 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 voronoi_n_sphere_radius_2d(vector2 coord, float randomness, output float outRadius)
+{
+ vector2 cellPosition = floor(coord);
+ vector2 localPosition = coord - cellPosition;
+
+ vector2 closestPoint;
+ vector2 closestPointOffset;
+ float minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 pointPosition = cellOffset +
+ hash_vector2_to_vector2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ vector2 closestPointToClosestPoint;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0) {
+ continue;
+ }
+ vector2 cellOffset = vector2(i, j) + closestPointOffset;
+ vector2 pointPosition = cellOffset +
+ hash_vector2_to_vector2(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(vector3 a, vector3 b, string metric, float exponent)
+{
+ if (metric == "euclidean") {
+ return distance(a, b);
+ }
+ else if (metric == "manhattan") {
+ return abs(a[0] - b[0]) + abs(a[1] - b[1]) + abs(a[2] - b[2]);
+ }
+ else if (metric == "chebychev") {
+ return max(abs(a[0] - b[0]), max(abs(a[1] - b[1]), abs(a[2] - b[2])));
+ }
+ else if (metric == "minkowski") {
+ return pow(pow(abs(a[0] - b[0]), exponent) + pow(abs(a[1] - b[1]), exponent) +
+ pow(abs(a[2] - b[2]), exponent),
+ 1.0 / exponent);
+ }
+ else {
+ return 0.0;
+ }
+}
- float d = 0.0;
- if (metric == "distance") {
- d = dot(pd, pd);
+void voronoi_f1_3d(vector3 coord,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector3 outPosition)
+{
+ vector3 cellPosition = floor(coord);
+ vector3 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0;
+ vector3 targetOffset, targetPosition;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 pointPosition = cellOffset +
+ hash_vector3_to_vector3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor = hash_vector3_to_color(cellPosition + targetOffset);
+ outPosition = targetPosition + cellPosition;
+}
+
+void voronoi_smooth_f1_3d(vector3 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector3 outPosition)
+{
+ vector3 cellPosition = floor(coord);
+ vector3 localPosition = coord - cellPosition;
+
+ float smoothDistance = 8.0;
+ color smoothColor = color(0.0);
+ vector3 smoothPosition = vector3(0.0);
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 pointPosition = cellOffset +
+ hash_vector3_to_vector3(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;
+ color cellColor = hash_vector3_to_color(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
+ outDistance = smoothDistance;
+ outColor = smoothColor;
+ outPosition = cellPosition + smoothPosition;
+}
+
+void voronoi_f2_3d(vector3 coord,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector3 outPosition)
+{
+ vector3 cellPosition = floor(coord);
+ vector3 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vector3 offsetF1 = vector3(0.0);
+ vector3 positionF1 = vector3(0.0);
+ vector3 offsetF2, positionF2;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 pointPosition = cellOffset +
+ hash_vector3_to_vector3(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 = hash_vector3_to_color(cellPosition + offsetF2);
+ outPosition = positionF2 + cellPosition;
+}
+
+void voronoi_distance_to_edge_3d(vector3 coord, float randomness, output float outDistance)
+{
+ vector3 cellPosition = floor(coord);
+ vector3 localPosition = coord - cellPosition;
+
+ vector3 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++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 vectorToPoint = cellOffset +
+ hash_vector3_to_vector3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 vectorToPoint = cellOffset +
+ hash_vector3_to_vector3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ vector3 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
}
- else if (metric == "manhattan") {
- d = fabs(pd[0]) + fabs(pd[1]) + fabs(pd[2]);
+ }
+ }
+ }
+ outDistance = minDistance;
+}
+
+void voronoi_n_sphere_radius_3d(vector3 coord, float randomness, output float outRadius)
+{
+ vector3 cellPosition = floor(coord);
+ vector3 localPosition = coord - cellPosition;
+
+ vector3 closestPoint;
+ vector3 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++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 pointPosition = cellOffset +
+ hash_vector3_to_vector3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
}
- else if (metric == "chebychev") {
- d = max(fabs(pd[0]), max(fabs(pd[1]), fabs(pd[2])));
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ vector3 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;
}
- else if (metric == "minkowski") {
- d = pow(pow(fabs(pd[0]), e) + pow(fabs(pd[1]), e) + pow(fabs(pd[2]), e), 1.0 / e);
+ vector3 cellOffset = vector3(i, j, k) + closestPointOffset;
+ vector3 pointPosition = cellOffset +
+ hash_vector3_to_vector3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
}
+ }
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 4D Voronoi **** */
+
+float voronoi_distance(vector4 a, vector4 b, string metric, float exponent)
+{
+ if (metric == "euclidean") {
+ return distance(a, b);
+ }
+ else if (metric == "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 == "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 == "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 {
+ return 0.0;
+ }
+}
+
+void voronoi_f1_4d(vector4 coord,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector4 outPosition)
+{
+ vector4 cellPosition = floor(coord);
+ vector4 localPosition = coord - cellPosition;
- vp += point(xx, yy, zz);
+ float minDistance = 8.0;
+ vector4 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++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 pointPosition = cellOffset +
+ hash_vector4_to_vector4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor = hash_vector4_to_color(cellPosition + targetOffset);
+ outPosition = targetPosition + cellPosition;
+}
- if (d < da[0]) {
- da[3] = da[2];
- da[2] = da[1];
- da[1] = da[0];
- da[0] = d;
+void voronoi_smooth_f1_4d(vector4 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector4 outPosition)
+{
+ vector4 cellPosition = floor(coord);
+ vector4 localPosition = coord - cellPosition;
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = pa[0];
- pa[0] = vp;
+ float smoothDistance = 8.0;
+ color smoothColor = color(0.0);
+ vector4 smoothPosition = vector4(0.0, 0.0, 0.0, 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++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 pointPosition = cellOffset +
+ hash_vector4_to_vector4(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;
+ color cellColor = hash_vector4_to_color(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
}
- else if (d < da[1]) {
- da[3] = da[2];
- da[2] = da[1];
- da[1] = d;
-
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = vp;
+ }
+ }
+ }
+ outDistance = smoothDistance;
+ outColor = smoothColor;
+ outPosition = cellPosition + smoothPosition;
+}
+
+void voronoi_f2_4d(vector4 coord,
+ float exponent,
+ float randomness,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector4 outPosition)
+{
+ vector4 cellPosition = floor(coord);
+ vector4 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vector4 offsetF1 = vector4(0.0, 0.0, 0.0, 0.0);
+ vector4 positionF1 = vector4(0.0, 0.0, 0.0, 0.0);
+ vector4 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++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 pointPosition = cellOffset +
+ hash_vector4_to_vector4(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 (d < da[2]) {
- da[3] = da[2];
- da[2] = d;
+ }
+ }
+ }
+ outDistance = distanceF2;
+ outColor = hash_vector4_to_color(cellPosition + offsetF2);
+ outPosition = positionF2 + cellPosition;
+}
+
+void voronoi_distance_to_edge_4d(vector4 coord, float randomness, output float outDistance)
+{
+ vector4 cellPosition = floor(coord);
+ vector4 localPosition = coord - cellPosition;
- pa[3] = pa[2];
- pa[2] = vp;
+ vector4 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++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 vectorToPoint = cellOffset +
+ hash_vector4_to_vector4(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
}
- else if (d < da[3]) {
- da[3] = d;
- pa[3] = vp;
+ }
+ }
+ }
+
+ 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++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 vectorToPoint = cellOffset +
+ hash_vector4_to_vector4(cellPosition + cellOffset) * randomness -
+ localPosition;
+ vector4 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
}
}
}
}
+ outDistance = minDistance;
}
-/* Voronoi */
+void voronoi_n_sphere_radius_4d(vector4 coord, float randomness, output float outRadius)
+{
+ vector4 cellPosition = floor(coord);
+ vector4 localPosition = coord - cellPosition;
+
+ vector4 closestPoint;
+ vector4 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++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 pointPosition = cellOffset +
+ hash_vector4_to_vector4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ vector4 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;
+ }
+ vector4 cellOffset = vector4(i, j, k, u) + closestPointOffset;
+ vector4 pointPosition = cellOffset +
+ hash_vector4_to_vector4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
shader node_voronoi_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- string coloring = "intensity",
- string metric = "distance",
- string feature = "F1",
- float Exponent = 1.0,
+ string dimensions = "3D",
+ string feature = "f1",
+ string metric = "euclidean",
+ vector3 Vector = P,
+ float WIn = 0.0,
float Scale = 5.0,
- point Vector = P,
- output float Fac = 0.0,
- output color Color = 0.0)
+ float Smoothness = 5.0,
+ float Exponent = 1.0,
+ float Randomness = 1.0,
+ output float Distance = 0.0,
+ output color Color = 0.0,
+ output vector3 Position = P,
+ output float WOut = 0.0,
+ output float Radius = 0.0)
{
- point p = Vector;
+ float randomness = clamp(Randomness, 0.0, 1.0);
+ float smoothness = clamp(Smoothness / 2.0, 0.0, 0.5);
+ vector3 coord = Vector;
if (use_mapping)
- p = transform(mapping, p);
+ coord = transform(mapping, coord);
- /* compute distance and point coordinate of 4 nearest neighbours */
- float da[4];
- point pa[4];
+ float w = WIn * Scale;
+ coord *= Scale;
- /* compute distance and point coordinate of 4 nearest neighbours */
- voronoi_m(p * Scale, metric, Exponent, da, pa);
-
- if (coloring == "intensity") {
- /* Intensity output */
- if (feature == "F1") {
- Fac = fabs(da[0]);
+ if (dimensions == "1D") {
+ if (feature == "f1") {
+ voronoi_f1_1d(w, Exponent, randomness, metric, Distance, Color, WOut);
+ }
+ else if (feature == "smooth_f1") {
+ voronoi_smooth_f1_1d(w, smoothness, Exponent, randomness, metric, Distance, Color, WOut);
}
- else if (feature == "F2") {
- Fac = fabs(da[1]);
+ else if (feature == "f2") {
+ voronoi_f2_1d(w, Exponent, randomness, metric, Distance, Color, WOut);
}
- else if (feature == "F3") {
- Fac = fabs(da[2]);
+ else if (feature == "distance_to_edge") {
+ voronoi_distance_to_edge_1d(w, randomness, Distance);
}
- else if (feature == "F4") {
- Fac = fabs(da[3]);
+ else if (feature == "n_sphere_radius") {
+ voronoi_n_sphere_radius_1d(w, randomness, Radius);
}
- else if (feature == "F2F1") {
- Fac = fabs(da[1] - da[0]);
+ else {
+ error("Unknown feature!");
}
- Color = color(Fac);
+ WOut = (Scale != 0.0) ? WOut / Scale : 0.0;
}
- else {
- /* Color output */
- if (feature == "F1") {
- Color = pa[0];
+ else if (dimensions == "2D") {
+ vector2 coord2D = vector2(coord[0], coord[1]);
+ vector2 outPosition2D;
+ if (feature == "f1") {
+ voronoi_f1_2d(coord2D, Exponent, randomness, metric, Distance, Color, outPosition2D);
}
- else if (feature == "F2") {
- Color = pa[1];
+ else if (feature == "smooth_f1") {
+ voronoi_smooth_f1_2d(
+ coord2D, smoothness, Exponent, randomness, metric, Distance, Color, outPosition2D);
}
- else if (feature == "F3") {
- Color = pa[2];
+ else if (feature == "f2") {
+ voronoi_f2_2d(coord2D, Exponent, randomness, metric, Distance, Color, outPosition2D);
}
- else if (feature == "F4") {
- Color = pa[3];
+ else if (feature == "distance_to_edge") {
+ voronoi_distance_to_edge_2d(coord2D, randomness, Distance);
}
- else if (feature == "F2F1") {
- Color = fabs(pa[1] - pa[0]);
+ else if (feature == "n_sphere_radius") {
+ voronoi_n_sphere_radius_2d(coord2D, randomness, Radius);
}
-
- Color = cellnoise_color(Color);
- Fac = (Color[0] + Color[1] + Color[2]) * (1.0 / 3.0);
+ else {
+ error("Unknown feature!");
+ }
+ outPosition2D = safe_divide(outPosition2D, Scale);
+ Position = vector3(outPosition2D.x, outPosition2D.y, 0.0);
+ }
+ else if (dimensions == "3D") {
+ if (feature == "f1") {
+ voronoi_f1_3d(coord, Exponent, randomness, metric, Distance, Color, Position);
+ }
+ else if (feature == "smooth_f1") {
+ voronoi_smooth_f1_3d(
+ coord, smoothness, Exponent, randomness, metric, Distance, Color, Position);
+ }
+ else if (feature == "f2") {
+ voronoi_f2_3d(coord, Exponent, randomness, metric, Distance, Color, Position);
+ }
+ else if (feature == "distance_to_edge") {
+ voronoi_distance_to_edge_3d(coord, randomness, Distance);
+ }
+ else if (feature == "n_sphere_radius") {
+ voronoi_n_sphere_radius_3d(coord, randomness, Radius);
+ }
+ else {
+ error("Unknown feature!");
+ }
+ Position = (Scale != 0.0) ? Position / Scale : vector3(0.0);
+ }
+ else if (dimensions == "4D") {
+ vector4 coord4D = vector4(coord[0], coord[1], coord[2], w);
+ vector4 outPosition4D;
+ if (feature == "f1") {
+ voronoi_f1_4d(coord4D, Exponent, randomness, metric, Distance, Color, outPosition4D);
+ }
+ else if (feature == "smooth_f1") {
+ voronoi_smooth_f1_4d(
+ coord4D, smoothness, Exponent, randomness, metric, Distance, Color, outPosition4D);
+ }
+ else if (feature == "f2") {
+ voronoi_f2_4d(coord4D, Exponent, randomness, metric, Distance, Color, outPosition4D);
+ }
+ else if (feature == "distance_to_edge") {
+ voronoi_distance_to_edge_4d(coord4D, randomness, Distance);
+ }
+ else if (feature == "n_sphere_radius") {
+ voronoi_n_sphere_radius_4d(coord4D, randomness, Radius);
+ }
+ else {
+ error("Unknown feature!");
+ }
+ outPosition4D = safe_divide(outPosition4D, Scale);
+ Position = vector3(outPosition4D.x, outPosition4D.y, outPosition4D.z);
+ WOut = outPosition4D.w;
+ }
+ else {
+ error("Unknown dimension!");
}
}
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index a192930937f..8de66a04963 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -429,7 +429,7 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
svm_node_tex_gradient(sd, stack, node);
break;
case NODE_TEX_VORONOI:
- svm_node_tex_voronoi(kg, sd, stack, node, &offset);
+ svm_node_tex_voronoi(kg, sd, stack, node.y, node.z, node.w, &offset);
break;
case NODE_TEX_MUSGRAVE:
svm_node_tex_musgrave(kg, sd, stack, node.y, node.z, node.w, &offset);
diff --git a/intern/cycles/kernel/svm/svm_noise.h b/intern/cycles/kernel/svm/svm_noise.h
index 8d832247b18..b67c1e9cb7e 100644
--- a/intern/cycles/kernel/svm/svm_noise.h
+++ b/intern/cycles/kernel/svm/svm_noise.h
@@ -590,28 +590,4 @@ ccl_device_inline float noise_4d(float4 p)
return 0.5f * snoise_4d(p) + 0.5f;
}
-/* cell noise */
-ccl_device float cellnoise(float3 p)
-{
- int3 ip = quick_floor_to_int3(p);
- return hash_uint3_to_float(ip.x, ip.y, ip.z);
-}
-
-ccl_device float3 cellnoise3(float3 p)
-{
- int3 ip = quick_floor_to_int3(p);
-#ifndef __KERNEL_SSE__
- float r = hash_uint3_to_float(ip.x, ip.y, ip.z);
- float g = hash_uint3_to_float(ip.y, ip.x, ip.z);
- float b = hash_uint3_to_float(ip.y, ip.z, ip.x);
- return make_float3(r, g, b);
-#else
- ssei ip_yxz = shuffle<1, 0, 2, 3>(ssei(ip.m128));
- ssei ip_xyy = shuffle<0, 1, 1, 3>(ssei(ip.m128));
- ssei ip_zzx = shuffle<2, 2, 0, 3>(ssei(ip.m128));
- ssei bits = hash_ssei3(ip_xyy, ip_yxz, ip_zzx);
- return float3(uint32_to_float(bits) * ssef(1.0f / (float)0xFFFFFFFF));
-#endif
-}
-
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index de7114566b3..65e2dacedae 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -357,24 +357,19 @@ typedef enum NodeGradientType {
NODE_BLEND_SPHERICAL
} NodeGradientType;
-typedef enum NodeVoronoiColoring {
- NODE_VORONOI_INTENSITY,
- NODE_VORONOI_CELLS
-} NodeVoronoiColoring;
-
typedef enum NodeVoronoiDistanceMetric {
- NODE_VORONOI_DISTANCE,
+ NODE_VORONOI_EUCLIDEAN,
NODE_VORONOI_MANHATTAN,
NODE_VORONOI_CHEBYCHEV,
- NODE_VORONOI_MINKOWSKI
+ NODE_VORONOI_MINKOWSKI,
} NodeVoronoiDistanceMetric;
typedef enum NodeVoronoiFeature {
NODE_VORONOI_F1,
NODE_VORONOI_F2,
- NODE_VORONOI_F3,
- NODE_VORONOI_F4,
- NODE_VORONOI_F2F1
+ NODE_VORONOI_SMOOTH_F1,
+ NODE_VORONOI_DISTANCE_TO_EDGE,
+ NODE_VORONOI_N_SPHERE_RADIUS,
} NodeVoronoiFeature;
typedef enum NodeBlendWeightType {
diff --git a/intern/cycles/kernel/svm/svm_voronoi.h b/intern/cycles/kernel/svm/svm_voronoi.h
index 3d7fa523968..4a479d9bc71 100644
--- a/intern/cycles/kernel/svm/svm_voronoi.h
+++ b/intern/cycles/kernel/svm/svm_voronoi.h
@@ -16,170 +16,1101 @@
CCL_NAMESPACE_BEGIN
-/* Voronoi */
-
-ccl_device void voronoi_neighbors(
- float3 p, NodeVoronoiDistanceMetric distance, float e, float da[4], float3 pa[4])
-{
- /* Compute the distance to and the position of the closest neighbors to p.
- *
- * The neighbors are randomly placed, 1 each in a 3x3x3 grid (Worley pattern).
- * The distances and points are returned in ascending order, i.e. da[0] and pa[0] will
- * contain the distance to the closest point and its coordinates respectively.
- */
-
- da[0] = 1e10f;
- da[1] = 1e10f;
- da[2] = 1e10f;
- da[3] = 1e10f;
-
- pa[0] = make_float3(0.0f, 0.0f, 0.0f);
- pa[1] = make_float3(0.0f, 0.0f, 0.0f);
- pa[2] = make_float3(0.0f, 0.0f, 0.0f);
- pa[3] = make_float3(0.0f, 0.0f, 0.0f);
-
- int3 xyzi = quick_floor_to_int3(p);
-
- for (int xx = -1; xx <= 1; xx++) {
- for (int yy = -1; yy <= 1; yy++) {
- for (int zz = -1; zz <= 1; zz++) {
- int3 ip = xyzi + make_int3(xx, yy, zz);
- float3 fp = make_float3(ip.x, ip.y, ip.z);
- float3 vp = fp + cellnoise3(fp);
-
- float d;
- switch (distance) {
- case NODE_VORONOI_DISTANCE:
- d = len_squared(p - vp);
- break;
- case NODE_VORONOI_MANHATTAN:
- d = reduce_add(fabs(vp - p));
- break;
- case NODE_VORONOI_CHEBYCHEV:
- d = max3(fabs(vp - p));
- break;
- case NODE_VORONOI_MINKOWSKI: {
- float3 n = fabs(vp - p);
- if (e == 0.5f) {
- d = sqr(reduce_add(sqrt(n)));
- }
- else {
- d = powf(reduce_add(pow3(n, e)), 1.0f / e);
- }
- break;
- }
+/*
+ * Smooth Voronoi:
+ *
+ * - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
+ *
+ * Distance To Edge:
+ *
+ * - https://www.shadertoy.com/view/llG3zy
+ *
+ */
+
+/* **** 1D Voronoi **** */
+
+ccl_device float voronoi_distance_1d(float a,
+ float b,
+ NodeVoronoiDistanceMetric metric,
+ float exponent)
+{
+ return fabsf(b - a);
+}
+
+ccl_device void voronoi_f1_1d(float w,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float *outW)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float minDistance = 8.0f;
+ float targetOffset, targetPosition;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_1d(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ *outDistance = minDistance;
+ *outColor = hash_float_to_float3(cellPosition + targetOffset);
+ *outW = targetPosition + cellPosition;
+}
+
+ccl_device void voronoi_smooth_f1_1d(float w,
+ float smoothness,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float *outW)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float smoothDistance = 8.0f;
+ float smoothPosition = 0.0f;
+ float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
+ for (int i = -2; i <= 2; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_1d(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0f - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ *outDistance = smoothDistance;
+ *outColor = smoothColor;
+ *outW = cellPosition + smoothPosition;
+}
+
+ccl_device void voronoi_f2_1d(float w,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float *outW)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float offsetF1 = 0.0f;
+ float positionF1 = 0.0f;
+ float offsetF2, positionF2;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_1d(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 = hash_float_to_float3(cellPosition + offsetF2);
+ *outW = positionF2 + cellPosition;
+}
+
+ccl_device void voronoi_distance_to_edge_1d(float w, float randomness, float *outDistance)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float minDistance = 8.0f;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = fabsf(pointPosition - localPosition);
+ minDistance = min(distanceToPoint, minDistance);
+ }
+ *outDistance = minDistance;
+}
+
+ccl_device void voronoi_n_sphere_radius_1d(float w, float randomness, float *outRadius)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float closestPoint;
+ float closestPointOffset;
+ float minDistance = 8.0f;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = fabsf(pointPosition - localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+
+ minDistance = 8.0f;
+ float closestPointToClosestPoint;
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0) {
+ continue;
+ }
+ float cellOffset = i + closestPointOffset;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = fabsf(closestPoint - pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ *outRadius = fabsf(closestPointToClosestPoint - closestPoint) / 2.0f;
+}
+
+/* **** 2D Voronoi **** */
+
+ccl_device float voronoi_distance_2d(float2 a,
+ float2 b,
+ NodeVoronoiDistanceMetric metric,
+ float exponent)
+{
+ if (metric == NODE_VORONOI_EUCLIDEAN) {
+ return distance(a, b);
+ }
+ else if (metric == NODE_VORONOI_MANHATTAN) {
+ return fabsf(a.x - b.x) + fabsf(a.y - b.y);
+ }
+ else if (metric == NODE_VORONOI_CHEBYCHEV) {
+ return max(fabsf(a.x - b.x), fabsf(a.y - b.y));
+ }
+ else if (metric == NODE_VORONOI_MINKOWSKI) {
+ return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent),
+ 1.0f / exponent);
+ }
+ else {
+ return 0.0f;
+ }
+}
+
+ccl_device void voronoi_f1_2d(float2 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float2 *outPosition)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0f;
+ float2 targetOffset, targetPosition;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_2d(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ *outDistance = minDistance;
+ *outColor = hash_float2_to_float3(cellPosition + targetOffset);
+ *outPosition = targetPosition + cellPosition;
+}
+
+ccl_device void voronoi_smooth_f1_2d(float2 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float2 *outPosition)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float smoothDistance = 8.0f;
+ float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
+ float2 smoothPosition = make_float2(0.0f, 0.0f);
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_2d(pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0f - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ float3 cellColor = hash_float2_to_float3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ *outDistance = smoothDistance;
+ *outColor = smoothColor;
+ *outPosition = cellPosition + smoothPosition;
+}
+
+ccl_device void voronoi_f2_2d(float2 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float2 *outPosition)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float2 offsetF1 = make_float2(0.0f, 0.0f);
+ float2 positionF1 = make_float2(0.0f, 0.0f);
+ float2 offsetF2, positionF2;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_2d(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 = hash_float2_to_float3(cellPosition + offsetF2);
+ *outPosition = positionF2 + cellPosition;
+}
+
+ccl_device void voronoi_distance_to_edge_2d(float2 coord, float randomness, float *outDistance)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float2 vectorToClosest;
+ float minDistance = 8.0f;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 vectorToPoint = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 vectorToPoint = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float2 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ *outDistance = minDistance;
+}
+
+ccl_device void voronoi_n_sphere_radius_2d(float2 coord, float randomness, float *outRadius)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float2 closestPoint;
+ float2 closestPointOffset;
+ float minDistance = 8.0f;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ float2 closestPointToClosestPoint;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0) {
+ continue;
+ }
+ float2 cellOffset = make_float2(i, j) + closestPointOffset;
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ *outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+}
+
+/* **** 3D Voronoi **** */
+
+ccl_device float voronoi_distance_3d(float3 a,
+ float3 b,
+ NodeVoronoiDistanceMetric metric,
+ float exponent)
+{
+ if (metric == NODE_VORONOI_EUCLIDEAN) {
+ return distance(a, b);
+ }
+ else if (metric == NODE_VORONOI_MANHATTAN) {
+ return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z);
+ }
+ else if (metric == NODE_VORONOI_CHEBYCHEV) {
+ return max(fabsf(a.x - b.x), max(fabsf(a.y - b.y), fabsf(a.z - b.z)));
+ }
+ else if (metric == NODE_VORONOI_MINKOWSKI) {
+ return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent) +
+ powf(fabsf(a.z - b.z), exponent),
+ 1.0f / exponent);
+ }
+ else {
+ return 0.0f;
+ }
+}
+
+ccl_device void voronoi_f1_3d(float3 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float3 *outPosition)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0f;
+ float3 targetOffset, targetPosition;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_3d(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
}
+ }
+ }
+ }
+ *outDistance = minDistance;
+ *outColor = hash_float3_to_float3(cellPosition + targetOffset);
+ *outPosition = targetPosition + cellPosition;
+}
+
+ccl_device void voronoi_smooth_f1_3d(float3 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float3 *outPosition)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float smoothDistance = 8.0f;
+ float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
+ float3 smoothPosition = make_float3(0.0f, 0.0f, 0.0f);
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_3d(
+ pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0f - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ float3 cellColor = hash_float3_to_float3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
+ *outDistance = smoothDistance;
+ *outColor = smoothColor;
+ *outPosition = cellPosition + smoothPosition;
+}
- /* To keep the shortest four distances and associated points we have to keep them in sorted
- * order. */
- if (d < da[0]) {
- da[3] = da[2];
- da[2] = da[1];
- da[1] = da[0];
- da[0] = d;
-
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = pa[0];
- pa[0] = vp;
+ccl_device void voronoi_f2_3d(float3 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float3 *outPosition)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float3 offsetF1 = make_float3(0.0f, 0.0f, 0.0f);
+ float3 positionF1 = make_float3(0.0f, 0.0f, 0.0f);
+ float3 offsetF2, positionF2;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_3d(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
}
- else if (d < da[1]) {
- da[3] = da[2];
- da[2] = da[1];
- da[1] = d;
-
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = vp;
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
}
- else if (d < da[2]) {
- da[3] = da[2];
- da[2] = d;
+ }
+ }
+ }
+ *outDistance = distanceF2;
+ *outColor = hash_float3_to_float3(cellPosition + offsetF2);
+ *outPosition = positionF2 + cellPosition;
+}
- pa[3] = pa[2];
- pa[2] = vp;
+ccl_device void voronoi_distance_to_edge_3d(float3 coord, float randomness, float *outDistance)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float3 vectorToClosest;
+ float minDistance = 8.0f;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 vectorToPoint = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
}
- else if (d < da[3]) {
- da[3] = d;
- pa[3] = vp;
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 vectorToPoint = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float3 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
}
}
}
}
+ *outDistance = minDistance;
}
-ccl_device void svm_node_tex_voronoi(
- KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
+ccl_device void voronoi_n_sphere_radius_3d(float3 coord, float randomness, float *outRadius)
{
- uint4 node2 = read_node(kg, offset);
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
- uint co_offset, coloring, distance, feature;
- uint scale_offset, e_offset, fac_offset, color_offset;
+ float3 closestPoint;
+ float3 closestPointOffset;
+ float minDistance = 8.0f;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+ }
- svm_unpack_node_uchar4(node.y, &co_offset, &coloring, &distance, &feature);
- svm_unpack_node_uchar4(node.z, &scale_offset, &e_offset, &fac_offset, &color_offset);
+ minDistance = 8.0f;
+ float3 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;
+ }
+ float3 cellOffset = make_float3(i, j, k) + closestPointOffset;
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ *outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+}
+
+/* **** 4D Voronoi **** */
- float3 co = stack_load_float3(stack, co_offset);
- float scale = stack_load_float_default(stack, scale_offset, node2.x);
- float exponent = stack_load_float_default(stack, e_offset, node2.y);
+ccl_device float voronoi_distance_4d(float4 a,
+ float4 b,
+ NodeVoronoiDistanceMetric metric,
+ float exponent)
+{
+ if (metric == NODE_VORONOI_EUCLIDEAN) {
+ return distance(a, b);
+ }
+ else if (metric == NODE_VORONOI_MANHATTAN) {
+ return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z) + fabsf(a.w - b.w);
+ }
+ else if (metric == NODE_VORONOI_CHEBYCHEV) {
+ return max(fabsf(a.x - b.x), max(fabsf(a.y - b.y), max(fabsf(a.z - b.z), fabsf(a.w - b.w))));
+ }
+ else if (metric == NODE_VORONOI_MINKOWSKI) {
+ return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent) +
+ powf(fabsf(a.z - b.z), exponent) + powf(fabsf(a.w - b.w), exponent),
+ 1.0f / exponent);
+ }
+ else {
+ return 0.0f;
+ }
+}
- float dist[4];
- float3 neighbor[4];
- voronoi_neighbors(co * scale, (NodeVoronoiDistanceMetric)distance, exponent, dist, neighbor);
+ccl_device void voronoi_f1_4d(float4 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float4 *outPosition)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
- float3 color;
- float fac;
- if (coloring == NODE_VORONOI_INTENSITY) {
- switch (feature) {
- case NODE_VORONOI_F1:
- fac = dist[0];
- break;
- case NODE_VORONOI_F2:
- fac = dist[1];
- break;
- case NODE_VORONOI_F3:
- fac = dist[2];
- break;
- case NODE_VORONOI_F4:
- fac = dist[3];
- break;
- case NODE_VORONOI_F2F1:
- fac = dist[1] - dist[0];
- break;
+ float minDistance = 8.0f;
+ float4 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++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_4d(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
}
+ }
+ *outDistance = minDistance;
+ *outColor = hash_float4_to_float3(cellPosition + targetOffset);
+ *outPosition = targetPosition + cellPosition;
+}
+
+ccl_device void voronoi_smooth_f1_4d(float4 coord,
+ float smoothness,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float4 *outPosition)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
- color = make_float3(fac, fac, fac);
+ float smoothDistance = 8.0f;
+ float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
+ float4 smoothPosition = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ 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++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_4d(
+ pointPosition, localPosition, metric, exponent);
+ float h = smoothstep(
+ 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
+ float correctionFactor = smoothness * h * (1.0f - h);
+ smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
+ correctionFactor /= 1.0f + 3.0f * smoothness;
+ float3 cellColor = hash_float4_to_float3(cellPosition + cellOffset);
+ smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
+ smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
+ }
+ }
+ }
}
- else {
- /* NODE_VORONOI_CELLS */
- switch (feature) {
- case NODE_VORONOI_F1:
- color = neighbor[0];
- break;
- case NODE_VORONOI_F2:
- color = neighbor[1];
- break;
- case NODE_VORONOI_F3:
- color = neighbor[2];
- break;
- case NODE_VORONOI_F4:
- color = neighbor[3];
- break;
- /* Usefulness of this vector is questionable. Note F2 >= F1 but the
- * individual vector components might not be. */
- case NODE_VORONOI_F2F1:
- color = fabs(neighbor[1] - neighbor[0]);
- break;
- }
-
- color = cellnoise3(color);
- fac = average(color);
- }
-
- if (stack_valid(fac_offset))
- stack_store_float(stack, fac_offset, fac);
- if (stack_valid(color_offset))
- stack_store_float3(stack, color_offset, color);
+ *outDistance = smoothDistance;
+ *outColor = smoothColor;
+ *outPosition = cellPosition + smoothPosition;
+}
+
+ccl_device void voronoi_f2_4d(float4 coord,
+ float exponent,
+ float randomness,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float4 *outPosition)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float4 offsetF1 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 positionF1 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 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++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = voronoi_distance_4d(
+ 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 = hash_float4_to_float3(cellPosition + offsetF2);
+ *outPosition = positionF2 + cellPosition;
+}
+
+ccl_device void voronoi_distance_to_edge_4d(float4 coord, float randomness, float *outDistance)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
+
+ float4 vectorToClosest;
+ float minDistance = 8.0f;
+ 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++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 vectorToPoint = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ 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++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 vectorToPoint = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness -
+ localPosition;
+ float4 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ }
+ }
+ *outDistance = minDistance;
+}
+
+ccl_device void voronoi_n_sphere_radius_4d(float4 coord, float randomness, float *outRadius)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
+
+ float4 closestPoint;
+ float4 closestPointOffset;
+ float minDistance = 8.0f;
+ 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++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ float4 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;
+ }
+ float4 cellOffset = make_float4(i, j, k, u) + closestPointOffset;
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * randomness;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ *outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+}
+
+ccl_device void svm_node_tex_voronoi(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint dimensions,
+ uint feature,
+ uint metric,
+ int *offset)
+{
+ uint4 stack_offsets = read_node(kg, offset);
+ uint4 defaults = read_node(kg, offset);
+
+ uint coord_stack_offset, w_stack_offset, scale_stack_offset, smoothness_stack_offset;
+ uint exponent_stack_offset, randomness_stack_offset, distance_out_stack_offset,
+ color_out_stack_offset;
+ uint position_out_stack_offset, w_out_stack_offset, radius_out_stack_offset;
+
+ svm_unpack_node_uchar4(stack_offsets.x,
+ &coord_stack_offset,
+ &w_stack_offset,
+ &scale_stack_offset,
+ &smoothness_stack_offset);
+ svm_unpack_node_uchar4(stack_offsets.y,
+ &exponent_stack_offset,
+ &randomness_stack_offset,
+ &distance_out_stack_offset,
+ &color_out_stack_offset);
+ svm_unpack_node_uchar3(
+ stack_offsets.z, &position_out_stack_offset, &w_out_stack_offset, &radius_out_stack_offset);
+
+ float3 coord = stack_load_float3(stack, coord_stack_offset);
+ float w = stack_load_float_default(stack, w_stack_offset, stack_offsets.w);
+ float scale = stack_load_float_default(stack, scale_stack_offset, defaults.x);
+ float smoothness = stack_load_float_default(stack, smoothness_stack_offset, defaults.y);
+ float exponent = stack_load_float_default(stack, exponent_stack_offset, defaults.z);
+ float randomness = stack_load_float_default(stack, randomness_stack_offset, defaults.w);
+
+ NodeVoronoiFeature voronoi_feature = (NodeVoronoiFeature)feature;
+ NodeVoronoiDistanceMetric voronoi_metric = (NodeVoronoiDistanceMetric)metric;
+
+ float distance_out, w_out, radius_out;
+ float3 color_out, position_out;
+
+ randomness = clamp(randomness, 0.0f, 1.0f);
+ smoothness = clamp(smoothness / 2.0f, 0.0f, 0.5f);
+
+ w *= scale;
+ coord *= scale;
+
+ switch (dimensions) {
+ case 1: {
+ switch (voronoi_feature) {
+ case NODE_VORONOI_F1:
+ voronoi_f1_1d(
+ w, exponent, randomness, voronoi_metric, &distance_out, &color_out, &w_out);
+ break;
+ case NODE_VORONOI_SMOOTH_F1:
+ voronoi_smooth_f1_1d(w,
+ smoothness,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &w_out);
+ break;
+ case NODE_VORONOI_F2:
+ voronoi_f2_1d(
+ w, exponent, randomness, voronoi_metric, &distance_out, &color_out, &w_out);
+ break;
+ case NODE_VORONOI_DISTANCE_TO_EDGE:
+ voronoi_distance_to_edge_1d(w, randomness, &distance_out);
+ break;
+ case NODE_VORONOI_N_SPHERE_RADIUS:
+ voronoi_n_sphere_radius_1d(w, randomness, &radius_out);
+ break;
+ default:
+ kernel_assert(0);
+ }
+ w_out = safe_divide(w_out, scale);
+ break;
+ }
+ case 2: {
+ float2 coord_2d = make_float2(coord.x, coord.y);
+ float2 position_out_2d;
+ switch (voronoi_feature) {
+ case NODE_VORONOI_F1:
+ voronoi_f1_2d(coord_2d,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_2d);
+ break;
+ case NODE_VORONOI_SMOOTH_F1:
+ voronoi_smooth_f1_2d(coord_2d,
+ smoothness,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_2d);
+ break;
+ case NODE_VORONOI_F2:
+ voronoi_f2_2d(coord_2d,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_2d);
+ break;
+ case NODE_VORONOI_DISTANCE_TO_EDGE:
+ voronoi_distance_to_edge_2d(coord_2d, randomness, &distance_out);
+ break;
+ case NODE_VORONOI_N_SPHERE_RADIUS:
+ voronoi_n_sphere_radius_2d(coord_2d, randomness, &radius_out);
+ break;
+ default:
+ kernel_assert(0);
+ }
+ position_out_2d = safe_divide_float2_float(position_out_2d, scale);
+ position_out = make_float3(position_out_2d.x, position_out_2d.y, 0.0f);
+ break;
+ }
+ case 3: {
+ switch (voronoi_feature) {
+ case NODE_VORONOI_F1:
+ voronoi_f1_3d(coord,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out);
+ break;
+ case NODE_VORONOI_SMOOTH_F1:
+ voronoi_smooth_f1_3d(coord,
+ smoothness,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out);
+ break;
+ case NODE_VORONOI_F2:
+ voronoi_f2_3d(coord,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out);
+ break;
+ case NODE_VORONOI_DISTANCE_TO_EDGE:
+ voronoi_distance_to_edge_3d(coord, randomness, &distance_out);
+ break;
+ case NODE_VORONOI_N_SPHERE_RADIUS:
+ voronoi_n_sphere_radius_3d(coord, randomness, &radius_out);
+ break;
+ default:
+ kernel_assert(0);
+ }
+ position_out = safe_divide_float3_float(position_out, scale);
+ break;
+ }
+ case 4: {
+ float4 coord_4d = make_float4(coord.x, coord.y, coord.z, w);
+ float4 position_out_4d;
+ switch (voronoi_feature) {
+ case NODE_VORONOI_F1:
+ voronoi_f1_4d(coord_4d,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_4d);
+ break;
+ case NODE_VORONOI_SMOOTH_F1:
+ voronoi_smooth_f1_4d(coord_4d,
+ smoothness,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_4d);
+ break;
+ case NODE_VORONOI_F2:
+ voronoi_f2_4d(coord_4d,
+ exponent,
+ randomness,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_4d);
+ break;
+ case NODE_VORONOI_DISTANCE_TO_EDGE:
+ voronoi_distance_to_edge_4d(coord_4d, randomness, &distance_out);
+ break;
+ case NODE_VORONOI_N_SPHERE_RADIUS:
+ voronoi_n_sphere_radius_4d(coord_4d, randomness, &radius_out);
+ break;
+ default:
+ kernel_assert(0);
+ }
+ position_out_4d = safe_divide_float4_float(position_out_4d, scale);
+ position_out = make_float3(position_out_4d.x, position_out_4d.y, position_out_4d.z);
+ w_out = position_out_4d.w;
+ break;
+ }
+ default:
+ kernel_assert(0);
+ }
+
+ if (stack_valid(distance_out_stack_offset))
+ stack_store_float(stack, distance_out_stack_offset, distance_out);
+ if (stack_valid(color_out_stack_offset))
+ stack_store_float3(stack, color_out_stack_offset, color_out);
+ if (stack_valid(position_out_stack_offset))
+ stack_store_float3(stack, position_out_stack_offset, position_out);
+ if (stack_valid(w_out_stack_offset))
+ stack_store_float(stack, w_out_stack_offset, w_out);
+ if (stack_valid(radius_out_stack_offset))
+ stack_store_float(stack, radius_out_stack_offset, radius_out);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 01661a6d1e0..1d98fabbc9f 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -965,33 +965,41 @@ NODE_DEFINE(VoronoiTextureNode)
TEXTURE_MAPPING_DEFINE(VoronoiTextureNode);
- static NodeEnum coloring_enum;
- coloring_enum.insert("intensity", NODE_VORONOI_INTENSITY);
- coloring_enum.insert("cells", NODE_VORONOI_CELLS);
- SOCKET_ENUM(coloring, "Coloring", coloring_enum, NODE_VORONOI_INTENSITY);
-
- static NodeEnum metric;
- metric.insert("distance", NODE_VORONOI_DISTANCE);
- metric.insert("manhattan", NODE_VORONOI_MANHATTAN);
- metric.insert("chebychev", NODE_VORONOI_CHEBYCHEV);
- metric.insert("minkowski", NODE_VORONOI_MINKOWSKI);
- SOCKET_ENUM(metric, "Distance Metric", metric, NODE_VORONOI_INTENSITY);
+ static NodeEnum dimensions_enum;
+ dimensions_enum.insert("1D", 1);
+ dimensions_enum.insert("2D", 2);
+ dimensions_enum.insert("3D", 3);
+ dimensions_enum.insert("4D", 4);
+ SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
+
+ static NodeEnum metric_enum;
+ metric_enum.insert("euclidean", NODE_VORONOI_EUCLIDEAN);
+ metric_enum.insert("manhattan", NODE_VORONOI_MANHATTAN);
+ metric_enum.insert("chebychev", NODE_VORONOI_CHEBYCHEV);
+ metric_enum.insert("minkowski", NODE_VORONOI_MINKOWSKI);
+ SOCKET_ENUM(metric, "Distance Metric", metric_enum, NODE_VORONOI_EUCLIDEAN);
static NodeEnum feature_enum;
- feature_enum.insert("F1", NODE_VORONOI_F1);
- feature_enum.insert("F2", NODE_VORONOI_F2);
- feature_enum.insert("F3", NODE_VORONOI_F3);
- feature_enum.insert("F4", NODE_VORONOI_F4);
- feature_enum.insert("F2F1", NODE_VORONOI_F2F1);
- SOCKET_ENUM(feature, "Feature", feature_enum, NODE_VORONOI_INTENSITY);
+ feature_enum.insert("f1", NODE_VORONOI_F1);
+ feature_enum.insert("f2", NODE_VORONOI_F2);
+ feature_enum.insert("smooth_f1", NODE_VORONOI_SMOOTH_F1);
+ feature_enum.insert("distance_to_edge", NODE_VORONOI_DISTANCE_TO_EDGE);
+ feature_enum.insert("n_sphere_radius", NODE_VORONOI_N_SPHERE_RADIUS);
+ SOCKET_ENUM(feature, "Feature", feature_enum, NODE_VORONOI_F1);
- SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
- SOCKET_IN_FLOAT(exponent, "Exponent", 0.5f);
SOCKET_IN_POINT(
vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+ SOCKET_IN_FLOAT(w, "W", 0.0f);
+ SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
+ SOCKET_IN_FLOAT(smoothness, "Smoothness", 5.0f);
+ SOCKET_IN_FLOAT(exponent, "Exponent", 0.5f);
+ SOCKET_IN_FLOAT(randomness, "Randomness", 1.0f);
+ SOCKET_OUT_FLOAT(distance, "Distance");
SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_FLOAT(fac, "Fac");
+ SOCKET_OUT_POINT(position, "Position");
+ SOCKET_OUT_FLOAT(w, "W");
+ SOCKET_OUT_FLOAT(radius, "Radius");
return type;
}
@@ -1002,39 +1010,57 @@ VoronoiTextureNode::VoronoiTextureNode() : TextureNode(node_type)
void VoronoiTextureNode::compile(SVMCompiler &compiler)
{
- ShaderInput *scale_in = input("Scale");
ShaderInput *vector_in = input("Vector");
+ ShaderInput *w_in = input("W");
+ ShaderInput *scale_in = input("Scale");
+ ShaderInput *smoothness_in = input("Smoothness");
ShaderInput *exponent_in = input("Exponent");
+ ShaderInput *randomness_in = input("Randomness");
+
+ ShaderOutput *distance_out = output("Distance");
ShaderOutput *color_out = output("Color");
- ShaderOutput *fac_out = output("Fac");
+ ShaderOutput *position_out = output("Position");
+ ShaderOutput *w_out = output("W");
+ ShaderOutput *radius_out = output("Radius");
- if (vector_in->link)
- compiler.stack_assign(vector_in);
- if (scale_in->link)
- compiler.stack_assign(scale_in);
- if (exponent_in->link)
- compiler.stack_assign(exponent_in);
+ int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
+ int w_in_stack_offset = compiler.stack_assign_if_linked(w_in);
+ int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
+ int smoothness_stack_offset = compiler.stack_assign_if_linked(smoothness_in);
+ int exponent_stack_offset = compiler.stack_assign_if_linked(exponent_in);
+ int randomness_stack_offset = compiler.stack_assign_if_linked(randomness_in);
+ int distance_stack_offset = compiler.stack_assign_if_linked(distance_out);
+ int color_stack_offset = compiler.stack_assign_if_linked(color_out);
+ int position_stack_offset = compiler.stack_assign_if_linked(position_out);
+ int w_out_stack_offset = compiler.stack_assign_if_linked(w_out);
+ int radius_stack_offset = compiler.stack_assign_if_linked(radius_out);
- int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
+ compiler.add_node(NODE_TEX_VORONOI, dimensions, feature, metric);
+ compiler.add_node(
+ compiler.encode_uchar4(
+ vector_stack_offset, w_in_stack_offset, scale_stack_offset, smoothness_stack_offset),
+ compiler.encode_uchar4(exponent_stack_offset,
+ randomness_stack_offset,
+ distance_stack_offset,
+ color_stack_offset),
+ compiler.encode_uchar4(position_stack_offset, w_out_stack_offset, radius_stack_offset),
+ __float_as_int(w));
- compiler.add_node(NODE_TEX_VORONOI,
- compiler.encode_uchar4(vector_offset, coloring, metric, feature),
- compiler.encode_uchar4(compiler.stack_assign_if_linked(scale_in),
- compiler.stack_assign_if_linked(exponent_in),
- compiler.stack_assign(fac_out),
- compiler.stack_assign(color_out)));
- compiler.add_node(__float_as_int(scale), __float_as_int(exponent));
+ compiler.add_node(__float_as_int(scale),
+ __float_as_int(smoothness),
+ __float_as_int(exponent),
+ __float_as_int(randomness));
- tex_mapping.compile_end(compiler, vector_in, vector_offset);
+ tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
}
void VoronoiTextureNode::compile(OSLCompiler &compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter(this, "coloring");
- compiler.parameter(this, "metric");
+ compiler.parameter(this, "dimensions");
compiler.parameter(this, "feature");
+ compiler.parameter(this, "metric");
compiler.add(this, "node_voronoi_texture");
}
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 5d7e074f62b..171568644fb 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -220,10 +220,10 @@ class VoronoiTextureNode : public TextureNode {
return NODE_GROUP_LEVEL_2;
}
- NodeVoronoiColoring coloring;
+ int dimensions;
NodeVoronoiDistanceMetric metric;
NodeVoronoiFeature feature;
- float scale, exponent;
+ float w, scale, exponent, smoothness, randomness;
float3 vector;
};
diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h
index 17bb766445d..53e528de66e 100644
--- a/intern/cycles/util/util_math.h
+++ b/intern/cycles/util/util_math.h
@@ -294,6 +294,21 @@ ccl_device_inline float mix(float a, float b, float t)
{
return a + t * (b - a);
}
+
+ccl_device_inline float smoothstep(float edge0, float edge1, float x)
+{
+ float result;
+ if (x < edge0)
+ result = 0.0f;
+ else if (x >= edge1)
+ result = 1.0f;
+ else {
+ float t = (x - edge0) / (edge1 - edge0);
+ result = (3.0f - 2.0f * t) * (t * t);
+ }
+ return result;
+}
+
#endif /* __KERNEL_OPENCL__ */
#ifndef __KERNEL_CUDA__
diff --git a/intern/cycles/util/util_math_float2.h b/intern/cycles/util/util_math_float2.h
index 9feaf042d19..bf21430af3c 100644
--- a/intern/cycles/util/util_math_float2.h
+++ b/intern/cycles/util/util_math_float2.h
@@ -35,7 +35,9 @@ ccl_device_inline float2 operator*(float f, const float2 &a);
ccl_device_inline float2 operator/(float f, const float2 &a);
ccl_device_inline float2 operator/(const float2 &a, float f);
ccl_device_inline float2 operator/(const float2 &a, const float2 &b);
+ccl_device_inline float2 operator+(const float2 &a, const float f);
ccl_device_inline float2 operator+(const float2 &a, const float2 &b);
+ccl_device_inline float2 operator-(const float2 &a, const float f);
ccl_device_inline float2 operator-(const float2 &a, const float2 &b);
ccl_device_inline float2 operator+=(float2 &a, const float2 &b);
ccl_device_inline float2 operator*=(float2 &a, const float2 &b);
@@ -48,6 +50,7 @@ ccl_device_inline bool operator!=(const float2 &a, const float2 &b);
ccl_device_inline bool is_zero(const float2 &a);
ccl_device_inline float average(const float2 &a);
+ccl_device_inline float distance(const float2 &a, const float2 &b);
ccl_device_inline float dot(const float2 &a, const float2 &b);
ccl_device_inline float cross(const float2 &a, const float2 &b);
ccl_device_inline float len(const float2 &a);
@@ -60,8 +63,11 @@ ccl_device_inline float2 clamp(const float2 &a, const float2 &mn, const float2 &
ccl_device_inline float2 fabs(const float2 &a);
ccl_device_inline float2 as_float2(const float4 &a);
ccl_device_inline float2 interp(const float2 &a, const float2 &b, float t);
+ccl_device_inline float2 floor(const float2 &a);
#endif /* !__KERNEL_OPENCL__ */
+ccl_device_inline float2 safe_divide_float2_float(const float2 a, const float b);
+
/*******************************************************************************
* Definition.
*/
@@ -103,11 +109,21 @@ ccl_device_inline float2 operator/(const float2 &a, const float2 &b)
return make_float2(a.x / b.x, a.y / b.y);
}
+ccl_device_inline float2 operator+(const float2 &a, const float f)
+{
+ return a + make_float2(f, f);
+}
+
ccl_device_inline float2 operator+(const float2 &a, const float2 &b)
{
return make_float2(a.x + b.x, a.y + b.y);
}
+ccl_device_inline float2 operator-(const float2 &a, const float f)
+{
+ return a - make_float2(f, f);
+}
+
ccl_device_inline float2 operator-(const float2 &a, const float2 &b)
{
return make_float2(a.x - b.x, a.y - b.y);
@@ -159,6 +175,11 @@ ccl_device_inline float average(const float2 &a)
return (a.x + a.y) * (1.0f / 2.0f);
}
+ccl_device_inline float distance(const float2 &a, const float2 &b)
+{
+ return len(a - b);
+}
+
ccl_device_inline float dot(const float2 &a, const float2 &b)
{
return a.x * b.x + a.y * b.y;
@@ -226,8 +247,18 @@ ccl_device_inline float2 mix(const float2 &a, const float2 &b, float t)
return a + t * (b - a);
}
+ccl_device_inline float2 floor(const float2 &a)
+{
+ return make_float2(floorf(a.x), floorf(a.y));
+}
+
#endif /* !__KERNEL_OPENCL__ */
+ccl_device_inline float2 safe_divide_float2_float(const float2 a, const float b)
+{
+ return (b != 0.0f) ? a / b : make_float2(0.0f, 0.0f);
+}
+
CCL_NAMESPACE_END
#endif /* __UTIL_MATH_FLOAT2_H__ */
diff --git a/intern/cycles/util/util_math_float3.h b/intern/cycles/util/util_math_float3.h
index c9a5b34aa58..dd2010715ba 100644
--- a/intern/cycles/util/util_math_float3.h
+++ b/intern/cycles/util/util_math_float3.h
@@ -35,7 +35,9 @@ ccl_device_inline float3 operator*(const float f, const float3 &a);
ccl_device_inline float3 operator/(const float f, const float3 &a);
ccl_device_inline float3 operator/(const float3 &a, const float f);
ccl_device_inline float3 operator/(const float3 &a, const float3 &b);
+ccl_device_inline float3 operator+(const float3 &a, const float f);
ccl_device_inline float3 operator+(const float3 &a, const float3 &b);
+ccl_device_inline float3 operator-(const float3 &a, const float f);
ccl_device_inline float3 operator-(const float3 &a, const float3 &b);
ccl_device_inline float3 operator+=(float3 &a, const float3 &b);
ccl_device_inline float3 operator-=(float3 &a, const float3 &b);
@@ -150,6 +152,11 @@ ccl_device_inline float3 operator/(const float3 &a, const float3 &b)
# endif
}
+ccl_device_inline float3 operator+(const float3 &a, const float f)
+{
+ return a + make_float3(f, f, f);
+}
+
ccl_device_inline float3 operator+(const float3 &a, const float3 &b)
{
# ifdef __KERNEL_SSE__
@@ -159,6 +166,11 @@ ccl_device_inline float3 operator+(const float3 &a, const float3 &b)
# endif
}
+ccl_device_inline float3 operator-(const float3 &a, const float f)
+{
+ return a - make_float3(f, f, f);
+}
+
ccl_device_inline float3 operator-(const float3 &a, const float3 &b)
{
# ifdef __KERNEL_SSE__
diff --git a/intern/cycles/util/util_math_float4.h b/intern/cycles/util/util_math_float4.h
index 1fb886572e3..bc5322a22bb 100644
--- a/intern/cycles/util/util_math_float4.h
+++ b/intern/cycles/util/util_math_float4.h
@@ -34,7 +34,9 @@ ccl_device_inline float4 operator*(const float4 &a, float f);
ccl_device_inline float4 operator*(float f, const float4 &a);
ccl_device_inline float4 operator/(const float4 &a, float f);
ccl_device_inline float4 operator/(const float4 &a, const float4 &b);
+ccl_device_inline float4 operator+(const float4 &a, const float f);
ccl_device_inline float4 operator+(const float4 &a, const float4 &b);
+ccl_device_inline float4 operator-(const float4 &a, const float f);
ccl_device_inline float4 operator-(const float4 &a, const float4 &b);
ccl_device_inline float4 operator+=(float4 &a, const float4 &b);
ccl_device_inline float4 operator*=(float4 &a, const float4 &b);
@@ -46,6 +48,7 @@ ccl_device_inline int4 operator>=(const float4 &a, const float4 &b);
ccl_device_inline int4 operator<=(const float4 &a, const float4 &b);
ccl_device_inline bool operator==(const float4 &a, const float4 &b);
+ccl_device_inline float distance(const float4 &a, const float4 &b);
ccl_device_inline float dot(const float4 &a, const float4 &b);
ccl_device_inline float len_squared(const float4 &a);
ccl_device_inline float4 rcp(const float4 &a);
@@ -61,8 +64,12 @@ ccl_device_inline float4 min(const float4 &a, const float4 &b);
ccl_device_inline float4 max(const float4 &a, const float4 &b);
ccl_device_inline float4 clamp(const float4 &a, const float4 &mn, const float4 &mx);
ccl_device_inline float4 fabs(const float4 &a);
+ccl_device_inline float4 floor(const float4 &a);
+ccl_device_inline float4 mix(const float4 &a, const float4 &b, float t);
#endif /* !__KERNEL_OPENCL__*/
+ccl_device_inline float4 safe_divide_float4_float(const float4 a, const float b);
+
#ifdef __KERNEL_SSE__
template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
__forceinline const float4 shuffle(const float4 &b);
@@ -139,6 +146,11 @@ ccl_device_inline float4 operator/(const float4 &a, const float4 &b)
# endif
}
+ccl_device_inline float4 operator+(const float4 &a, const float f)
+{
+ return a + make_float4(f, f, f, f);
+}
+
ccl_device_inline float4 operator+(const float4 &a, const float4 &b)
{
# ifdef __KERNEL_SSE__
@@ -148,6 +160,11 @@ ccl_device_inline float4 operator+(const float4 &a, const float4 &b)
# endif
}
+ccl_device_inline float4 operator-(const float4 &a, const float f)
+{
+ return a - make_float4(f, f, f, f);
+}
+
ccl_device_inline float4 operator-(const float4 &a, const float4 &b)
{
# ifdef __KERNEL_SSE__
@@ -213,6 +230,11 @@ ccl_device_inline bool operator==(const float4 &a, const float4 &b)
# endif
}
+ccl_device_inline float distance(const float4 &a, const float4 &b)
+{
+ return len(a - b);
+}
+
ccl_device_inline float dot(const float4 &a, const float4 &b)
{
# if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
@@ -338,6 +360,21 @@ ccl_device_inline float4 fabs(const float4 &a)
return make_float4(fabsf(a.x), fabsf(a.y), fabsf(a.z), fabsf(a.w));
# endif
}
+
+ccl_device_inline float4 floor(const float4 &a)
+{
+# ifdef __KERNEL_SSE__
+ return float4(_mm_floor_ps(a));
+# else
+ return make_float4(floorf(a.x), floorf(a.y), floorf(a.z), floorf(a.w));
+# endif
+}
+
+ccl_device_inline float4 mix(const float4 &a, const float4 &b, float t)
+{
+ return a + t * (b - a);
+}
+
#endif /* !__KERNEL_OPENCL__*/
#ifdef __KERNEL_SSE__
@@ -430,6 +467,11 @@ ccl_device_inline float4 load_float4(const float *v)
#endif /* !__KERNEL_GPU__ */
+ccl_device_inline float4 safe_divide_float4_float(const float4 a, const float b)
+{
+ return (b != 0.0f) ? a / b : make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+}
+
CCL_NAMESPACE_END
#endif /* __UTIL_MATH_FLOAT4_H__ */
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;