Geometry Nodes: Add Voronoi Texture
Port shader Voronoi to GN Reviewed By: JacquesLucke Differential Revision: https://developer.blender.org/D12725
This commit is contained in:
parent
6e4ab5b761
commit
104887800c
|
@ -720,6 +720,7 @@ geometry_node_categories = [
|
|||
GeometryNodeCategory("GEO_TEXTURE", "Texture", items=[
|
||||
NodeItem("ShaderNodeTexGradient"),
|
||||
NodeItem("ShaderNodeTexNoise"),
|
||||
NodeItem("ShaderNodeTexVoronoi"),
|
||||
NodeItem("ShaderNodeTexWhiteNoise"),
|
||||
]),
|
||||
GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[
|
||||
|
|
|
@ -115,6 +115,11 @@ struct float2 {
|
|||
return {a.x - b.x, a.y - b.y};
|
||||
}
|
||||
|
||||
friend float2 operator-(const float2 &a, const float &b)
|
||||
{
|
||||
return {a.x - b, a.y - b};
|
||||
}
|
||||
|
||||
friend float2 operator*(const float2 &a, float b)
|
||||
{
|
||||
return {a.x * b, a.y * b};
|
||||
|
@ -137,6 +142,26 @@ struct float2 {
|
|||
return stream;
|
||||
}
|
||||
|
||||
static float2 safe_divide(const float2 &a, const float b)
|
||||
{
|
||||
return (b != 0.0f) ? a / b : float2(0.0f);
|
||||
}
|
||||
|
||||
static float2 floor(const float2 &a)
|
||||
{
|
||||
return float2(floorf(a.x), floorf(a.y));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a normalized vector. The original vector is not changed.
|
||||
*/
|
||||
float2 normalized() const
|
||||
{
|
||||
float2 result;
|
||||
normalize_v2_v2(result, *this);
|
||||
return result;
|
||||
}
|
||||
|
||||
static float dot(const float2 &a, const float2 &b)
|
||||
{
|
||||
return a.x * b.x + a.y * b.y;
|
||||
|
|
|
@ -80,6 +80,11 @@ struct float3 {
|
|||
return {-a.x, -a.y, -a.z};
|
||||
}
|
||||
|
||||
friend float3 operator-(const float3 &a, const float &b)
|
||||
{
|
||||
return {a.x - b, a.y - b, a.z - b};
|
||||
}
|
||||
|
||||
float3 &operator-=(const float3 &b)
|
||||
{
|
||||
this->x -= b.x;
|
||||
|
@ -218,6 +223,16 @@ struct float3 {
|
|||
return result;
|
||||
}
|
||||
|
||||
static float3 safe_divide(const float3 &a, const float b)
|
||||
{
|
||||
return (b != 0.0f) ? a / b : float3(0.0f);
|
||||
}
|
||||
|
||||
static float3 floor(const float3 &a)
|
||||
{
|
||||
return float3(floorf(a.x), floorf(a.y), floorf(a.z));
|
||||
}
|
||||
|
||||
void invert()
|
||||
{
|
||||
x = -x;
|
||||
|
|
|
@ -44,6 +44,11 @@ struct float4 {
|
|||
return &x;
|
||||
}
|
||||
|
||||
friend float4 operator+(const float4 &a, const float &b)
|
||||
{
|
||||
return {a.x + b, a.y + b, a.z + b, a.w + b};
|
||||
}
|
||||
|
||||
operator const float *() const
|
||||
{
|
||||
return &x;
|
||||
|
@ -58,11 +63,27 @@ struct float4 {
|
|||
return *this;
|
||||
}
|
||||
|
||||
friend float4 operator-(const float4 &a, const float4 &b)
|
||||
{
|
||||
return {a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w};
|
||||
}
|
||||
|
||||
friend float4 operator-(const float4 &a, const float &b)
|
||||
{
|
||||
return {a.x - b, a.y - b, a.z - b, a.w - b};
|
||||
}
|
||||
|
||||
friend float4 operator+(const float4 &a, const float4 &b)
|
||||
{
|
||||
return {a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w};
|
||||
}
|
||||
|
||||
friend float4 operator/(const float4 &a, float f)
|
||||
{
|
||||
BLI_assert(f != 0.0f);
|
||||
return a * (1.0f / f);
|
||||
}
|
||||
|
||||
float4 &operator*=(float factor)
|
||||
{
|
||||
x *= factor;
|
||||
|
@ -81,6 +102,37 @@ struct float4 {
|
|||
{
|
||||
return b * a;
|
||||
}
|
||||
|
||||
float length() const
|
||||
{
|
||||
return len_v4(*this);
|
||||
}
|
||||
|
||||
static float distance(const float4 &a, const float4 &b)
|
||||
{
|
||||
return (a - b).length();
|
||||
}
|
||||
|
||||
static float4 safe_divide(const float4 &a, const float b)
|
||||
{
|
||||
return (b != 0.0f) ? a / b : float4(0.0f);
|
||||
}
|
||||
|
||||
static float4 interpolate(const float4 &a, const float4 &b, float t)
|
||||
{
|
||||
return a * (1 - t) + b * t;
|
||||
}
|
||||
|
||||
static float4 floor(const float4 &a)
|
||||
{
|
||||
return float4(floorf(a.x), floorf(a.y), floorf(a.z), floorf(a.w));
|
||||
}
|
||||
|
||||
static float4 normalize(const float4 &a)
|
||||
{
|
||||
const float t = len_v4(a);
|
||||
return (t != 0.0f) ? a / t : float4(0.0f);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender
|
||||
|
|
|
@ -112,4 +112,98 @@ float3 perlin_float3_fractal_distorted(float4 position,
|
|||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Voronoi Noise
|
||||
* \{ */
|
||||
|
||||
void voronoi_f1(
|
||||
const float w, const float randomness, float *r_distance, float3 *r_color, float *r_w);
|
||||
void voronoi_smooth_f1(const float w,
|
||||
const float smoothness,
|
||||
const float randomness,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float *r_w);
|
||||
void voronoi_f2(
|
||||
const float w, const float randomness, float *r_distance, float3 *r_color, float *r_w);
|
||||
void voronoi_distance_to_edge(const float w, const float randomness, float *r_distance);
|
||||
void voronoi_n_sphere_radius(const float w, const float randomness, float *r_radius);
|
||||
|
||||
void voronoi_f1(const float2 coord,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float2 *r_position);
|
||||
void voronoi_smooth_f1(const float2 coord,
|
||||
const float smoothness,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float2 *r_position);
|
||||
void voronoi_f2(const float2 coord,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float2 *r_position);
|
||||
void voronoi_distance_to_edge(const float2 coord, const float randomness, float *r_distance);
|
||||
void voronoi_n_sphere_radius(const float2 coord, const float randomness, float *r_radius);
|
||||
|
||||
void voronoi_f1(const float3 coord,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float3 *r_position);
|
||||
void voronoi_smooth_f1(const float3 coord,
|
||||
const float smoothness,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float3 *r_position);
|
||||
void voronoi_f2(const float3 coord,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float3 *r_position);
|
||||
void voronoi_distance_to_edge(const float3 coord, const float randomness, float *r_distance);
|
||||
void voronoi_n_sphere_radius(const float3 coord, const float randomness, float *r_radius);
|
||||
|
||||
void voronoi_f1(const float4 coord,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float4 *r_position);
|
||||
void voronoi_smooth_f1(const float4 coord,
|
||||
const float smoothness,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float4 *r_position);
|
||||
void voronoi_f2(const float4 coord,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float4 *r_position);
|
||||
void voronoi_distance_to_edge(const float4 coord, const float randomness, float *r_distance);
|
||||
void voronoi_n_sphere_radius(const float4 coord, const float randomness, float *r_radius);
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::noise
|
||||
|
|
|
@ -511,6 +511,22 @@ MINLINE float smoothminf(float a, float b, float c)
|
|||
}
|
||||
}
|
||||
|
||||
MINLINE float smoothstep(float edge0, float edge1, float x)
|
||||
{
|
||||
float result;
|
||||
if (x < edge0) {
|
||||
result = 0.0f;
|
||||
}
|
||||
else if (x >= edge1) {
|
||||
result = 1.0f;
|
||||
}
|
||||
else {
|
||||
float t = (x - edge0) / (edge1 - edge0);
|
||||
result = (3.0f - 2.0f * t) * (t * t);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
MINLINE double min_dd(double a, double b)
|
||||
{
|
||||
return (a < b) ? a : b;
|
||||
|
|
|
@ -1145,6 +1145,19 @@ MINLINE float len_v3v3(const float a[3], const float b[3])
|
|||
return len_v3(d);
|
||||
}
|
||||
|
||||
MINLINE float len_v4(const float a[4])
|
||||
{
|
||||
return sqrtf(dot_v4v4(a, a));
|
||||
}
|
||||
|
||||
MINLINE float len_v4v4(const float a[4], const float b[4])
|
||||
{
|
||||
float d[4];
|
||||
|
||||
sub_v4_v4v4(d, b, a);
|
||||
return len_v4(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* \note any vectors containing `nan` will be zeroed out.
|
||||
*/
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "BLI_float2.hh"
|
||||
#include "BLI_float3.hh"
|
||||
#include "BLI_float4.hh"
|
||||
#include "BLI_math_base_safe.h"
|
||||
#include "BLI_noise.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
|
@ -755,4 +756,893 @@ float3 perlin_float3_fractal_distorted(float4 position,
|
|||
perlin_fractal(position + random_float4_offset(5.0f), octaves, roughness));
|
||||
}
|
||||
|
||||
/*
|
||||
* Voronoi: Ported from Cycles code.
|
||||
*
|
||||
* Original code is under the MIT License, Copyright (c) 2013 Inigo Quilez.
|
||||
*
|
||||
* Smooth Voronoi:
|
||||
*
|
||||
* - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
|
||||
*
|
||||
* Distance To Edge based on:
|
||||
*
|
||||
* - https://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm
|
||||
* - https://www.shadertoy.com/view/ldl3W8
|
||||
*
|
||||
* With optimization to change -2..2 scan window to -1..1 for better performance,
|
||||
* as explained in https://www.shadertoy.com/view/llG3zy.
|
||||
*/
|
||||
|
||||
/* **** 1D Voronoi **** */
|
||||
|
||||
/* Ensure to align with DNA. */
|
||||
enum {
|
||||
NOISE_SHD_VORONOI_EUCLIDEAN = 0,
|
||||
NOISE_SHD_VORONOI_MANHATTAN = 1,
|
||||
NOISE_SHD_VORONOI_CHEBYCHEV = 2,
|
||||
NOISE_SHD_VORONOI_MINKOWSKI = 3,
|
||||
};
|
||||
|
||||
BLI_INLINE float voronoi_distance(const float a, const float b)
|
||||
{
|
||||
return fabsf(b - a);
|
||||
}
|
||||
|
||||
void voronoi_f1(
|
||||
const float w, const float randomness, float *r_distance, float3 *r_color, float *r_w)
|
||||
{
|
||||
const float cellPosition = floorf(w);
|
||||
const float localPosition = w - cellPosition;
|
||||
|
||||
float minDistance = 8.0f;
|
||||
float targetOffset = 0.0f;
|
||||
float targetPosition = 0.0f;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float cellOffset = i;
|
||||
const float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * randomness;
|
||||
const float distanceToPoint = voronoi_distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
*r_distance = minDistance;
|
||||
*r_color = hash_float_to_float3(cellPosition + targetOffset);
|
||||
*r_w = targetPosition + cellPosition;
|
||||
}
|
||||
|
||||
void voronoi_smooth_f1(const float w,
|
||||
const float smoothness,
|
||||
const float randomness,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float *r_w)
|
||||
{
|
||||
const float cellPosition = floorf(w);
|
||||
const float localPosition = w - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0f;
|
||||
float smoothPosition = 0.0f;
|
||||
float3 smoothColor = float3(0.0f, 0.0f, 0.0f);
|
||||
for (int i = -2; i <= 2; i++) {
|
||||
const float cellOffset = i;
|
||||
const float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * randomness;
|
||||
const float distanceToPoint = voronoi_distance(pointPosition, localPosition);
|
||||
const float h = smoothstep(
|
||||
0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
|
||||
float correctionFactor = smoothness * h * (1.0f - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0f + 3.0f * smoothness;
|
||||
const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
|
||||
smoothColor = float3::interpolate(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
*r_distance = smoothDistance;
|
||||
*r_color = smoothColor;
|
||||
*r_w = cellPosition + smoothPosition;
|
||||
}
|
||||
|
||||
void voronoi_f2(
|
||||
const float w, const float randomness, float *r_distance, float3 *r_color, float *r_w)
|
||||
{
|
||||
const float cellPosition = floorf(w);
|
||||
const float localPosition = w - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0f;
|
||||
float distanceF2 = 8.0f;
|
||||
float offsetF1 = 0.0f;
|
||||
float positionF1 = 0.0f;
|
||||
float offsetF2 = 0.0f;
|
||||
float positionF2 = 0.0f;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float cellOffset = i;
|
||||
const float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * randomness;
|
||||
const 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;
|
||||
}
|
||||
}
|
||||
*r_distance = distanceF2;
|
||||
*r_color = hash_float_to_float3(cellPosition + offsetF2);
|
||||
*r_w = positionF2 + cellPosition;
|
||||
}
|
||||
|
||||
void voronoi_distance_to_edge(const float w, const float randomness, float *r_distance)
|
||||
{
|
||||
const float cellPosition = floorf(w);
|
||||
const float localPosition = w - cellPosition;
|
||||
|
||||
const float midPointPosition = hash_float_to_float(cellPosition) * randomness;
|
||||
const float leftPointPosition = -1.0f + hash_float_to_float(cellPosition - 1.0f) * randomness;
|
||||
const float rightPointPosition = 1.0f + hash_float_to_float(cellPosition + 1.0f) * randomness;
|
||||
const float distanceToMidLeft = fabsf((midPointPosition + leftPointPosition) / 2.0f -
|
||||
localPosition);
|
||||
const float distanceToMidRight = fabsf((midPointPosition + rightPointPosition) / 2.0f -
|
||||
localPosition);
|
||||
|
||||
*r_distance = std::min(distanceToMidLeft, distanceToMidRight);
|
||||
}
|
||||
|
||||
void voronoi_n_sphere_radius(const float w, const float randomness, float *r_radius)
|
||||
{
|
||||
const float cellPosition = floorf(w);
|
||||
const float localPosition = w - cellPosition;
|
||||
|
||||
float closestPoint = 0.0f;
|
||||
float closestPointOffset = 0.0f;
|
||||
float minDistance = 8.0f;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float cellOffset = i;
|
||||
const float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * randomness;
|
||||
const float distanceToPoint = fabsf(pointPosition - localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0f;
|
||||
float closestPointToClosestPoint = 0.0f;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
if (i == 0) {
|
||||
continue;
|
||||
}
|
||||
const float cellOffset = i + closestPointOffset;
|
||||
const float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * randomness;
|
||||
const float distanceToPoint = fabsf(closestPoint - pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
*r_radius = fabsf(closestPointToClosestPoint - closestPoint) / 2.0f;
|
||||
}
|
||||
|
||||
/* **** 2D Voronoi **** */
|
||||
|
||||
static float voronoi_distance(const float2 a,
|
||||
const float2 b,
|
||||
const int metric,
|
||||
const float exponent)
|
||||
{
|
||||
switch (metric) {
|
||||
case NOISE_SHD_VORONOI_EUCLIDEAN:
|
||||
return float2::distance(a, b);
|
||||
case NOISE_SHD_VORONOI_MANHATTAN:
|
||||
return fabsf(a.x - b.x) + fabsf(a.y - b.y);
|
||||
case NOISE_SHD_VORONOI_CHEBYCHEV:
|
||||
return std::max(fabsf(a.x - b.x), fabsf(a.y - b.y));
|
||||
case NOISE_SHD_VORONOI_MINKOWSKI:
|
||||
return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent),
|
||||
1.0f / exponent);
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void voronoi_f1(const float2 coord,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float2 *r_position)
|
||||
{
|
||||
const float2 cellPosition = float2::floor(coord);
|
||||
const float2 localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0f;
|
||||
float2 targetOffset = float2(0.0f, 0.0f);
|
||||
float2 targetPosition = float2(0.0f, 0.0f);
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float2 cellOffset = float2(i, j);
|
||||
const float2 pointPosition = cellOffset +
|
||||
hash_float_to_float2(cellPosition + cellOffset) * randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
*r_distance = minDistance;
|
||||
*r_color = hash_float_to_float3(cellPosition + targetOffset);
|
||||
*r_position = targetPosition + cellPosition;
|
||||
}
|
||||
|
||||
void voronoi_smooth_f1(const float2 coord,
|
||||
const float smoothness,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float2 *r_position)
|
||||
{
|
||||
const float2 cellPosition = float2::floor(coord);
|
||||
const float2 localPosition = coord - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0f;
|
||||
float3 smoothColor = float3(0.0f, 0.0f, 0.0f);
|
||||
float2 smoothPosition = float2(0.0f, 0.0f);
|
||||
for (int j = -2; j <= 2; j++) {
|
||||
for (int i = -2; i <= 2; i++) {
|
||||
const float2 cellOffset = float2(i, j);
|
||||
const float2 pointPosition = cellOffset +
|
||||
hash_float_to_float2(cellPosition + cellOffset) * randomness;
|
||||
const float distanceToPoint = voronoi_distance(
|
||||
pointPosition, localPosition, metric, exponent);
|
||||
const float h = smoothstep(
|
||||
0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
|
||||
float correctionFactor = smoothness * h * (1.0f - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0f + 3.0f * smoothness;
|
||||
const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
|
||||
smoothColor = float3::interpolate(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = float2::interpolate(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
}
|
||||
*r_distance = smoothDistance;
|
||||
*r_color = smoothColor;
|
||||
*r_position = cellPosition + smoothPosition;
|
||||
}
|
||||
|
||||
void voronoi_f2(const float2 coord,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float2 *r_position)
|
||||
{
|
||||
const float2 cellPosition = float2::floor(coord);
|
||||
const float2 localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0f;
|
||||
float distanceF2 = 8.0f;
|
||||
float2 offsetF1 = float2(0.0f, 0.0f);
|
||||
float2 positionF1 = float2(0.0f, 0.0f);
|
||||
float2 offsetF2 = float2(0.0f, 0.0f);
|
||||
float2 positionF2 = float2(0.0f, 0.0f);
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float2 cellOffset = float2(i, j);
|
||||
const float2 pointPosition = cellOffset +
|
||||
hash_float_to_float2(cellPosition + cellOffset) * randomness;
|
||||
const float distanceToPoint = voronoi_distance(
|
||||
pointPosition, localPosition, metric, exponent);
|
||||
if (distanceToPoint < distanceF1) {
|
||||
distanceF2 = distanceF1;
|
||||
distanceF1 = distanceToPoint;
|
||||
offsetF2 = offsetF1;
|
||||
offsetF1 = cellOffset;
|
||||
positionF2 = positionF1;
|
||||
positionF1 = pointPosition;
|
||||
}
|
||||
else if (distanceToPoint < distanceF2) {
|
||||
distanceF2 = distanceToPoint;
|
||||
offsetF2 = cellOffset;
|
||||
positionF2 = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
*r_distance = distanceF2;
|
||||
*r_color = hash_float_to_float3(cellPosition + offsetF2);
|
||||
*r_position = positionF2 + cellPosition;
|
||||
}
|
||||
|
||||
void voronoi_distance_to_edge(const float2 coord, const float randomness, float *r_distance)
|
||||
{
|
||||
const float2 cellPosition = float2::floor(coord);
|
||||
const float2 localPosition = coord - cellPosition;
|
||||
|
||||
float2 vectorToClosest = float2(0.0f, 0.0f);
|
||||
float minDistance = 8.0f;
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float2 cellOffset = float2(i, j);
|
||||
const float2 vectorToPoint = cellOffset +
|
||||
hash_float_to_float2(cellPosition + cellOffset) * randomness -
|
||||
localPosition;
|
||||
const float distanceToPoint = dot_v2v2(vectorToPoint, vectorToPoint);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
vectorToClosest = vectorToPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0f;
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float2 cellOffset = float2(i, j);
|
||||
const float2 vectorToPoint = cellOffset +
|
||||
hash_float_to_float2(cellPosition + cellOffset) * randomness -
|
||||
localPosition;
|
||||
const float2 perpendicularToEdge = vectorToPoint - vectorToClosest;
|
||||
if (dot_v2v2(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
|
||||
const float distanceToEdge = dot_v2v2((vectorToClosest + vectorToPoint) / 2.0f,
|
||||
perpendicularToEdge.normalized());
|
||||
minDistance = std::min(minDistance, distanceToEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
*r_distance = minDistance;
|
||||
}
|
||||
|
||||
void voronoi_n_sphere_radius(const float2 coord, const float randomness, float *r_radius)
|
||||
{
|
||||
const float2 cellPosition = float2::floor(coord);
|
||||
const float2 localPosition = coord - cellPosition;
|
||||
|
||||
float2 closestPoint = float2(0.0f, 0.0f);
|
||||
float2 closestPointOffset = float2(0.0f, 0.0f);
|
||||
float minDistance = 8.0f;
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float2 cellOffset = float2(i, j);
|
||||
const float2 pointPosition = cellOffset +
|
||||
hash_float_to_float2(cellPosition + cellOffset) * randomness;
|
||||
const float distanceToPoint = float2::distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0f;
|
||||
float2 closestPointToClosestPoint = float2(0.0f, 0.0f);
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
if (i == 0 && j == 0) {
|
||||
continue;
|
||||
}
|
||||
const float2 cellOffset = float2(i, j) + closestPointOffset;
|
||||
const float2 pointPosition = cellOffset +
|
||||
hash_float_to_float2(cellPosition + cellOffset) * randomness;
|
||||
const float distanceToPoint = float2::distance(closestPoint, pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
*r_radius = float2::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
|
||||
}
|
||||
|
||||
/* **** 3D Voronoi **** */
|
||||
|
||||
static float voronoi_distance(const float3 a,
|
||||
const float3 b,
|
||||
const int metric,
|
||||
const float exponent)
|
||||
{
|
||||
switch (metric) {
|
||||
case NOISE_SHD_VORONOI_EUCLIDEAN:
|
||||
return float3::distance(a, b);
|
||||
case NOISE_SHD_VORONOI_MANHATTAN:
|
||||
return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z);
|
||||
case NOISE_SHD_VORONOI_CHEBYCHEV:
|
||||
return std::max(fabsf(a.x - b.x), std::max(fabsf(a.y - b.y), fabsf(a.z - b.z)));
|
||||
case NOISE_SHD_VORONOI_MINKOWSKI:
|
||||
return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent) +
|
||||
powf(fabsf(a.z - b.z), exponent),
|
||||
1.0f / exponent);
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void voronoi_f1(const float3 coord,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float3 *r_position)
|
||||
{
|
||||
const float3 cellPosition = float3::floor(coord);
|
||||
const float3 localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0f;
|
||||
float3 targetOffset = float3(0.0f, 0.0f, 0.0f);
|
||||
float3 targetPosition = float3(0.0f, 0.0f, 0.0f);
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float3 cellOffset = float3(i, j, k);
|
||||
const float3 pointPosition = cellOffset +
|
||||
hash_float_to_float3(cellPosition + cellOffset) * randomness;
|
||||
const float distanceToPoint = voronoi_distance(
|
||||
pointPosition, localPosition, metric, exponent);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*r_distance = minDistance;
|
||||
*r_color = hash_float_to_float3(cellPosition + targetOffset);
|
||||
*r_position = targetPosition + cellPosition;
|
||||
}
|
||||
|
||||
void voronoi_smooth_f1(const float3 coord,
|
||||
const float smoothness,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float3 *r_position)
|
||||
{
|
||||
const float3 cellPosition = float3::floor(coord);
|
||||
const float3 localPosition = coord - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0f;
|
||||
float3 smoothColor = float3(0.0f, 0.0f, 0.0f);
|
||||
float3 smoothPosition = float3(0.0f, 0.0f, 0.0f);
|
||||
for (int k = -2; k <= 2; k++) {
|
||||
for (int j = -2; j <= 2; j++) {
|
||||
for (int i = -2; i <= 2; i++) {
|
||||
const float3 cellOffset = float3(i, j, k);
|
||||
const float3 pointPosition = cellOffset +
|
||||
hash_float_to_float3(cellPosition + cellOffset) * randomness;
|
||||
const float distanceToPoint = voronoi_distance(
|
||||
pointPosition, localPosition, metric, exponent);
|
||||
const float h = smoothstep(
|
||||
0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
|
||||
float correctionFactor = smoothness * h * (1.0f - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0f + 3.0f * smoothness;
|
||||
const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
|
||||
smoothColor = float3::interpolate(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = float3::interpolate(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
*r_distance = smoothDistance;
|
||||
*r_color = smoothColor;
|
||||
*r_position = cellPosition + smoothPosition;
|
||||
}
|
||||
|
||||
void voronoi_f2(const float3 coord,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float3 *r_position)
|
||||
{
|
||||
const float3 cellPosition = float3::floor(coord);
|
||||
const float3 localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0f;
|
||||
float distanceF2 = 8.0f;
|
||||
float3 offsetF1 = float3(0.0f, 0.0f, 0.0f);
|
||||
float3 positionF1 = float3(0.0f, 0.0f, 0.0f);
|
||||
float3 offsetF2 = float3(0.0f, 0.0f, 0.0f);
|
||||
float3 positionF2 = float3(0.0f, 0.0f, 0.0f);
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float3 cellOffset = float3(i, j, k);
|
||||
const float3 pointPosition = cellOffset +
|
||||
hash_float_to_float3(cellPosition + cellOffset) * randomness;
|
||||
const float distanceToPoint = voronoi_distance(
|
||||
pointPosition, localPosition, metric, exponent);
|
||||
if (distanceToPoint < distanceF1) {
|
||||
distanceF2 = distanceF1;
|
||||
distanceF1 = distanceToPoint;
|
||||
offsetF2 = offsetF1;
|
||||
offsetF1 = cellOffset;
|
||||
positionF2 = positionF1;
|
||||
positionF1 = pointPosition;
|
||||
}
|
||||
else if (distanceToPoint < distanceF2) {
|
||||
distanceF2 = distanceToPoint;
|
||||
offsetF2 = cellOffset;
|
||||
positionF2 = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*r_distance = distanceF2;
|
||||
*r_color = hash_float_to_float3(cellPosition + offsetF2);
|
||||
*r_position = positionF2 + cellPosition;
|
||||
}
|
||||
|
||||
void voronoi_distance_to_edge(const float3 coord, const float randomness, float *r_distance)
|
||||
{
|
||||
const float3 cellPosition = float3::floor(coord);
|
||||
const float3 localPosition = coord - cellPosition;
|
||||
|
||||
float3 vectorToClosest = float3(0.0f, 0.0f, 0.0f);
|
||||
float minDistance = 8.0f;
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float3 cellOffset = float3(i, j, k);
|
||||
const float3 vectorToPoint = cellOffset +
|
||||
hash_float_to_float3(cellPosition + cellOffset) * randomness -
|
||||
localPosition;
|
||||
const float distanceToPoint = dot_v3v3(vectorToPoint, vectorToPoint);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
vectorToClosest = vectorToPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0f;
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float3 cellOffset = float3(i, j, k);
|
||||
const float3 vectorToPoint = cellOffset +
|
||||
hash_float_to_float3(cellPosition + cellOffset) * randomness -
|
||||
localPosition;
|
||||
const float3 perpendicularToEdge = vectorToPoint - vectorToClosest;
|
||||
if (dot_v3v3(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
|
||||
const float distanceToEdge = dot_v3v3((vectorToClosest + vectorToPoint) / 2.0f,
|
||||
perpendicularToEdge.normalized());
|
||||
minDistance = std::min(minDistance, distanceToEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*r_distance = minDistance;
|
||||
}
|
||||
|
||||
void voronoi_n_sphere_radius(const float3 coord, const float randomness, float *r_radius)
|
||||
{
|
||||
const float3 cellPosition = float3::floor(coord);
|
||||
const float3 localPosition = coord - cellPosition;
|
||||
|
||||
float3 closestPoint = float3(0.0f, 0.0f, 0.0f);
|
||||
float3 closestPointOffset = float3(0.0f, 0.0f, 0.0f);
|
||||
float minDistance = 8.0f;
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float3 cellOffset = float3(i, j, k);
|
||||
const float3 pointPosition = cellOffset +
|
||||
hash_float_to_float3(cellPosition + cellOffset) * randomness;
|
||||
const float distanceToPoint = float3::distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0f;
|
||||
float3 closestPointToClosestPoint = float3(0.0f, 0.0f, 0.0f);
|
||||
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;
|
||||
}
|
||||
const float3 cellOffset = float3(i, j, k) + closestPointOffset;
|
||||
const float3 pointPosition = cellOffset +
|
||||
hash_float_to_float3(cellPosition + cellOffset) * randomness;
|
||||
const float distanceToPoint = float3::distance(closestPoint, pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*r_radius = float3::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
|
||||
}
|
||||
|
||||
/* **** 4D Voronoi **** */
|
||||
|
||||
static float voronoi_distance(const float4 a,
|
||||
const float4 b,
|
||||
const int metric,
|
||||
const float exponent)
|
||||
{
|
||||
switch (metric) {
|
||||
case NOISE_SHD_VORONOI_EUCLIDEAN:
|
||||
return float4::distance(a, b);
|
||||
case NOISE_SHD_VORONOI_MANHATTAN:
|
||||
return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z) + fabsf(a.w - b.w);
|
||||
case NOISE_SHD_VORONOI_CHEBYCHEV:
|
||||
return std::max(fabsf(a.x - b.x),
|
||||
std::max(fabsf(a.y - b.y), std::max(fabsf(a.z - b.z), fabsf(a.w - b.w))));
|
||||
case NOISE_SHD_VORONOI_MINKOWSKI:
|
||||
return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent) +
|
||||
powf(fabsf(a.z - b.z), exponent) + powf(fabsf(a.w - b.w), exponent),
|
||||
1.0f / exponent);
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void voronoi_f1(const float4 coord,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float4 *r_position)
|
||||
{
|
||||
const float4 cellPosition = float4::floor(coord);
|
||||
const float4 localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0f;
|
||||
float4 targetOffset = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
float4 targetPosition = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float4 cellOffset = float4(i, j, k, u);
|
||||
const float4 pointPosition = cellOffset +
|
||||
hash_float_to_float4(cellPosition + cellOffset) *
|
||||
randomness;
|
||||
const float distanceToPoint = voronoi_distance(
|
||||
pointPosition, localPosition, metric, exponent);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*r_distance = minDistance;
|
||||
*r_color = hash_float_to_float3(cellPosition + targetOffset);
|
||||
*r_position = targetPosition + cellPosition;
|
||||
}
|
||||
|
||||
void voronoi_smooth_f1(const float4 coord,
|
||||
const float smoothness,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float4 *r_position)
|
||||
{
|
||||
const float4 cellPosition = float4::floor(coord);
|
||||
const float4 localPosition = coord - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0f;
|
||||
float3 smoothColor = float3(0.0f, 0.0f, 0.0f);
|
||||
float4 smoothPosition = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
for (int u = -2; u <= 2; u++) {
|
||||
for (int k = -2; k <= 2; k++) {
|
||||
for (int j = -2; j <= 2; j++) {
|
||||
for (int i = -2; i <= 2; i++) {
|
||||
const float4 cellOffset = float4(i, j, k, u);
|
||||
const float4 pointPosition = cellOffset +
|
||||
hash_float_to_float4(cellPosition + cellOffset) *
|
||||
randomness;
|
||||
const float distanceToPoint = voronoi_distance(
|
||||
pointPosition, localPosition, metric, exponent);
|
||||
const float h = smoothstep(
|
||||
0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / smoothness);
|
||||
float correctionFactor = smoothness * h * (1.0f - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0f + 3.0f * smoothness;
|
||||
const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
|
||||
smoothColor = float3::interpolate(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = float4::interpolate(smoothPosition, pointPosition, h) -
|
||||
correctionFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*r_distance = smoothDistance;
|
||||
*r_color = smoothColor;
|
||||
*r_position = cellPosition + smoothPosition;
|
||||
}
|
||||
|
||||
void voronoi_f2(const float4 coord,
|
||||
const float exponent,
|
||||
const float randomness,
|
||||
const int metric,
|
||||
float *r_distance,
|
||||
float3 *r_color,
|
||||
float4 *r_position)
|
||||
{
|
||||
const float4 cellPosition = float4::floor(coord);
|
||||
const float4 localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0f;
|
||||
float distanceF2 = 8.0f;
|
||||
float4 offsetF1 = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
float4 positionF1 = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
float4 offsetF2 = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
float4 positionF2 = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float4 cellOffset = float4(i, j, k, u);
|
||||
const float4 pointPosition = cellOffset +
|
||||
hash_float_to_float4(cellPosition + cellOffset) *
|
||||
randomness;
|
||||
const float distanceToPoint = voronoi_distance(
|
||||
pointPosition, localPosition, metric, exponent);
|
||||
if (distanceToPoint < distanceF1) {
|
||||
distanceF2 = distanceF1;
|
||||
distanceF1 = distanceToPoint;
|
||||
offsetF2 = offsetF1;
|
||||
offsetF1 = cellOffset;
|
||||
positionF2 = positionF1;
|
||||
positionF1 = pointPosition;
|
||||
}
|
||||
else if (distanceToPoint < distanceF2) {
|
||||
distanceF2 = distanceToPoint;
|
||||
offsetF2 = cellOffset;
|
||||
positionF2 = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*r_distance = distanceF2;
|
||||
*r_color = hash_float_to_float3(cellPosition + offsetF2);
|
||||
*r_position = positionF2 + cellPosition;
|
||||
}
|
||||
|
||||
void voronoi_distance_to_edge(const float4 coord, const float randomness, float *r_distance)
|
||||
{
|
||||
const float4 cellPosition = float4::floor(coord);
|
||||
const float4 localPosition = coord - cellPosition;
|
||||
|
||||
float4 vectorToClosest = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
float minDistance = 8.0f;
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float4 cellOffset = float4(i, j, k, u);
|
||||
const float4 vectorToPoint = cellOffset +
|
||||
hash_float_to_float4(cellPosition + cellOffset) *
|
||||
randomness -
|
||||
localPosition;
|
||||
const float distanceToPoint = dot_v4v4(vectorToPoint, vectorToPoint);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
vectorToClosest = vectorToPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0f;
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float4 cellOffset = float4(i, j, k, u);
|
||||
const float4 vectorToPoint = cellOffset +
|
||||
hash_float_to_float4(cellPosition + cellOffset) *
|
||||
randomness -
|
||||
localPosition;
|
||||
const float4 perpendicularToEdge = vectorToPoint - vectorToClosest;
|
||||
if (dot_v4v4(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
|
||||
const float distanceToEdge = dot_v4v4((vectorToClosest + vectorToPoint) / 2.0f,
|
||||
float4::normalize(perpendicularToEdge));
|
||||
minDistance = std::min(minDistance, distanceToEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*r_distance = minDistance;
|
||||
}
|
||||
|
||||
void voronoi_n_sphere_radius(const float4 coord, const float randomness, float *r_radius)
|
||||
{
|
||||
const float4 cellPosition = float4::floor(coord);
|
||||
const float4 localPosition = coord - cellPosition;
|
||||
|
||||
float4 closestPoint = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
float4 closestPointOffset = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
float minDistance = 8.0f;
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
const float4 cellOffset = float4(i, j, k, u);
|
||||
const float4 pointPosition = cellOffset +
|
||||
hash_float_to_float4(cellPosition + cellOffset) *
|
||||
randomness;
|
||||
const float distanceToPoint = float4::distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0f;
|
||||
float4 closestPointToClosestPoint = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
if (i == 0 && j == 0 && k == 0 && u == 0) {
|
||||
continue;
|
||||
}
|
||||
const float4 cellOffset = float4(i, j, k, u) + closestPointOffset;
|
||||
const float4 pointPosition = cellOffset +
|
||||
hash_float_to_float4(cellPosition + cellOffset) *
|
||||
randomness;
|
||||
const float distanceToPoint = float4::distance(closestPoint, pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*r_radius = float4::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
|
||||
}
|
||||
|
||||
} // namespace blender::noise
|
||||
|
|
|
@ -333,6 +333,7 @@ static void get_socket_value(const SocketRef &socket, void *r_value)
|
|||
GEO_NODE_SET_POSITION,
|
||||
SH_NODE_TEX_GRADIENT,
|
||||
SH_NODE_TEX_NOISE,
|
||||
SH_NODE_TEX_VORONOI,
|
||||
SH_NODE_TEX_WHITE_NOISE,
|
||||
GEO_NODE_MESH_TO_POINTS,
|
||||
GEO_NODE_PROXIMITY)) {
|
||||
|
|
|
@ -19,12 +19,14 @@
|
|||
|
||||
#include "../node_shader_util.h"
|
||||
|
||||
#include "BLI_noise.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
static void sh_node_tex_voronoi_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.is_function_node();
|
||||
b.add_input<decl::Vector>("Vector").hide_value();
|
||||
b.add_input<decl::Vector>("Vector").hide_value().implicit_field();
|
||||
b.add_input<decl::Float>("W").min(-1000.0f).max(1000.0f);
|
||||
b.add_input<decl::Float>("Scale").min(-1000.0f).max(1000.0f).default_value(5.0f);
|
||||
b.add_input<decl::Float>("Smoothness")
|
||||
|
@ -143,6 +145,7 @@ static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node
|
|||
tex->distance == SHD_VORONOI_MINKOWSKI && tex->dimensions != 1 &&
|
||||
!ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS));
|
||||
nodeSetSocketAvailability(inSmoothnessSock, tex->feature == SHD_VORONOI_SMOOTH_F1);
|
||||
|
||||
nodeSetSocketAvailability(outDistanceSock, tex->feature != SHD_VORONOI_N_SPHERE_RADIUS);
|
||||
nodeSetSocketAvailability(outColorSock,
|
||||
tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
|
||||
|
@ -158,17 +161,921 @@ static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node
|
|||
nodeSetSocketAvailability(outRadiusSock, tex->feature == SHD_VORONOI_N_SPHERE_RADIUS);
|
||||
}
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
class VoronoiMinowskiFunction : public fn::MultiFunction {
|
||||
private:
|
||||
int dimensions_;
|
||||
int feature_;
|
||||
|
||||
public:
|
||||
VoronoiMinowskiFunction(int dimensions, int feature) : dimensions_(dimensions), feature_(feature)
|
||||
{
|
||||
BLI_assert(dimensions >= 2 && dimensions <= 4);
|
||||
BLI_assert(feature >= 0 && feature <= 2);
|
||||
static std::array<fn::MFSignature, 9> signatures{
|
||||
create_signature(2, SHD_VORONOI_F1),
|
||||
create_signature(3, SHD_VORONOI_F1),
|
||||
create_signature(4, SHD_VORONOI_F1),
|
||||
|
||||
create_signature(2, SHD_VORONOI_F2),
|
||||
create_signature(3, SHD_VORONOI_F2),
|
||||
create_signature(4, SHD_VORONOI_F2),
|
||||
|
||||
create_signature(2, SHD_VORONOI_SMOOTH_F1),
|
||||
create_signature(3, SHD_VORONOI_SMOOTH_F1),
|
||||
create_signature(4, SHD_VORONOI_SMOOTH_F1),
|
||||
};
|
||||
this->set_signature(&signatures[(dimensions - 1) + feature * 3 - 1]);
|
||||
}
|
||||
|
||||
static fn::MFSignature create_signature(int dimensions, int feature)
|
||||
{
|
||||
fn::MFSignatureBuilder signature{"voronoi_minowski"};
|
||||
|
||||
if (ELEM(dimensions, 2, 3, 4)) {
|
||||
signature.single_input<float3>("Vector");
|
||||
}
|
||||
if (ELEM(dimensions, 1, 4)) {
|
||||
signature.single_input<float>("W");
|
||||
}
|
||||
signature.single_input<float>("Scale");
|
||||
if (feature == SHD_VORONOI_SMOOTH_F1) {
|
||||
signature.single_input<float>("Smoothness");
|
||||
}
|
||||
signature.single_input<float>("Exponent");
|
||||
signature.single_input<float>("Randomness");
|
||||
signature.single_output<float>("Distance");
|
||||
signature.single_output<ColorGeometry4f>("Color");
|
||||
|
||||
if (dimensions != 1) {
|
||||
signature.single_output<float3>("Position");
|
||||
}
|
||||
if ((dimensions == 1 || dimensions == 4)) {
|
||||
signature.single_output<float>("W");
|
||||
}
|
||||
|
||||
return signature.build();
|
||||
}
|
||||
|
||||
void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
|
||||
{
|
||||
auto get_vector = [&](int param_index) -> const VArray<float3> & {
|
||||
return params.readonly_single_input<float3>(param_index, "Vector");
|
||||
};
|
||||
auto get_w = [&](int param_index) -> const VArray<float> & {
|
||||
return params.readonly_single_input<float>(param_index, "W");
|
||||
};
|
||||
auto get_scale = [&](int param_index) -> const VArray<float> & {
|
||||
return params.readonly_single_input<float>(param_index, "Scale");
|
||||
};
|
||||
auto get_smoothness = [&](int param_index) -> const VArray<float> & {
|
||||
return params.readonly_single_input<float>(param_index, "Smoothness");
|
||||
};
|
||||
auto get_exponent = [&](int param_index) -> const VArray<float> & {
|
||||
return params.readonly_single_input<float>(param_index, "Exponent");
|
||||
};
|
||||
auto get_randomness = [&](int param_index) -> const VArray<float> & {
|
||||
return params.readonly_single_input<float>(param_index, "Randomness");
|
||||
};
|
||||
auto get_r_distance = [&](int param_index) -> MutableSpan<float> {
|
||||
return params.uninitialized_single_output<float>(param_index, "Distance");
|
||||
};
|
||||
auto get_r_color = [&](int param_index) -> MutableSpan<ColorGeometry4f> {
|
||||
return params.uninitialized_single_output<ColorGeometry4f>(param_index, "Color");
|
||||
};
|
||||
auto get_r_position = [&](int param_index) -> MutableSpan<float3> {
|
||||
return params.uninitialized_single_output<float3>(param_index, "Position");
|
||||
};
|
||||
auto get_r_w = [&](int param_index) -> MutableSpan<float> {
|
||||
return params.uninitialized_single_output<float>(param_index, "W");
|
||||
};
|
||||
|
||||
int param = 0;
|
||||
switch (dimensions_) {
|
||||
case 2: {
|
||||
switch (feature_) {
|
||||
case SHD_VORONOI_F1: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &exponent = get_exponent(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
float3 col;
|
||||
float2 pos;
|
||||
noise::voronoi_f1(float2(vector[i].x, vector[i].y) * scale[i],
|
||||
exponent[i],
|
||||
rand,
|
||||
SHD_VORONOI_MINKOWSKI,
|
||||
&r_distance[i],
|
||||
&col,
|
||||
&pos);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
pos = float2::safe_divide(pos, scale[i]);
|
||||
r_position[i] = float3(pos.x, pos.y, 0.0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_F2: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &exponent = get_exponent(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
float3 col;
|
||||
float2 pos;
|
||||
noise::voronoi_f2(float2(vector[i].x, vector[i].y) * scale[i],
|
||||
exponent[i],
|
||||
rand,
|
||||
SHD_VORONOI_MINKOWSKI,
|
||||
&r_distance[i],
|
||||
&col,
|
||||
&pos);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
pos = float2::safe_divide(pos, scale[i]);
|
||||
r_position[i] = float3(pos.x, pos.y, 0.0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_SMOOTH_F1: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &smoothness = get_smoothness(param++);
|
||||
const VArray<float> &exponent = get_exponent(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
float3 col;
|
||||
float2 pos;
|
||||
noise::voronoi_smooth_f1(float2(vector[i].x, vector[i].y) * scale[i],
|
||||
smth,
|
||||
exponent[i],
|
||||
rand,
|
||||
SHD_VORONOI_MINKOWSKI,
|
||||
&r_distance[i],
|
||||
&col,
|
||||
&pos);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
pos = float2::safe_divide(pos, scale[i]);
|
||||
r_position[i] = float3(pos.x, pos.y, 0.0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
switch (feature_) {
|
||||
case SHD_VORONOI_F1: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &exponent = get_exponent(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
float3 col;
|
||||
noise::voronoi_f1(vector[i] * scale[i],
|
||||
exponent[i],
|
||||
rand,
|
||||
SHD_VORONOI_MINKOWSKI,
|
||||
&r_distance[i],
|
||||
&col,
|
||||
&r_position[i]);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
r_position[i] = float3::safe_divide(r_position[i], scale[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_F2: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &exponent = get_exponent(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
float3 col;
|
||||
noise::voronoi_f2(vector[i] * scale[i],
|
||||
exponent[i],
|
||||
rand,
|
||||
SHD_VORONOI_MINKOWSKI,
|
||||
&r_distance[i],
|
||||
&col,
|
||||
&r_position[i]);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
r_position[i] = float3::safe_divide(r_position[i], scale[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_SMOOTH_F1: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &smoothness = get_smoothness(param++);
|
||||
const VArray<float> &exponent = get_exponent(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
float3 col;
|
||||
noise::voronoi_smooth_f1(vector[i] * scale[i],
|
||||
smth,
|
||||
exponent[i],
|
||||
rand,
|
||||
SHD_VORONOI_MINKOWSKI,
|
||||
&r_distance[i],
|
||||
&col,
|
||||
&r_position[i]);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
r_position[i] = float3::safe_divide(r_position[i], scale[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
switch (feature_) {
|
||||
case SHD_VORONOI_F1: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &w = get_w(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &exponent = get_exponent(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
MutableSpan<float> r_w = get_r_w(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
|
||||
float3 col;
|
||||
float4 pos;
|
||||
noise::voronoi_f1(p, exponent[i], rand, SHD_VORONOI_F1, &r_distance[i], &col, &pos);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
pos = float4::safe_divide(pos, scale[i]);
|
||||
r_position[i] = float3(pos.x, pos.y, pos.z);
|
||||
r_w[i] = pos.w;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_F2: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &w = get_w(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &exponent = get_exponent(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
MutableSpan<float> r_w = get_r_w(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
|
||||
float3 col;
|
||||
float4 pos;
|
||||
noise::voronoi_f2(
|
||||
p, exponent[i], rand, SHD_VORONOI_MINKOWSKI, &r_distance[i], &col, &pos);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
pos = float4::safe_divide(pos, scale[i]);
|
||||
r_position[i] = float3(pos.x, pos.y, pos.z);
|
||||
r_w[i] = pos.w;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_SMOOTH_F1: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &w = get_w(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &smoothness = get_smoothness(param++);
|
||||
const VArray<float> &exponent = get_exponent(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
MutableSpan<float> r_w = get_r_w(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
|
||||
float3 col;
|
||||
float4 pos;
|
||||
noise::voronoi_smooth_f1(
|
||||
p, smth, exponent[i], rand, SHD_VORONOI_MINKOWSKI, &r_distance[i], &col, &pos);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
pos = float4::safe_divide(pos, scale[i]);
|
||||
r_position[i] = float3(pos.x, pos.y, pos.z);
|
||||
r_w[i] = pos.w;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class VoronoiMetricFunction : public fn::MultiFunction {
|
||||
private:
|
||||
int dimensions_;
|
||||
int feature_;
|
||||
int metric_;
|
||||
|
||||
public:
|
||||
VoronoiMetricFunction(int dimensions, int feature, int metric)
|
||||
: dimensions_(dimensions), feature_(feature), metric_(metric)
|
||||
{
|
||||
BLI_assert(dimensions >= 1 && dimensions <= 4);
|
||||
BLI_assert(feature >= 0 && feature <= 4);
|
||||
static std::array<fn::MFSignature, 12> signatures{
|
||||
create_signature(1, SHD_VORONOI_F1),
|
||||
create_signature(2, SHD_VORONOI_F1),
|
||||
create_signature(3, SHD_VORONOI_F1),
|
||||
create_signature(4, SHD_VORONOI_F1),
|
||||
|
||||
create_signature(1, SHD_VORONOI_F2),
|
||||
create_signature(2, SHD_VORONOI_F2),
|
||||
create_signature(3, SHD_VORONOI_F2),
|
||||
create_signature(4, SHD_VORONOI_F2),
|
||||
|
||||
create_signature(1, SHD_VORONOI_SMOOTH_F1),
|
||||
create_signature(2, SHD_VORONOI_SMOOTH_F1),
|
||||
create_signature(3, SHD_VORONOI_SMOOTH_F1),
|
||||
create_signature(4, SHD_VORONOI_SMOOTH_F1),
|
||||
};
|
||||
this->set_signature(&signatures[dimensions + feature * 4 - 1]);
|
||||
}
|
||||
|
||||
static fn::MFSignature create_signature(int dimensions, int feature)
|
||||
{
|
||||
fn::MFSignatureBuilder signature{"voronoi_metric"};
|
||||
|
||||
if (ELEM(dimensions, 2, 3, 4)) {
|
||||
signature.single_input<float3>("Vector");
|
||||
}
|
||||
if (ELEM(dimensions, 1, 4)) {
|
||||
signature.single_input<float>("W");
|
||||
}
|
||||
signature.single_input<float>("Scale");
|
||||
if (feature == SHD_VORONOI_SMOOTH_F1) {
|
||||
signature.single_input<float>("Smoothness");
|
||||
}
|
||||
signature.single_input<float>("Randomness");
|
||||
signature.single_output<float>("Distance");
|
||||
signature.single_output<ColorGeometry4f>("Color");
|
||||
|
||||
if (dimensions != 1) {
|
||||
signature.single_output<float3>("Position");
|
||||
}
|
||||
if ((dimensions == 1 || dimensions == 4)) {
|
||||
signature.single_output<float>("W");
|
||||
}
|
||||
|
||||
return signature.build();
|
||||
}
|
||||
|
||||
void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
|
||||
{
|
||||
auto get_vector = [&](int param_index) -> const VArray<float3> & {
|
||||
return params.readonly_single_input<float3>(param_index, "Vector");
|
||||
};
|
||||
auto get_w = [&](int param_index) -> const VArray<float> & {
|
||||
return params.readonly_single_input<float>(param_index, "W");
|
||||
};
|
||||
auto get_scale = [&](int param_index) -> const VArray<float> & {
|
||||
return params.readonly_single_input<float>(param_index, "Scale");
|
||||
};
|
||||
auto get_smoothness = [&](int param_index) -> const VArray<float> & {
|
||||
return params.readonly_single_input<float>(param_index, "Smoothness");
|
||||
};
|
||||
auto get_randomness = [&](int param_index) -> const VArray<float> & {
|
||||
return params.readonly_single_input<float>(param_index, "Randomness");
|
||||
};
|
||||
auto get_r_distance = [&](int param_index) -> MutableSpan<float> {
|
||||
return params.uninitialized_single_output<float>(param_index, "Distance");
|
||||
};
|
||||
auto get_r_color = [&](int param_index) -> MutableSpan<ColorGeometry4f> {
|
||||
return params.uninitialized_single_output<ColorGeometry4f>(param_index, "Color");
|
||||
};
|
||||
auto get_r_position = [&](int param_index) -> MutableSpan<float3> {
|
||||
return params.uninitialized_single_output<float3>(param_index, "Position");
|
||||
};
|
||||
auto get_r_w = [&](int param_index) -> MutableSpan<float> {
|
||||
return params.uninitialized_single_output<float>(param_index, "W");
|
||||
};
|
||||
|
||||
int param = 0;
|
||||
switch (dimensions_) {
|
||||
case 1: {
|
||||
switch (feature_) {
|
||||
case SHD_VORONOI_F1: {
|
||||
const VArray<float> &w = get_w(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float> r_w = get_r_w(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float p = w[i] * scale[i];
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
float3 col;
|
||||
noise::voronoi_f1(p, rand, &r_distance[i], &col, &r_w[i]);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
r_w[i] = safe_divide(r_w[i], scale[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_F2: {
|
||||
const VArray<float> &w = get_w(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float> r_w = get_r_w(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float p = w[i] * scale[i];
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
float3 col;
|
||||
noise::voronoi_f2(p, rand, &r_distance[i], &col, &r_w[i]);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
r_w[i] = safe_divide(r_w[i], scale[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_SMOOTH_F1: {
|
||||
const VArray<float> &w = get_w(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &smoothness = get_smoothness(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float> r_w = get_r_w(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float p = w[i] * scale[i];
|
||||
const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
float3 col;
|
||||
noise::voronoi_smooth_f1(p, smth, rand, &r_distance[i], &col, &r_w[i]);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
r_w[i] = safe_divide(r_w[i], scale[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
switch (feature_) {
|
||||
case SHD_VORONOI_F1: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
float3 col;
|
||||
float2 pos;
|
||||
noise::voronoi_f1(float2(vector[i].x, vector[i].y) * scale[i],
|
||||
0.0f,
|
||||
rand,
|
||||
metric_,
|
||||
&r_distance[i],
|
||||
&col,
|
||||
&pos);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
pos = float2::safe_divide(pos, scale[i]);
|
||||
r_position[i] = float3(pos.x, pos.y, 0.0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_F2: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
float3 col;
|
||||
float2 pos;
|
||||
noise::voronoi_f2(float2(vector[i].x, vector[i].y) * scale[i],
|
||||
0.0f,
|
||||
rand,
|
||||
metric_,
|
||||
&r_distance[i],
|
||||
&col,
|
||||
&pos);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
pos = float2::safe_divide(pos, scale[i]);
|
||||
r_position[i] = float3(pos.x, pos.y, 0.0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_SMOOTH_F1: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &smoothness = get_smoothness(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
float3 col;
|
||||
float2 pos;
|
||||
noise::voronoi_smooth_f1(float2(vector[i].x, vector[i].y) * scale[i],
|
||||
smth,
|
||||
0.0f,
|
||||
rand,
|
||||
metric_,
|
||||
&r_distance[i],
|
||||
&col,
|
||||
&pos);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
pos = float2::safe_divide(pos, scale[i]);
|
||||
r_position[i] = float3(pos.x, pos.y, 0.0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
switch (feature_) {
|
||||
case SHD_VORONOI_F1: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
float3 col;
|
||||
noise::voronoi_f1(
|
||||
vector[i] * scale[i], 0.0f, rand, metric_, &r_distance[i], &col, &r_position[i]);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
r_position[i] = float3::safe_divide(r_position[i], scale[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_F2: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
float3 col;
|
||||
noise::voronoi_f2(
|
||||
vector[i] * scale[i], 0.0f, rand, metric_, &r_distance[i], &col, &r_position[i]);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
r_position[i] = float3::safe_divide(r_position[i], scale[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_SMOOTH_F1: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &smoothness = get_smoothness(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
float3 col;
|
||||
noise::voronoi_smooth_f1(vector[i] * scale[i],
|
||||
smth,
|
||||
0.0f,
|
||||
rand,
|
||||
metric_,
|
||||
&r_distance[i],
|
||||
&col,
|
||||
&r_position[i]);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
r_position[i] = float3::safe_divide(r_position[i], scale[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
switch (feature_) {
|
||||
case SHD_VORONOI_F1: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &w = get_w(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
MutableSpan<float> r_w = get_r_w(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
|
||||
float3 col;
|
||||
float4 pos;
|
||||
noise::voronoi_f1(p, 0.0f, rand, metric_, &r_distance[i], &col, &pos);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
pos = float4::safe_divide(pos, scale[i]);
|
||||
r_position[i] = float3(pos.x, pos.y, pos.z);
|
||||
r_w[i] = pos.w;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_F2: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &w = get_w(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
MutableSpan<float> r_w = get_r_w(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
|
||||
float3 col;
|
||||
float4 pos;
|
||||
noise::voronoi_f2(p, 0.0f, rand, metric_, &r_distance[i], &col, &pos);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
pos = float4::safe_divide(pos, scale[i]);
|
||||
r_position[i] = float3(pos.x, pos.y, pos.z);
|
||||
r_w[i] = pos.w;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_SMOOTH_F1: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &w = get_w(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &smoothness = get_smoothness(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
MutableSpan<ColorGeometry4f> r_color = get_r_color(param++);
|
||||
MutableSpan<float3> r_position = get_r_position(param++);
|
||||
MutableSpan<float> r_w = get_r_w(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float smth = std::min(std::max(smoothness[i] / 2.0f, 0.0f), 0.5f);
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
|
||||
float3 col;
|
||||
float4 pos;
|
||||
noise::voronoi_smooth_f1(p, smth, 0.0f, rand, metric_, &r_distance[i], &col, &pos);
|
||||
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
|
||||
pos = float4::safe_divide(pos, scale[i]);
|
||||
r_position[i] = float3(pos.x, pos.y, pos.z);
|
||||
r_w[i] = pos.w;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class VoronoiEdgeFunction : public fn::MultiFunction {
|
||||
private:
|
||||
int dimensions_;
|
||||
int feature_;
|
||||
|
||||
public:
|
||||
VoronoiEdgeFunction(int dimensions, int feature) : dimensions_(dimensions), feature_(feature)
|
||||
{
|
||||
BLI_assert(dimensions >= 1 && dimensions <= 4);
|
||||
BLI_assert(feature >= 3 && feature <= 4);
|
||||
static std::array<fn::MFSignature, 8> signatures{
|
||||
create_signature(1, SHD_VORONOI_DISTANCE_TO_EDGE),
|
||||
create_signature(2, SHD_VORONOI_DISTANCE_TO_EDGE),
|
||||
create_signature(3, SHD_VORONOI_DISTANCE_TO_EDGE),
|
||||
create_signature(4, SHD_VORONOI_DISTANCE_TO_EDGE),
|
||||
|
||||
create_signature(1, SHD_VORONOI_N_SPHERE_RADIUS),
|
||||
create_signature(2, SHD_VORONOI_N_SPHERE_RADIUS),
|
||||
create_signature(3, SHD_VORONOI_N_SPHERE_RADIUS),
|
||||
create_signature(4, SHD_VORONOI_N_SPHERE_RADIUS),
|
||||
};
|
||||
this->set_signature(&signatures[dimensions + (feature - 3) * 4 - 1]);
|
||||
}
|
||||
|
||||
static fn::MFSignature create_signature(int dimensions, int feature)
|
||||
{
|
||||
fn::MFSignatureBuilder signature{"voronoi_edge"};
|
||||
|
||||
if (ELEM(dimensions, 2, 3, 4)) {
|
||||
signature.single_input<float3>("Vector");
|
||||
}
|
||||
if (ELEM(dimensions, 1, 4)) {
|
||||
signature.single_input<float>("W");
|
||||
}
|
||||
signature.single_input<float>("Scale");
|
||||
signature.single_input<float>("Randomness");
|
||||
|
||||
if (feature == SHD_VORONOI_DISTANCE_TO_EDGE) {
|
||||
signature.single_output<float>("Distance");
|
||||
}
|
||||
if (feature == SHD_VORONOI_N_SPHERE_RADIUS) {
|
||||
signature.single_output<float>("Radius");
|
||||
}
|
||||
|
||||
return signature.build();
|
||||
}
|
||||
|
||||
void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
|
||||
{
|
||||
auto get_vector = [&](int param_index) -> const VArray<float3> & {
|
||||
return params.readonly_single_input<float3>(param_index, "Vector");
|
||||
};
|
||||
auto get_w = [&](int param_index) -> const VArray<float> & {
|
||||
return params.readonly_single_input<float>(param_index, "W");
|
||||
};
|
||||
auto get_scale = [&](int param_index) -> const VArray<float> & {
|
||||
return params.readonly_single_input<float>(param_index, "Scale");
|
||||
};
|
||||
auto get_randomness = [&](int param_index) -> const VArray<float> & {
|
||||
return params.readonly_single_input<float>(param_index, "Randomness");
|
||||
};
|
||||
auto get_r_distance = [&](int param_index) -> MutableSpan<float> {
|
||||
return params.uninitialized_single_output<float>(param_index, "Distance");
|
||||
};
|
||||
auto get_r_radius = [&](int param_index) -> MutableSpan<float> {
|
||||
return params.uninitialized_single_output<float>(param_index, "Radius");
|
||||
};
|
||||
|
||||
int param = 0;
|
||||
switch (dimensions_) {
|
||||
case 1: {
|
||||
const VArray<float> &w = get_w(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
switch (feature_) {
|
||||
case SHD_VORONOI_DISTANCE_TO_EDGE: {
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
const float p = w[i] * scale[i];
|
||||
noise::voronoi_distance_to_edge(p, rand, &r_distance[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_N_SPHERE_RADIUS: {
|
||||
MutableSpan<float> r_radius = get_r_radius(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
const float p = w[i] * scale[i];
|
||||
noise::voronoi_n_sphere_radius(p, rand, &r_radius[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
switch (feature_) {
|
||||
case SHD_VORONOI_DISTANCE_TO_EDGE: {
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
const float2 p = float2(vector[i].x, vector[i].y) * scale[i];
|
||||
noise::voronoi_distance_to_edge(p, rand, &r_distance[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_N_SPHERE_RADIUS: {
|
||||
MutableSpan<float> r_radius = get_r_radius(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
const float2 p = float2(vector[i].x, vector[i].y) * scale[i];
|
||||
noise::voronoi_n_sphere_radius(p, rand, &r_radius[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
switch (feature_) {
|
||||
case SHD_VORONOI_DISTANCE_TO_EDGE: {
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
noise::voronoi_distance_to_edge(vector[i] * scale[i], rand, &r_distance[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_N_SPHERE_RADIUS: {
|
||||
MutableSpan<float> r_radius = get_r_radius(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
noise::voronoi_n_sphere_radius(vector[i] * scale[i], rand, &r_radius[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
const VArray<float3> &vector = get_vector(param++);
|
||||
const VArray<float> &w = get_w(param++);
|
||||
const VArray<float> &scale = get_scale(param++);
|
||||
const VArray<float> &randomness = get_randomness(param++);
|
||||
switch (feature_) {
|
||||
case SHD_VORONOI_DISTANCE_TO_EDGE: {
|
||||
MutableSpan<float> r_distance = get_r_distance(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
|
||||
noise::voronoi_distance_to_edge(p, rand, &r_distance[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHD_VORONOI_N_SPHERE_RADIUS: {
|
||||
MutableSpan<float> r_radius = get_r_radius(param++);
|
||||
for (int64_t i : mask) {
|
||||
const float rand = std::min(std::max(randomness[i], 0.0f), 1.0f);
|
||||
const float4 p = float4(vector[i].x, vector[i].y, vector[i].z, w[i]) * scale[i];
|
||||
noise::voronoi_n_sphere_radius(p, rand, &r_radius[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
static void sh_node_voronoi_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
|
||||
{
|
||||
bNode &node = builder.node();
|
||||
NodeTexVoronoi *tex = (NodeTexVoronoi *)node.storage;
|
||||
bool minowski = (tex->distance == SHD_VORONOI_MINKOWSKI && tex->dimensions != 1 &&
|
||||
!ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS));
|
||||
bool dist_radius = (tex->feature == SHD_VORONOI_DISTANCE_TO_EDGE ||
|
||||
tex->feature == SHD_VORONOI_N_SPHERE_RADIUS);
|
||||
if (dist_radius) {
|
||||
builder.construct_and_set_matching_fn<VoronoiEdgeFunction>(tex->dimensions, tex->feature);
|
||||
}
|
||||
else if (minowski) {
|
||||
builder.construct_and_set_matching_fn<VoronoiMinowskiFunction>(tex->dimensions, tex->feature);
|
||||
}
|
||||
else {
|
||||
builder.construct_and_set_matching_fn<VoronoiMetricFunction>(
|
||||
tex->dimensions, tex->feature, tex->distance);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
void register_node_type_sh_tex_voronoi(void)
|
||||
{
|
||||
static bNodeType ntype;
|
||||
|
||||
sh_node_type_base(&ntype, SH_NODE_TEX_VORONOI, "Voronoi Texture", NODE_CLASS_TEXTURE, 0);
|
||||
sh_fn_node_type_base(&ntype, SH_NODE_TEX_VORONOI, "Voronoi Texture", NODE_CLASS_TEXTURE, 0);
|
||||
ntype.declare = blender::nodes::sh_node_tex_voronoi_declare;
|
||||
node_type_init(&ntype, node_shader_init_tex_voronoi);
|
||||
node_type_storage(
|
||||
&ntype, "NodeTexVoronoi", node_free_standard_storage, node_copy_standard_storage);
|
||||
node_type_gpu(&ntype, node_shader_gpu_tex_voronoi);
|
||||
node_type_update(&ntype, node_shader_update_tex_voronoi);
|
||||
ntype.build_multi_function = blender::nodes::sh_node_voronoi_build_multi_function;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue