Add Fractal Voronoi Noise V.2 #106827

Merged
Jacques Lucke merged 77 commits from Hoshinova/blender:add-fractal-voronoi into main 2023-06-13 09:18:18 +02:00
20 changed files with 4059 additions and 3788 deletions

View File

@ -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;

View File

@ -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}
)

View File

@ -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)

View File

@ -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

View File

@ -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");
}

View File

@ -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)

View File

@ -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();

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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 &params);
float voronoi_distance(const float3 a, const float3 b, const VoronoiParams &params);
float voronoi_distance(const float4 a, const float4 b, const VoronoiParams &params);
/* **** 1D Voronoi **** */
float4 voronoi_position(const float coord);
VoronoiOutput voronoi_f1(const VoronoiParams &params, const float coord);
VoronoiOutput voronoi_smooth_f1(const VoronoiParams &params,
const float coord,
const bool calc_color);
VoronoiOutput voronoi_f2(const VoronoiParams &params, const float coord);
float voronoi_distance_to_edge(const VoronoiParams &params, const float coord);
float voronoi_n_sphere_radius(const VoronoiParams &params, const float coord);
/* **** 2D Voronoi **** */
float4 voronoi_position(const float2 coord);
VoronoiOutput voronoi_f1(const VoronoiParams &params, const float2 coord);
VoronoiOutput voronoi_smooth_f1(const VoronoiParams &params,
const float2 coord,
const bool calc_color);
VoronoiOutput voronoi_f2(const VoronoiParams &params, const float2 coord);
float voronoi_distance_to_edge(const VoronoiParams &params, const float2 coord);
float voronoi_n_sphere_radius(const VoronoiParams &params, const float2 coord);
/* **** 3D Voronoi **** */
float4 voronoi_position(const float3 coord);
VoronoiOutput voronoi_f1(const VoronoiParams &params, const float3 coord);
VoronoiOutput voronoi_smooth_f1(const VoronoiParams &params,
const float3 coord,
const bool calc_color);
VoronoiOutput voronoi_f2(const VoronoiParams &params, const float3 coord);
float voronoi_distance_to_edge(const VoronoiParams &params, const float3 coord);
float voronoi_n_sphere_radius(const VoronoiParams &params, const float3 coord);
/* **** 4D Voronoi **** */
float4 voronoi_position(const float4 coord);
VoronoiOutput voronoi_f1(const VoronoiParams &params, const float4 coord);
VoronoiOutput voronoi_smooth_f1(const VoronoiParams &params,
const float4 coord,
const bool calc_color);
VoronoiOutput voronoi_f2(const VoronoiParams &params, const float4 coord);
float voronoi_distance_to_edge(const VoronoiParams &params, const float4 coord);
float voronoi_n_sphere_radius(const VoronoiParams &params, const float4 coord);
/* Fractal Voronoi Noise */
template<typename T>
VoronoiOutput fractal_voronoi_x_fx(const VoronoiParams &params,
const T coord,
const bool calc_color);
template<typename T>
float fractal_voronoi_distance_to_edge(const VoronoiParams &params, const T coord);
/** \} */

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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)

View File

@ -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;
}

View File

@ -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 {

View File

@ -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