diff options
Diffstat (limited to 'intern/cycles/kernel/osl/shaders/node_voronoi_texture.osl')
-rw-r--r-- | intern/cycles/kernel/osl/shaders/node_voronoi_texture.osl | 1031 |
1 files changed, 1031 insertions, 0 deletions
diff --git a/intern/cycles/kernel/osl/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/osl/shaders/node_voronoi_texture.osl new file mode 100644 index 00000000000..de6c697fc85 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_voronoi_texture.osl @@ -0,0 +1,1031 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "node_hash.h" +#include "stdcycles.h" +#include "vector2.h" +#include "vector4.h" + +#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) +{ + 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); +} + +/* + * Original code is under the MIT License, Copyright (c) 2013 Inigo Quilez. + * + * Smooth Voronoi: + * - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi + * + * Distance To Edge based on: + * + * - https://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm + * - https://www.shadertoy.com/view/ldl3W8 + * + * With optimization to change -2..2 scan window to -1..1 for better performance, + * as explained in https://www.shadertoy.com/view/llG3zy. + */ + +/* **** 1D Voronoi **** */ + +float voronoi_distance(float a, float b, string metric, float exponent) +{ + return abs(a - b); +} + +void voronoi_f1_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 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; +} + +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; + + 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 midPointPosition = hash_float_to_float(cellPosition) * randomness; + float leftPointPosition = -1.0 + hash_float_to_float(cellPosition - 1.0) * randomness; + float rightPointPosition = 1.0 + hash_float_to_float(cellPosition + 1.0) * randomness; + float distanceToMidLeft = distance((midPointPosition + leftPointPosition) / 2.0, localPosition); + float distanceToMidRight = distance((midPointPosition + rightPointPosition) / 2.0, + localPosition); + + outDistance = min(distanceToMidLeft, distanceToMidRight); +} + +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; + } +} + +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((vector)perpendicularToEdge)); + minDistance = min(minDistance, distanceToEdge); + } + } + } + } + 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; + } + } + } + } + + 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; + } + 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; + + 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; +} + +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; + + 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; + } + } + } + } + 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; + } + } + } + } + } + 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; + + 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; + } + } + } + } + } + + 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; +} + +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 dimensions = "3D", + string feature = "f1", + string metric = "euclidean", + vector3 Vector = P, + float WIn = 0.0, + float Scale = 5.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) +{ + float randomness = clamp(Randomness, 0.0, 1.0); + float smoothness = clamp(Smoothness / 2.0, 0.0, 0.5); + + vector3 coord = Vector; + if (use_mapping) + coord = transform(mapping, coord); + + float w = WIn * Scale; + coord *= Scale; + + 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") { + voronoi_f2_1d(w, Exponent, randomness, metric, Distance, Color, WOut); + } + else if (feature == "distance_to_edge") { + voronoi_distance_to_edge_1d(w, randomness, Distance); + } + else if (feature == "n_sphere_radius") { + voronoi_n_sphere_radius_1d(w, randomness, Radius); + } + else { + error("Unknown feature!"); + } + WOut = (Scale != 0.0) ? WOut / Scale : 0.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 == "smooth_f1") { + voronoi_smooth_f1_2d( + coord2D, smoothness, Exponent, randomness, metric, Distance, Color, outPosition2D); + } + else if (feature == "f2") { + voronoi_f2_2d(coord2D, Exponent, randomness, metric, Distance, Color, outPosition2D); + } + else if (feature == "distance_to_edge") { + voronoi_distance_to_edge_2d(coord2D, randomness, Distance); + } + else if (feature == "n_sphere_radius") { + voronoi_n_sphere_radius_2d(coord2D, randomness, Radius); + } + 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!"); + } +} |