Add Fractal Voronoi Noise V.2 #106827
|
@ -873,6 +873,7 @@ static ShaderNode *add_node(Scene *scene,
|
|||
voronoi->set_dimensions(b_voronoi_node.voronoi_dimensions());
|
||||
voronoi->set_feature((NodeVoronoiFeature)b_voronoi_node.feature());
|
||||
voronoi->set_metric((NodeVoronoiDistanceMetric)b_voronoi_node.distance());
|
||||
voronoi->set_normalize(b_voronoi_node.normalize());
|
||||
BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping());
|
||||
get_tex_mapping(voronoi, b_texture_mapping);
|
||||
node = voronoi;
|
||||
|
|
|
@ -113,11 +113,13 @@ file(GLOB SRC_OSL_HEADER_DIST ${OSL_SHADER_DIR}/*.h)
|
|||
set(SRC_OSL_HEADERS
|
||||
node_color.h
|
||||
node_color_blend.h
|
||||
node_fractal_voronoi.h
|
||||
node_fresnel.h
|
||||
node_hash.h
|
||||
node_math.h
|
||||
node_noise.h
|
||||
node_ramp_util.h
|
||||
node_voronoi.h
|
||||
stdcycles.h
|
||||
${SRC_OSL_HEADER_DIST}
|
||||
)
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright 2011-2022 Blender Foundation */
|
||||
|
||||
#include "node_voronoi.h"
|
||||
#include "stdcycles.h"
|
||||
#include "vector2.h"
|
||||
#include "vector4.h"
|
||||
|
||||
#define vector3 point
|
||||
|
||||
#define FRACTAL_VORONOI_X_FX(T) \
|
||||
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, T coord) \
|
||||
{ \
|
||||
float amplitude = 1.0; \
|
||||
float max_amplitude = 0.0; \
|
||||
float scale = 1.0; \
|
||||
\
|
||||
VoronoiOutput Output; \
|
||||
Output.Distance = 0.0; \
|
||||
Output.Color = color(0.0, 0.0, 0.0); \
|
||||
Output.Position = vector4(0.0, 0.0, 0.0, 0.0); \
|
||||
int zero_input = params.detail == 0.0 || params.roughness == 0.0 || params.lacunarity == 0.0; \
|
||||
\
|
||||
for (int i = 0; i <= ceil(params.detail); ++i) { \
|
||||
VoronoiOutput octave; \
|
||||
if (params.feature == "f1") { \
|
||||
octave = voronoi_f1(params, coord * scale); \
|
||||
} \
|
||||
else if (params.feature == "smooth_f1") { \
|
||||
octave = voronoi_smooth_f1(params, coord * scale); \
|
||||
} \
|
||||
else { \
|
||||
octave = voronoi_f2(params, coord * scale); \
|
||||
} \
|
||||
\
|
||||
if (zero_input) { \
|
||||
max_amplitude = 1.0; \
|
||||
Output = octave; \
|
||||
break; \
|
||||
} \
|
||||
else if (i <= params.detail) { \
|
||||
max_amplitude += amplitude; \
|
||||
Output.Distance += octave.Distance * amplitude; \
|
||||
Output.Color += octave.Color * amplitude; \
|
||||
Output.Position = mix(Output.Position, octave.Position / scale, amplitude); \
|
||||
scale *= params.lacunarity; \
|
||||
amplitude *= params.roughness; \
|
||||
} \
|
||||
else { \
|
||||
float remainder = params.detail - floor(params.detail); \
|
||||
if (remainder != 0.0) { \
|
||||
max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder); \
|
||||
Output.Distance = mix( \
|
||||
Output.Distance, Output.Distance + octave.Distance * amplitude, remainder); \
|
||||
Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder); \
|
||||
Output.Position = mix(Output.Position, \
|
||||
mix(Output.Position, octave.Position / scale, amplitude), \
|
||||
remainder); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (params.normalize) { \
|
||||
Output.Distance /= max_amplitude * params.max_distance; \
|
||||
Output.Color /= max_amplitude; \
|
||||
} \
|
||||
\
|
||||
Output.Position = safe_divide(Output.Position, params.scale); \
|
||||
\
|
||||
return Output; \
|
||||
}
|
||||
|
||||
#define FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(T) \
|
||||
float fractal_voronoi_distance_to_edge(VoronoiParams params, T coord) \
|
||||
{ \
|
||||
float amplitude = 1.0; \
|
||||
float max_amplitude = 0.5 + 0.5 * params.randomness; \
|
||||
float scale = 1.0; \
|
||||
float distance = 8.0; \
|
||||
\
|
||||
int zero_input = params.detail == 0.0 || params.roughness == 0.0 || params.lacunarity == 0.0; \
|
||||
\
|
||||
for (int i = 0; i <= ceil(params.detail); ++i) { \
|
||||
float octave_distance = voronoi_distance_to_edge(params, coord * scale); \
|
||||
\
|
||||
if (zero_input) { \
|
||||
distance = octave_distance; \
|
||||
break; \
|
||||
} \
|
||||
else if (i <= params.detail) { \
|
||||
max_amplitude = mix(max_amplitude, (0.5 + 0.5 * params.randomness) / scale, amplitude); \
|
||||
distance = mix(distance, min(distance, octave_distance / scale), amplitude); \
|
||||
scale *= params.lacunarity; \
|
||||
amplitude *= params.roughness; \
|
||||
} \
|
||||
else { \
|
||||
float remainder = params.detail - floor(params.detail); \
|
||||
if (remainder != 0.0) { \
|
||||
float lerp_amplitude = mix( \
|
||||
max_amplitude, (0.5 + 0.5 * params.randomness) / scale, amplitude); \
|
||||
max_amplitude = mix(max_amplitude, lerp_amplitude, remainder); \
|
||||
float lerp_distance = mix(distance, min(distance, octave_distance / scale), amplitude); \
|
||||
distance = mix(distance, min(distance, lerp_distance), remainder); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (params.normalize) { \
|
||||
distance /= max_amplitude; \
|
||||
} \
|
||||
\
|
||||
return distance; \
|
||||
}
|
||||
|
||||
/* **** 1D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(float)
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(float)
|
||||
|
||||
/* **** 2D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(vector2)
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vector2)
|
||||
|
||||
/* **** 3D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(vector3)
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vector3)
|
||||
|
||||
/* **** 4D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(vector4)
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vector4)
|
|
@ -0,0 +1,920 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright 2011-2022 Blender Foundation */
|
||||
|
||||
#include "node_hash.h"
|
||||
#include "stdcycles.h"
|
||||
#include "vector2.h"
|
||||
#include "vector4.h"
|
||||
|
||||
#define vector3 point
|
||||
|
||||
struct VoronoiParams {
|
||||
float scale;
|
||||
float detail;
|
||||
float roughness;
|
||||
float lacunarity;
|
||||
float smoothness;
|
||||
float exponent;
|
||||
float randomness;
|
||||
float max_distance;
|
||||
int normalize;
|
||||
string feature;
|
||||
string metric;
|
||||
};
|
||||
|
||||
struct VoronoiOutput {
|
||||
float Distance;
|
||||
color Color;
|
||||
vector4 Position;
|
||||
};
|
||||
|
||||
/* **** 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);
|
||||
}
|
||||
|
||||
float voronoi_distance(float a, float b)
|
||||
{
|
||||
return abs(a - b);
|
||||
}
|
||||
|
||||
float voronoi_distance(vector2 a, vector2 b, VoronoiParams params)
|
||||
{
|
||||
if (params.metric == "euclidean") {
|
||||
return distance(a, b);
|
||||
}
|
||||
else if (params.metric == "manhattan") {
|
||||
return abs(a.x - b.x) + abs(a.y - b.y);
|
||||
}
|
||||
else if (params.metric == "chebychev") {
|
||||
return max(abs(a.x - b.x), abs(a.y - b.y));
|
||||
}
|
||||
else if (params.metric == "minkowski") {
|
||||
return pow(pow(abs(a.x - b.x), params.exponent) + pow(abs(a.y - b.y), params.exponent),
|
||||
1.0 / params.exponent);
|
||||
}
|
||||
else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
float voronoi_distance(vector3 a, vector3 b, VoronoiParams params)
|
||||
{
|
||||
if (params.metric == "euclidean") {
|
||||
return distance(a, b);
|
||||
}
|
||||
else if (params.metric == "manhattan") {
|
||||
return abs(a[0] - b[0]) + abs(a[1] - b[1]) + abs(a[2] - b[2]);
|
||||
}
|
||||
else if (params.metric == "chebychev") {
|
||||
return max(abs(a[0] - b[0]), max(abs(a[1] - b[1]), abs(a[2] - b[2])));
|
||||
}
|
||||
else if (params.metric == "minkowski") {
|
||||
return pow(pow(abs(a[0] - b[0]), params.exponent) + pow(abs(a[1] - b[1]), params.exponent) +
|
||||
pow(abs(a[2] - b[2]), params.exponent),
|
||||
1.0 / params.exponent);
|
||||
}
|
||||
else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
float voronoi_distance(vector4 a, vector4 b, VoronoiParams params)
|
||||
{
|
||||
if (params.metric == "euclidean") {
|
||||
return distance(a, b);
|
||||
}
|
||||
else if (params.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 (params.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 (params.metric == "minkowski") {
|
||||
return pow(pow(abs(a.x - b.x), params.exponent) + pow(abs(a.y - b.y), params.exponent) +
|
||||
pow(abs(a.z - b.z), params.exponent) + pow(abs(a.w - b.w), params.exponent),
|
||||
1.0 / params.exponent);
|
||||
}
|
||||
else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/* **** 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* Original code is 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 **** */
|
||||
|
||||
vector4 voronoi_position(float coord)
|
||||
{
|
||||
return vector4(0.0, 0.0, 0.0, coord);
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f1(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0;
|
||||
float targetOffset = 0.0;
|
||||
float targetPosition = 0.0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
float cellOffset = i;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = minDistance;
|
||||
octave.Color = hash_float_to_color(cellPosition + targetOffset);
|
||||
octave.Position = voronoi_position(targetPosition + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0;
|
||||
float smoothPosition = 0.0;
|
||||
vector3 smoothColor = vector3(0.0, 0.0, 0.0);
|
||||
for (int i = -2; i <= 2; i++) {
|
||||
float cellOffset = i;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
|
||||
float h = smoothstep(
|
||||
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
|
||||
float correctionFactor = params.smoothness * h * (1.0 - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0 + 3.0 * params.smoothness;
|
||||
color cellColor = hash_float_to_color(cellPosition + cellOffset);
|
||||
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = smoothDistance;
|
||||
octave.Color = smoothColor;
|
||||
octave.Position = voronoi_position(cellPosition + smoothPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f2(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0;
|
||||
float distanceF2 = 8.0;
|
||||
float offsetF1 = 0.0;
|
||||
float positionF1 = 0.0;
|
||||
float offsetF2 = 0.0;
|
||||
float positionF2 = 0.0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
float cellOffset = i;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = distanceF2;
|
||||
octave.Color = hash_float_to_color(cellPosition + offsetF2);
|
||||
octave.Position = voronoi_position(positionF2 + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
float voronoi_distance_to_edge(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float midPointPosition = hash_float_to_float(cellPosition) * params.randomness;
|
||||
float leftPointPosition = -1.0 + hash_float_to_float(cellPosition - 1.0) * params.randomness;
|
||||
float rightPointPosition = 1.0 + hash_float_to_float(cellPosition + 1.0) * params.randomness;
|
||||
float distanceToMidLeft = abs((midPointPosition + leftPointPosition) / 2.0 - localPosition);
|
||||
float distanceToMidRight = abs((midPointPosition + rightPointPosition) / 2.0 - localPosition);
|
||||
|
||||
return min(distanceToMidLeft, distanceToMidRight);
|
||||
}
|
||||
|
||||
float voronoi_n_sphere_radius(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float closestPoint = 0.0;
|
||||
float closestPointOffset = 0.0;
|
||||
float minDistance = 8.0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
float cellOffset = i;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = abs(pointPosition - localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
float closestPointToClosestPoint = 0.0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
if (i == 0) {
|
||||
continue;
|
||||
}
|
||||
float cellOffset = i + closestPointOffset;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = abs(closestPoint - pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
|
||||
return abs(closestPointToClosestPoint - closestPoint) / 2.0;
|
||||
}
|
||||
|
||||
/* **** 2D Voronoi **** */
|
||||
|
||||
vector4 voronoi_position(vector2 coord)
|
||||
{
|
||||
return vector4(coord.x, coord.y, 0.0, 0.0);
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f1(VoronoiParams params, vector2 coord)
|
||||
{
|
||||
vector2 cellPosition = floor(coord);
|
||||
vector2 localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0;
|
||||
vector2 targetOffset = vector2(0.0, 0.0);
|
||||
vector2 targetPosition = vector2(0.0, 0.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) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = minDistance;
|
||||
octave.Color = hash_vector2_to_color(cellPosition + targetOffset);
|
||||
octave.Position = voronoi_position(targetPosition + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vector2 coord)
|
||||
{
|
||||
vector2 cellPosition = floor(coord);
|
||||
vector2 localPosition = coord - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0;
|
||||
vector3 smoothColor = vector3(0.0, 0.0, 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) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
float h = smoothstep(
|
||||
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
|
||||
float correctionFactor = params.smoothness * h * (1.0 - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0 + 3.0 * params.smoothness;
|
||||
color cellColor = hash_vector2_to_color(cellPosition + cellOffset);
|
||||
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = smoothDistance;
|
||||
octave.Color = smoothColor;
|
||||
octave.Position = voronoi_position(cellPosition + smoothPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f2(VoronoiParams params, vector2 coord)
|
||||
{
|
||||
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 = vector2(0.0, 0.0);
|
||||
vector2 positionF2 = vector2(0.0, 0.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) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = distanceF2;
|
||||
octave.Color = hash_vector2_to_color(cellPosition + offsetF2);
|
||||
octave.Position = voronoi_position(positionF2 + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
float voronoi_distance_to_edge(VoronoiParams params, vector2 coord)
|
||||
{
|
||||
vector2 cellPosition = floor(coord);
|
||||
vector2 localPosition = coord - cellPosition;
|
||||
|
||||
vector2 vectorToClosest = vector2(0.0, 0.0);
|
||||
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) *
|
||||
params.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) *
|
||||
params.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
float voronoi_n_sphere_radius(VoronoiParams params, vector2 coord)
|
||||
{
|
||||
vector2 cellPosition = floor(coord);
|
||||
vector2 localPosition = coord - cellPosition;
|
||||
|
||||
vector2 closestPoint = vector2(0.0, 0.0);
|
||||
vector2 closestPointOffset = vector2(0.0, 0.0);
|
||||
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) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
vector2 closestPointToClosestPoint = vector2(0.0, 0.0);
|
||||
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) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(closestPoint, pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
|
||||
}
|
||||
|
||||
/* **** 3D Voronoi **** */
|
||||
|
||||
vector4 voronoi_position(vector3 coord)
|
||||
{
|
||||
return vector4(coord.x, coord.y, coord.z, 0.0);
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f1(VoronoiParams params, vector3 coord)
|
||||
{
|
||||
vector3 cellPosition = floor(coord);
|
||||
vector3 localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0;
|
||||
vector3 targetOffset = vector3(0.0, 0.0, 0.0);
|
||||
vector3 targetPosition = vector3(0.0, 0.0, 0.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) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = minDistance;
|
||||
octave.Color = hash_vector3_to_color(cellPosition + targetOffset);
|
||||
octave.Position = voronoi_position(targetPosition + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vector3 coord)
|
||||
{
|
||||
vector3 cellPosition = floor(coord);
|
||||
vector3 localPosition = coord - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0;
|
||||
vector3 smoothColor = vector3(0.0, 0.0, 0.0);
|
||||
vector3 smoothPosition = vector3(0.0, 0.0, 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) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
float h = smoothstep(
|
||||
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
|
||||
float correctionFactor = params.smoothness * h * (1.0 - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0 + 3.0 * params.smoothness;
|
||||
color cellColor = hash_vector3_to_color(cellPosition + cellOffset);
|
||||
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = smoothDistance;
|
||||
octave.Color = smoothColor;
|
||||
octave.Position = voronoi_position(cellPosition + smoothPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f2(VoronoiParams params, vector3 coord)
|
||||
{
|
||||
vector3 cellPosition = floor(coord);
|
||||
vector3 localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0;
|
||||
float distanceF2 = 8.0;
|
||||
vector3 offsetF1 = vector3(0.0, 0.0, 0.0);
|
||||
vector3 positionF1 = vector3(0.0, 0.0, 0.0);
|
||||
vector3 offsetF2 = vector3(0.0, 0.0, 0.0);
|
||||
vector3 positionF2 = vector3(0.0, 0.0, 0.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) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = distanceF2;
|
||||
octave.Color = hash_vector3_to_color(cellPosition + offsetF2);
|
||||
octave.Position = voronoi_position(positionF2 + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
float voronoi_distance_to_edge(VoronoiParams params, vector3 coord)
|
||||
{
|
||||
vector3 cellPosition = floor(coord);
|
||||
vector3 localPosition = coord - cellPosition;
|
||||
|
||||
vector3 vectorToClosest = vector3(0.0, 0.0, 0.0);
|
||||
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) *
|
||||
params.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) *
|
||||
params.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
float voronoi_n_sphere_radius(VoronoiParams params, vector3 coord)
|
||||
{
|
||||
vector3 cellPosition = floor(coord);
|
||||
vector3 localPosition = coord - cellPosition;
|
||||
|
||||
vector3 closestPoint = vector3(0.0, 0.0, 0.0);
|
||||
vector3 closestPointOffset = vector3(0.0, 0.0, 0.0);
|
||||
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) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
vector3 closestPointToClosestPoint = vector3(0.0, 0.0, 0.0);
|
||||
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) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(closestPoint, pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
|
||||
}
|
||||
|
||||
/* **** 4D Voronoi **** */
|
||||
|
||||
vector4 voronoi_position(vector4 coord)
|
||||
{
|
||||
return coord;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f1(VoronoiParams params, vector4 coord)
|
||||
{
|
||||
vector4 cellPosition = floor(coord);
|
||||
vector4 localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0;
|
||||
vector4 targetOffset = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
vector4 targetPosition = vector4(0.0, 0.0, 0.0, 0.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) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = minDistance;
|
||||
octave.Color = hash_vector4_to_color(cellPosition + targetOffset);
|
||||
octave.Position = voronoi_position(targetPosition + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vector4 coord)
|
||||
{
|
||||
vector4 cellPosition = floor(coord);
|
||||
vector4 localPosition = coord - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0;
|
||||
vector3 smoothColor = vector3(0.0, 0.0, 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) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
float h = smoothstep(
|
||||
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
|
||||
float correctionFactor = params.smoothness * h * (1.0 - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0 + 3.0 * params.smoothness;
|
||||
color cellColor = hash_vector4_to_color(cellPosition + cellOffset);
|
||||
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = smoothDistance;
|
||||
octave.Color = smoothColor;
|
||||
octave.Position = voronoi_position(cellPosition + smoothPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f2(VoronoiParams params, vector4 coord)
|
||||
{
|
||||
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 = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
vector4 positionF2 = vector4(0.0, 0.0, 0.0, 0.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) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = distanceF2;
|
||||
octave.Color = hash_vector4_to_color(cellPosition + offsetF2);
|
||||
octave.Position = voronoi_position(positionF2 + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
float voronoi_distance_to_edge(VoronoiParams params, vector4 coord)
|
||||
{
|
||||
vector4 cellPosition = floor(coord);
|
||||
vector4 localPosition = coord - cellPosition;
|
||||
|
||||
vector4 vectorToClosest = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
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) *
|
||||
params.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) *
|
||||
params.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
float voronoi_n_sphere_radius(VoronoiParams params, vector4 coord)
|
||||
{
|
||||
vector4 cellPosition = floor(coord);
|
||||
vector4 localPosition = coord - cellPosition;
|
||||
|
||||
vector4 closestPoint = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
vector4 closestPointOffset = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
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) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
vector4 closestPointToClosestPoint = vector4(0.0, 0.0, 0.0, 0.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++) {
|
||||
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) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(closestPoint, pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1207,9 +1207,14 @@ NODE_DEFINE(VoronoiTextureNode)
|
|||
feature_enum.insert("n_sphere_radius", NODE_VORONOI_N_SPHERE_RADIUS);
|
||||
SOCKET_ENUM(feature, "Feature", feature_enum, NODE_VORONOI_F1);
|
||||
|
||||
SOCKET_BOOLEAN(normalize, "Normalize", false);
|
||||
|
||||
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
|
||||
SOCKET_IN_FLOAT(w, "W", 0.0f);
|
||||
SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
|
||||
SOCKET_IN_FLOAT(detail, "Detail", 0.0f);
|
||||
SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
|
||||
SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 2.0f);
|
||||
SOCKET_IN_FLOAT(smoothness, "Smoothness", 5.0f);
|
||||
SOCKET_IN_FLOAT(exponent, "Exponent", 0.5f);
|
||||
SOCKET_IN_FLOAT(randomness, "Randomness", 1.0f);
|
||||
|
@ -1230,6 +1235,9 @@ void VoronoiTextureNode::compile(SVMCompiler &compiler)
|
|||
ShaderInput *vector_in = input("Vector");
|
||||
ShaderInput *w_in = input("W");
|
||||
ShaderInput *scale_in = input("Scale");
|
||||
ShaderInput *detail_in = input("Detail");
|
||||
ShaderInput *roughness_in = input("Roughness");
|
||||
ShaderInput *lacunarity_in = input("Lacunarity");
|
||||
ShaderInput *smoothness_in = input("Smoothness");
|
||||
ShaderInput *exponent_in = input("Exponent");
|
||||
ShaderInput *randomness_in = input("Randomness");
|
||||
|
@ -1243,6 +1251,9 @@ void VoronoiTextureNode::compile(SVMCompiler &compiler)
|
|||
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 detail_stack_offset = compiler.stack_assign_if_linked(detail_in);
|
||||
int roughness_stack_offset = compiler.stack_assign_if_linked(roughness_in);
|
||||
int lacunarity_stack_offset = compiler.stack_assign_if_linked(lacunarity_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);
|
||||
|
@ -1255,19 +1266,21 @@ void VoronoiTextureNode::compile(SVMCompiler &compiler)
|
|||
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));
|
||||
vector_stack_offset, w_in_stack_offset, scale_stack_offset, detail_stack_offset),
|
||||
compiler.encode_uchar4(roughness_stack_offset,
|
||||
lacunarity_stack_offset,
|
||||
smoothness_stack_offset,
|
||||
exponent_stack_offset),
|
||||
compiler.encode_uchar4(
|
||||
randomness_stack_offset, normalize, distance_stack_offset, color_stack_offset),
|
||||
compiler.encode_uchar4(position_stack_offset, w_out_stack_offset, radius_stack_offset));
|
||||
|
||||
compiler.add_node(__float_as_int(scale),
|
||||
compiler.add_node(
|
||||
__float_as_int(w), __float_as_int(scale), __float_as_int(detail), __float_as_int(roughness));
|
||||
compiler.add_node(__float_as_int(lacunarity),
|
||||
__float_as_int(smoothness),
|
||||
__float_as_int(exponent),
|
||||
__float_as_int(randomness));
|
||||
|
||||
tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
|
||||
}
|
||||
|
||||
|
@ -1278,6 +1291,7 @@ void VoronoiTextureNode::compile(OSLCompiler &compiler)
|
|||
compiler.parameter(this, "dimensions");
|
||||
compiler.parameter(this, "feature");
|
||||
compiler.parameter(this, "metric");
|
||||
compiler.parameter(this, "normalize");
|
||||
compiler.add(this, "node_voronoi_texture");
|
||||
}
|
||||
|
||||
|
|
|
@ -254,8 +254,12 @@ class VoronoiTextureNode : public TextureNode {
|
|||
NODE_SOCKET_API(int, dimensions)
|
||||
NODE_SOCKET_API(NodeVoronoiDistanceMetric, metric)
|
||||
NODE_SOCKET_API(NodeVoronoiFeature, feature)
|
||||
NODE_SOCKET_API(bool, normalize)
|
||||
NODE_SOCKET_API(float, w)
|
||||
NODE_SOCKET_API(float, scale)
|
||||
NODE_SOCKET_API(float, detail)
|
||||
NODE_SOCKET_API(float, roughness)
|
||||
NODE_SOCKET_API(float, lacunarity)
|
||||
NODE_SOCKET_API(float, exponent)
|
||||
NODE_SOCKET_API(float, smoothness)
|
||||
NODE_SOCKET_API(float, randomness)
|
||||
|
|
|
@ -224,6 +224,12 @@ ccl_device_inline float2 floor(const float2 a)
|
|||
|
||||
#endif /* !__KERNEL_METAL__ */
|
||||
|
||||
/* Consistent name for this would be pow, but HIP compiler crashes in name mangling. */
|
||||
ccl_device_inline float2 power(float2 v, float e)
|
||||
{
|
||||
return make_float2(powf(v.x, e), powf(v.y, e));
|
||||
}
|
||||
|
||||
ccl_device_inline float2 safe_divide_float2_float(const float2 a, const float b)
|
||||
{
|
||||
return (b != 0.0f) ? a / b : zero_float2();
|
||||
|
|
|
@ -469,7 +469,8 @@ ccl_device_inline bool isequal(const float3 a, const float3 b)
|
|||
#endif
|
||||
}
|
||||
|
||||
ccl_device_inline float3 pow(float3 v, float e)
|
||||
/* Consistent name for this would be pow, but HIP compiler crashes in name mangling. */
|
||||
ccl_device_inline float3 power(float3 v, float e)
|
||||
{
|
||||
return make_float3(powf(v.x, e), powf(v.y, e), powf(v.z, e));
|
||||
}
|
||||
|
|
|
@ -593,7 +593,8 @@ ccl_device_inline float4 ensure_finite(float4 v)
|
|||
return v;
|
||||
}
|
||||
|
||||
ccl_device_inline float4 pow(float4 v, float e)
|
||||
/* Consistent name for this would be pow, but HIP compiler crashes in name mangling. */
|
||||
ccl_device_inline float4 power(float4 v, float e)
|
||||
{
|
||||
return make_float4(powf(v.x, e), powf(v.y, e), powf(v.z, e), powf(v.w, e));
|
||||
}
|
||||
|
|
|
@ -306,87 +306,85 @@ float musgrave_hetero_terrain(
|
|||
/** \name Voronoi Noise
|
||||
* \{ */
|
||||
|
||||
void voronoi_f1(float w, float randomness, float *r_distance, float3 *r_color, float *r_w);
|
||||
void voronoi_smooth_f1(
|
||||
float w, float smoothness, float randomness, float *r_distance, float3 *r_color, float *r_w);
|
||||
void voronoi_f2(float w, float randomness, float *r_distance, float3 *r_color, float *r_w);
|
||||
void voronoi_distance_to_edge(float w, float randomness, float *r_distance);
|
||||
void voronoi_n_sphere_radius(float w, float randomness, float *r_radius);
|
||||
struct VoronoiParams {
|
||||
float scale;
|
||||
float detail;
|
||||
float roughness;
|
||||
float lacunarity;
|
||||
float smoothness;
|
||||
float exponent;
|
||||
float randomness;
|
||||
float max_distance;
|
||||
bool normalize;
|
||||
int feature;
|
||||
int metric;
|
||||
};
|
||||
|
||||
void voronoi_f1(const float2 coord,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float2 *r_position);
|
||||
void voronoi_smooth_f1(const float2 coord,
|
||||
float smoothness,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float2 *r_position);
|
||||
void voronoi_f2(const float2 coord,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float2 *r_position);
|
||||
void voronoi_distance_to_edge(const float2 coord, float randomness, float *r_distance);
|
||||
void voronoi_n_sphere_radius(const float2 coord, float randomness, float *r_radius);
|
||||
struct VoronoiOutput {
|
||||
float distance = 0.0f;
|
||||
float3 color{0.0f, 0.0f, 0.0f};
|
||||
float4 position{0.0f, 0.0f, 0.0f, 0.0f};
|
||||
};
|
||||
|
||||
void voronoi_f1(const float3 coord,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float3 *r_position);
|
||||
void voronoi_smooth_f1(const float3 coord,
|
||||
float smoothness,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float3 *r_position);
|
||||
void voronoi_f2(const float3 coord,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float3 *r_position);
|
||||
void voronoi_distance_to_edge(const float3 coord, float randomness, float *r_distance);
|
||||
void voronoi_n_sphere_radius(const float3 coord, float randomness, float *r_radius);
|
||||
/* ***** Distances ***** */
|
||||
|
||||
void voronoi_f1(const float4 coord,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float4 *r_position);
|
||||
void voronoi_smooth_f1(const float4 coord,
|
||||
float smoothness,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float4 *r_position);
|
||||
void voronoi_f2(const float4 coord,
|
||||
float exponent,
|
||||
float randomness,
|
||||
int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float4 *r_position);
|
||||
void voronoi_distance_to_edge(const float4 coord, float randomness, float *r_distance);
|
||||
void voronoi_n_sphere_radius(const float4 coord, float randomness, float *r_radius);
|
||||
float voronoi_distance(const float a, const float b);
|
||||
float voronoi_distance(const float2 a, const float2 b, const VoronoiParams ¶ms);
|
||||
float voronoi_distance(const float3 a, const float3 b, const VoronoiParams ¶ms);
|
||||
float voronoi_distance(const float4 a, const float4 b, const VoronoiParams ¶ms);
|
||||
|
||||
/* **** 1D Voronoi **** */
|
||||
|
||||
float4 voronoi_position(const float coord);
|
||||
VoronoiOutput voronoi_f1(const VoronoiParams ¶ms, const float coord);
|
||||
VoronoiOutput voronoi_smooth_f1(const VoronoiParams ¶ms,
|
||||
const float coord,
|
||||
const bool calc_color);
|
||||
VoronoiOutput voronoi_f2(const VoronoiParams ¶ms, const float coord);
|
||||
float voronoi_distance_to_edge(const VoronoiParams ¶ms, const float coord);
|
||||
float voronoi_n_sphere_radius(const VoronoiParams ¶ms, const float coord);
|
||||
|
||||
/* **** 2D Voronoi **** */
|
||||
|
||||
float4 voronoi_position(const float2 coord);
|
||||
VoronoiOutput voronoi_f1(const VoronoiParams ¶ms, const float2 coord);
|
||||
VoronoiOutput voronoi_smooth_f1(const VoronoiParams ¶ms,
|
||||
const float2 coord,
|
||||
const bool calc_color);
|
||||
VoronoiOutput voronoi_f2(const VoronoiParams ¶ms, const float2 coord);
|
||||
float voronoi_distance_to_edge(const VoronoiParams ¶ms, const float2 coord);
|
||||
float voronoi_n_sphere_radius(const VoronoiParams ¶ms, const float2 coord);
|
||||
|
||||
/* **** 3D Voronoi **** */
|
||||
|
||||
float4 voronoi_position(const float3 coord);
|
||||
VoronoiOutput voronoi_f1(const VoronoiParams ¶ms, const float3 coord);
|
||||
VoronoiOutput voronoi_smooth_f1(const VoronoiParams ¶ms,
|
||||
const float3 coord,
|
||||
const bool calc_color);
|
||||
VoronoiOutput voronoi_f2(const VoronoiParams ¶ms, const float3 coord);
|
||||
float voronoi_distance_to_edge(const VoronoiParams ¶ms, const float3 coord);
|
||||
float voronoi_n_sphere_radius(const VoronoiParams ¶ms, const float3 coord);
|
||||
|
||||
/* **** 4D Voronoi **** */
|
||||
|
||||
float4 voronoi_position(const float4 coord);
|
||||
VoronoiOutput voronoi_f1(const VoronoiParams ¶ms, const float4 coord);
|
||||
VoronoiOutput voronoi_smooth_f1(const VoronoiParams ¶ms,
|
||||
const float4 coord,
|
||||
const bool calc_color);
|
||||
VoronoiOutput voronoi_f2(const VoronoiParams ¶ms, const float4 coord);
|
||||
float voronoi_distance_to_edge(const VoronoiParams ¶ms, const float4 coord);
|
||||
float voronoi_n_sphere_radius(const VoronoiParams ¶ms, const float4 coord);
|
||||
|
||||
/* Fractal Voronoi Noise */
|
||||
|
||||
template<typename T>
|
||||
VoronoiOutput fractal_voronoi_x_fx(const VoronoiParams ¶ms,
|
||||
const T coord,
|
||||
const bool calc_color);
|
||||
template<typename T>
|
||||
float fractal_voronoi_distance_to_edge(const VoronoiParams ¶ms, const T coord);
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -482,6 +482,7 @@ set(GLSL_SRC
|
|||
shaders/material/gpu_shader_material_eevee_specular.glsl
|
||||
shaders/material/gpu_shader_material_emission.glsl
|
||||
shaders/material/gpu_shader_material_fractal_noise.glsl
|
||||
shaders/material/gpu_shader_material_fractal_voronoi.glsl
|
||||
shaders/material/gpu_shader_material_fresnel.glsl
|
||||
shaders/material/gpu_shader_material_gamma.glsl
|
||||
shaders/material/gpu_shader_material_geometry.glsl
|
||||
|
@ -546,6 +547,7 @@ set(GLSL_SRC
|
|||
shaders/material/gpu_shader_material_volume_absorption.glsl
|
||||
shaders/material/gpu_shader_material_volume_principled.glsl
|
||||
shaders/material/gpu_shader_material_volume_scatter.glsl
|
||||
shaders/material/gpu_shader_material_voronoi.glsl
|
||||
shaders/material/gpu_shader_material_wireframe.glsl
|
||||
shaders/material/gpu_shader_material_world_normals.glsl
|
||||
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_material_voronoi.glsl)
|
||||
|
||||
#define FRACTAL_VORONOI_X_FX(T) \
|
||||
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, T coord) \
|
||||
{ \
|
||||
float amplitude = 1.0; \
|
||||
float max_amplitude = 0.0; \
|
||||
float scale = 1.0; \
|
||||
\
|
||||
VoronoiOutput Output; \
|
||||
Output.Distance = 0.0; \
|
||||
Output.Color = vec3(0.0, 0.0, 0.0); \
|
||||
Output.Position = vec4(0.0, 0.0, 0.0, 0.0); \
|
||||
bool zero_input = params.detail == 0.0 || params.roughness == 0.0 || \
|
||||
params.lacunarity == 0.0; \
|
||||
\
|
||||
for (int i = 0; i <= ceil(params.detail); ++i) { \
|
||||
VoronoiOutput octave; \
|
||||
if (params.feature == 0) /* SHD_VORONOI_F1 */ { \
|
||||
octave = voronoi_f1(params, coord * scale); \
|
||||
} \
|
||||
else if (params.feature == 2) /* SHD_VORONOI_SMOOTH_F1 */ { \
|
||||
octave = voronoi_smooth_f1(params, coord * scale); \
|
||||
} \
|
||||
else { \
|
||||
octave = voronoi_f2(params, coord * scale); \
|
||||
} \
|
||||
\
|
||||
if (zero_input) { \
|
||||
max_amplitude = 1.0; \
|
||||
Output = octave; \
|
||||
break; \
|
||||
} \
|
||||
else if (i <= params.detail) { \
|
||||
max_amplitude += amplitude; \
|
||||
Output.Distance += octave.Distance * amplitude; \
|
||||
Output.Color += octave.Color * amplitude; \
|
||||
Output.Position = mix(Output.Position, octave.Position / scale, amplitude); \
|
||||
scale *= params.lacunarity; \
|
||||
amplitude *= params.roughness; \
|
||||
} \
|
||||
else { \
|
||||
float remainder = params.detail - floor(params.detail); \
|
||||
if (remainder != 0.0) { \
|
||||
max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder); \
|
||||
Output.Distance = mix( \
|
||||
Output.Distance, Output.Distance + octave.Distance * amplitude, remainder); \
|
||||
Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder); \
|
||||
Output.Position = mix(Output.Position, \
|
||||
mix(Output.Position, octave.Position / scale, amplitude), \
|
||||
remainder); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (params.normalize) { \
|
||||
Output.Distance /= max_amplitude * params.max_distance; \
|
||||
Output.Color /= max_amplitude; \
|
||||
} \
|
||||
\
|
||||
Output.Position = safe_divide(Output.Position, params.scale); \
|
||||
\
|
||||
return Output; \
|
||||
}
|
||||
|
||||
#define FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(T) \
|
||||
float fractal_voronoi_distance_to_edge(VoronoiParams params, T coord) \
|
||||
{ \
|
||||
float amplitude = 1.0; \
|
||||
float max_amplitude = 0.5 + 0.5 * params.randomness; \
|
||||
float scale = 1.0; \
|
||||
float distance = 8.0; \
|
||||
\
|
||||
bool zero_input = params.detail == 0.0 || params.roughness == 0.0 || \
|
||||
params.lacunarity == 0.0; \
|
||||
\
|
||||
for (int i = 0; i <= ceil(params.detail); ++i) { \
|
||||
float octave_distance = voronoi_distance_to_edge(params, coord * scale); \
|
||||
\
|
||||
if (zero_input) { \
|
||||
distance = octave_distance; \
|
||||
break; \
|
||||
} \
|
||||
else if (i <= params.detail) { \
|
||||
max_amplitude = mix(max_amplitude, (0.5 + 0.5 * params.randomness) / scale, amplitude); \
|
||||
distance = mix(distance, min(distance, octave_distance / scale), amplitude); \
|
||||
scale *= params.lacunarity; \
|
||||
amplitude *= params.roughness; \
|
||||
} \
|
||||
else { \
|
||||
float remainder = params.detail - floor(params.detail); \
|
||||
if (remainder != 0.0) { \
|
||||
float lerp_amplitude = mix( \
|
||||
max_amplitude, (0.5 + 0.5 * params.randomness) / scale, amplitude); \
|
||||
max_amplitude = mix(max_amplitude, lerp_amplitude, remainder); \
|
||||
float lerp_distance = mix(distance, min(distance, octave_distance / scale), amplitude); \
|
||||
distance = mix(distance, min(distance, lerp_distance), remainder); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (params.normalize) { \
|
||||
distance /= max_amplitude; \
|
||||
} \
|
||||
\
|
||||
return distance; \
|
||||
}
|
||||
|
||||
/* **** 1D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(float)
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(float)
|
||||
|
||||
/* **** 2D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(vec2)
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vec2)
|
||||
|
||||
/* **** 3D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(vec3)
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vec3)
|
||||
|
||||
/* **** 4D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(vec4)
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vec4)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,889 @@
|
|||
#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
struct VoronoiParams {
|
||||
float scale;
|
||||
float detail;
|
||||
float roughness;
|
||||
float lacunarity;
|
||||
float smoothness;
|
||||
float exponent;
|
||||
float randomness;
|
||||
float max_distance;
|
||||
bool normalize;
|
||||
int feature;
|
||||
int metric;
|
||||
};
|
||||
|
||||
struct VoronoiOutput {
|
||||
float Distance;
|
||||
vec3 Color;
|
||||
vec4 Position;
|
||||
};
|
||||
|
||||
/* **** Distance Functions **** */
|
||||
|
||||
float voronoi_distance(float a, float b)
|
||||
{
|
||||
return abs(a - b);
|
||||
}
|
||||
|
||||
float voronoi_distance(vec2 a, vec2 b, VoronoiParams params)
|
||||
{
|
||||
if (params.metric == 0) // SHD_VORONOI_EUCLIDEAN
|
||||
{
|
||||
return distance(a, b);
|
||||
}
|
||||
else if (params.metric == 1) // SHD_VORONOI_MANHATTAN
|
||||
{
|
||||
return abs(a.x - b.x) + abs(a.y - b.y);
|
||||
}
|
||||
else if (params.metric == 2) // SHD_VORONOI_CHEBYCHEV
|
||||
{
|
||||
return max(abs(a.x - b.x), abs(a.y - b.y));
|
||||
}
|
||||
else if (params.metric == 3) // SHD_VORONOI_MINKOWSKI
|
||||
{
|
||||
return pow(pow(abs(a.x - b.x), params.exponent) + pow(abs(a.y - b.y), params.exponent),
|
||||
1.0 / params.exponent);
|
||||
}
|
||||
else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
float voronoi_distance(vec3 a, vec3 b, VoronoiParams params)
|
||||
{
|
||||
if (params.metric == 0) // SHD_VORONOI_EUCLIDEAN
|
||||
{
|
||||
return distance(a, b);
|
||||
}
|
||||
else if (params.metric == 1) // SHD_VORONOI_MANHATTAN
|
||||
{
|
||||
return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z);
|
||||
}
|
||||
else if (params.metric == 2) // SHD_VORONOI_CHEBYCHEV
|
||||
{
|
||||
return max(abs(a.x - b.x), max(abs(a.y - b.y), abs(a.z - b.z)));
|
||||
}
|
||||
else if (params.metric == 3) // SHD_VORONOI_MINKOWSKI
|
||||
{
|
||||
return pow(pow(abs(a.x - b.x), params.exponent) + pow(abs(a.y - b.y), params.exponent) +
|
||||
pow(abs(a.z - b.z), params.exponent),
|
||||
1.0 / params.exponent);
|
||||
}
|
||||
else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
float voronoi_distance(vec4 a, vec4 b, VoronoiParams params)
|
||||
{
|
||||
if (params.metric == 0) // SHD_VORONOI_EUCLIDEAN
|
||||
{
|
||||
return distance(a, b);
|
||||
}
|
||||
else if (params.metric == 1) // 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 (params.metric == 2) // 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 (params.metric == 3) // SHD_VORONOI_MINKOWSKI
|
||||
{
|
||||
return pow(pow(abs(a.x - b.x), params.exponent) + pow(abs(a.y - b.y), params.exponent) +
|
||||
pow(abs(a.z - b.z), params.exponent) + pow(abs(a.w - b.w), params.exponent),
|
||||
1.0 / params.exponent);
|
||||
}
|
||||
else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/* **** 1D Voronoi **** */
|
||||
|
||||
vec4 voronoi_position(float coord)
|
||||
{
|
||||
return vec4(0.0, 0.0, 0.0, coord);
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f1(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0;
|
||||
float targetOffset = 0.0;
|
||||
float targetPosition = 0.0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
float cellOffset = i;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = minDistance;
|
||||
octave.Color = hash_float_to_vec3(cellPosition + targetOffset);
|
||||
octave.Position = voronoi_position(targetPosition + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0;
|
||||
float smoothPosition = 0.0;
|
||||
vec3 smoothColor = vec3(0.0);
|
||||
for (int i = -2; i <= 2; i++) {
|
||||
float cellOffset = i;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
|
||||
float h = smoothstep(
|
||||
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
|
||||
float correctionFactor = params.smoothness * h * (1.0 - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0 + 3.0 * params.smoothness;
|
||||
vec3 cellColor = hash_float_to_vec3(cellPosition + cellOffset);
|
||||
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = smoothDistance;
|
||||
octave.Color = smoothColor;
|
||||
octave.Position = voronoi_position(cellPosition + smoothPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f2(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0;
|
||||
float distanceF2 = 8.0;
|
||||
float offsetF1 = 0.0;
|
||||
float positionF1 = 0.0;
|
||||
float offsetF2 = 0.0;
|
||||
float positionF2 = 0.0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
float cellOffset = i;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = distanceF2;
|
||||
octave.Color = hash_float_to_vec3(cellPosition + offsetF2);
|
||||
octave.Position = voronoi_position(positionF2 + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
float voronoi_distance_to_edge(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float midPointPosition = hash_float_to_float(cellPosition) * params.randomness;
|
||||
float leftPointPosition = -1.0 + hash_float_to_float(cellPosition - 1.0) * params.randomness;
|
||||
float rightPointPosition = 1.0 + hash_float_to_float(cellPosition + 1.0) * params.randomness;
|
||||
float distanceToMidLeft = abs((midPointPosition + leftPointPosition) / 2.0 - localPosition);
|
||||
float distanceToMidRight = abs((midPointPosition + rightPointPosition) / 2.0 - localPosition);
|
||||
|
||||
return min(distanceToMidLeft, distanceToMidRight);
|
||||
}
|
||||
|
||||
float voronoi_n_sphere_radius(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float closestPoint = 0.0;
|
||||
float closestPointOffset = 0.0;
|
||||
float minDistance = 8.0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
float cellOffset = i;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = abs(pointPosition - localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
float closestPointToClosestPoint = 0.0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
if (i == 0) {
|
||||
continue;
|
||||
}
|
||||
float cellOffset = i + closestPointOffset;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = abs(closestPoint - pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
|
||||
return abs(closestPointToClosestPoint - closestPoint) / 2.0;
|
||||
}
|
||||
|
||||
/* **** 2D Voronoi **** */
|
||||
|
||||
vec4 voronoi_position(vec2 coord)
|
||||
{
|
||||
return vec4(coord.x, coord.y, 0.0, 0.0);
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f1(VoronoiParams params, vec2 coord)
|
||||
{
|
||||
vec2 cellPosition = floor(coord);
|
||||
vec2 localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0;
|
||||
vec2 targetOffset = vec2(0.0);
|
||||
vec2 targetPosition = vec2(0.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) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = minDistance;
|
||||
octave.Color = hash_vec2_to_vec3(cellPosition + targetOffset);
|
||||
octave.Position = voronoi_position(targetPosition + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vec2 coord)
|
||||
{
|
||||
vec2 cellPosition = floor(coord);
|
||||
vec2 localPosition = coord - 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) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
float h = smoothstep(
|
||||
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
|
||||
float correctionFactor = params.smoothness * h * (1.0 - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0 + 3.0 * params.smoothness;
|
||||
vec3 cellColor = hash_vec2_to_vec3(cellPosition + cellOffset);
|
||||
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = smoothDistance;
|
||||
octave.Color = smoothColor;
|
||||
octave.Position = voronoi_position(cellPosition + smoothPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f2(VoronoiParams params, vec2 coord)
|
||||
{
|
||||
vec2 cellPosition = floor(coord);
|
||||
vec2 localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0;
|
||||
float distanceF2 = 8.0;
|
||||
vec2 offsetF1 = vec2(0.0);
|
||||
vec2 positionF1 = vec2(0.0);
|
||||
vec2 offsetF2 = vec2(0.0);
|
||||
vec2 positionF2 = vec2(0.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) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = distanceF2;
|
||||
octave.Color = hash_vec2_to_vec3(cellPosition + offsetF2);
|
||||
octave.Position = voronoi_position(positionF2 + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
float voronoi_distance_to_edge(VoronoiParams params, vec2 coord)
|
||||
{
|
||||
vec2 cellPosition = floor(coord);
|
||||
vec2 localPosition = coord - cellPosition;
|
||||
|
||||
vec2 vectorToClosest = vec2(0.0);
|
||||
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) * params.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) * params.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
float voronoi_n_sphere_radius(VoronoiParams params, vec2 coord)
|
||||
{
|
||||
vec2 cellPosition = floor(coord);
|
||||
vec2 localPosition = coord - cellPosition;
|
||||
|
||||
vec2 closestPoint = vec2(0.0);
|
||||
vec2 closestPointOffset = vec2(0.0);
|
||||
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) * params.randomness;
|
||||
float distanceToPoint = distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
vec2 closestPointToClosestPoint = vec2(0.0);
|
||||
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) * params.randomness;
|
||||
float distanceToPoint = distance(closestPoint, pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
|
||||
}
|
||||
|
||||
/* **** 3D Voronoi **** */
|
||||
|
||||
vec4 voronoi_position(vec3 coord)
|
||||
{
|
||||
return vec4(coord.x, coord.y, coord.z, 0.0);
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f1(VoronoiParams params, vec3 coord)
|
||||
{
|
||||
vec3 cellPosition = floor(coord);
|
||||
vec3 localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0;
|
||||
vec3 targetOffset = vec3(0.0);
|
||||
vec3 targetPosition = vec3(0.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) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = minDistance;
|
||||
octave.Color = hash_vec3_to_vec3(cellPosition + targetOffset);
|
||||
octave.Position = voronoi_position(targetPosition + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vec3 coord)
|
||||
{
|
||||
vec3 cellPosition = floor(coord);
|
||||
vec3 localPosition = coord - 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) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
float h = smoothstep(
|
||||
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
|
||||
float correctionFactor = params.smoothness * h * (1.0 - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0 + 3.0 * params.smoothness;
|
||||
vec3 cellColor = hash_vec3_to_vec3(cellPosition + cellOffset);
|
||||
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = smoothDistance;
|
||||
octave.Color = smoothColor;
|
||||
octave.Position = voronoi_position(cellPosition + smoothPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f2(VoronoiParams params, vec3 coord)
|
||||
{
|
||||
vec3 cellPosition = floor(coord);
|
||||
vec3 localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0;
|
||||
float distanceF2 = 8.0;
|
||||
vec3 offsetF1 = vec3(0.0);
|
||||
vec3 positionF1 = vec3(0.0);
|
||||
vec3 offsetF2 = vec3(0.0);
|
||||
vec3 positionF2 = vec3(0.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) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = distanceF2;
|
||||
octave.Color = hash_vec3_to_vec3(cellPosition + offsetF2);
|
||||
octave.Position = voronoi_position(positionF2 + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
float voronoi_distance_to_edge(VoronoiParams params, vec3 coord)
|
||||
{
|
||||
vec3 cellPosition = floor(coord);
|
||||
vec3 localPosition = coord - cellPosition;
|
||||
|
||||
vec3 vectorToClosest = vec3(0.0);
|
||||
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) * params.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++) {
|
||||
vec3 cellOffset = vec3(i, j, k);
|
||||
vec3 vectorToPoint = cellOffset +
|
||||
hash_vec3_to_vec3(cellPosition + cellOffset) * params.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
float voronoi_n_sphere_radius(VoronoiParams params, vec3 coord)
|
||||
{
|
||||
vec3 cellPosition = floor(coord);
|
||||
vec3 localPosition = coord - cellPosition;
|
||||
|
||||
vec3 closestPoint = vec3(0.0);
|
||||
vec3 closestPointOffset = vec3(0.0);
|
||||
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) * params.randomness;
|
||||
float distanceToPoint = distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
vec3 closestPointToClosestPoint = vec3(0.0);
|
||||
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) * params.randomness;
|
||||
float distanceToPoint = distance(closestPoint, pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
|
||||
}
|
||||
|
||||
/* **** 4D Voronoi **** */
|
||||
|
||||
vec4 voronoi_position(vec4 coord)
|
||||
{
|
||||
return coord;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f1(VoronoiParams params, vec4 coord)
|
||||
{
|
||||
vec4 cellPosition = floor(coord);
|
||||
vec4 localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0;
|
||||
vec4 targetOffset = vec4(0.0);
|
||||
vec4 targetPosition = vec4(0.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) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = minDistance;
|
||||
octave.Color = hash_vec4_to_vec3(cellPosition + targetOffset);
|
||||
octave.Position = voronoi_position(targetPosition + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vec4 coord)
|
||||
{
|
||||
vec4 cellPosition = floor(coord);
|
||||
vec4 localPosition = coord - 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) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
float h = smoothstep(
|
||||
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
|
||||
float correctionFactor = params.smoothness * h * (1.0 - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0 + 3.0 * params.smoothness;
|
||||
vec3 cellColor = hash_vec4_to_vec3(cellPosition + cellOffset);
|
||||
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = smoothDistance;
|
||||
octave.Color = smoothColor;
|
||||
octave.Position = voronoi_position(cellPosition + smoothPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f2(VoronoiParams params, vec4 coord)
|
||||
{
|
||||
vec4 cellPosition = floor(coord);
|
||||
vec4 localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0;
|
||||
float distanceF2 = 8.0;
|
||||
vec4 offsetF1 = vec4(0.0);
|
||||
vec4 positionF1 = vec4(0.0);
|
||||
vec4 offsetF2 = vec4(0.0);
|
||||
vec4 positionF2 = vec4(0.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) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = distanceF2;
|
||||
octave.Color = hash_vec4_to_vec3(cellPosition + offsetF2);
|
||||
octave.Position = voronoi_position(positionF2 + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
float voronoi_distance_to_edge(VoronoiParams params, vec4 coord)
|
||||
{
|
||||
vec4 cellPosition = floor(coord);
|
||||
vec4 localPosition = coord - cellPosition;
|
||||
|
||||
vec4 vectorToClosest = vec4(0.0);
|
||||
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) * params.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) * params.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
float voronoi_n_sphere_radius(VoronoiParams params, vec4 coord)
|
||||
{
|
||||
vec4 cellPosition = floor(coord);
|
||||
vec4 localPosition = coord - cellPosition;
|
||||
|
||||
vec4 closestPoint = vec4(0.0);
|
||||
vec4 closestPointOffset = vec4(0.0);
|
||||
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) * params.randomness;
|
||||
float distanceToPoint = distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
vec4 closestPointToClosestPoint = vec4(0.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++) {
|
||||
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) * params.randomness;
|
||||
float distanceToPoint = distance(closestPoint, pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
|
||||
}
|
|
@ -1108,7 +1108,9 @@ typedef struct NodeTexVoronoi {
|
|||
int dimensions;
|
||||
int feature;
|
||||
int distance;
|
||||
int normalize;
|
||||
int coloring DNA_DEPRECATED;
|
||||
char _pad[4];
|
||||
} NodeTexVoronoi;
|
||||
|
||||
typedef struct NodeTexMusgrave {
|
||||
|
|
|
@ -5922,6 +5922,11 @@ static void def_sh_tex_voronoi(StructRNA *srna)
|
|||
RNA_def_property_ui_text(
|
||||
prop, "Feature Output", "The Voronoi feature that the node will compute");
|
||||
RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
|
||||
|
||||
prop = RNA_def_property(srna, "normalize", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "normalize", 0);
|
||||
RNA_def_property_ui_text(prop, "Normalize", "Normalize output Distance to 0.0 to 1.0 range");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void def_sh_tex_wave(StructRNA *srna)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue