Files
LNXSDK/leenkx/blender/lnx/material/cycles_functions.py

2873 lines
97 KiB
Python

str_tex_checker = """
vec3 tex_checker(const vec3 co, const vec3 col1, const vec3 col2, const float scale) {
// Prevent precision issues on unit coordinates
vec3 p = (co + 0.000001 * 0.999999) * scale;
float xi = abs(floor(p.x));
float yi = abs(floor(p.y));
float zi = abs(floor(p.z));
bool check = ((mod(xi, 2.0) == mod(yi, 2.0)) == bool(mod(zi, 2.0)));
return check ? col1 : col2;
}
float tex_checker_f(const vec3 co, const float scale) {
vec3 p = (co + 0.000001 * 0.999999) * scale;
float xi = abs(floor(p.x));
float yi = abs(floor(p.y));
float zi = abs(floor(p.z));
return float((mod(xi, 2.0) == mod(yi, 2.0)) == bool(mod(zi, 2.0)));
}
"""
str_tex_voronoi_5 = """
#define SHD_VORONOI_EUCLIDEAN 0
#define SHD_VORONOI_MANHATTAN 1
#define SHD_VORONOI_CHEBYCHEV 2
#define SHD_VORONOI_MINKOWSKI 3
#define SHD_VORONOI_F1 0
#define SHD_VORONOI_F2 1
#define SHD_VORONOI_SMOOTH_F1 2
#define SHD_VORONOI_DISTANCE_TO_EDGE 3
#define SHD_VORONOI_N_SPHERE_RADIUS 4
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;
};
ivec3 hash_pcg3d_i(ivec3 v) {
v = v * 1664525 + 1013904223;
v.x += v.y * v.z;
v.y += v.z * v.x;
v.z += v.x * v.y;
v = v ^ (v >> 16);
v.x += v.y * v.z;
v.y += v.z * v.x;
v.z += v.x * v.y;
return v;
}
vec3 hash_int3_to_vec3(ivec3 k) {
ivec3 h = hash_pcg3d_i(k);
return vec3(h & 0x7fffffff) * (1.0 / float(0x7fffffff));
}
ivec4 hash_pcg4d_i(ivec4 v) {
v = v * 1664525 + 1013904223;
v.x += v.y * v.w;
v.y += v.z * v.x;
v.z += v.x * v.y;
v.w += v.y * v.z;
v = v ^ (v >> 16);
v.x += v.y * v.w;
v.y += v.z * v.x;
v.z += v.x * v.y;
v.w += v.y * v.z;
return v;
}
vec4 hash_int4_to_vec4(ivec4 k) {
ivec4 h = hash_pcg4d_i(k);
return vec4(h & 0x7fffffff) * (1.0 / float(0x7fffffff));
}
vec3 hash_int4_to_vec3(ivec4 k) {
return hash_int4_to_vec4(k).xyz;
}
float voronoi_distance(vec3 a, vec3 b, VoronoiParams params)
{
if (params.metric == SHD_VORONOI_EUCLIDEAN) {
return distance(a, b);
}
else if (params.metric == SHD_VORONOI_MANHATTAN) {
return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z);
}
else if (params.metric == 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 == 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 == SHD_VORONOI_EUCLIDEAN) {
return distance(a, b);
}
else if (params.metric == 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 == 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 == 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;
}
}
vec4 voronoi_position(vec3 coord)
{
return vec4(coord.x, coord.y, coord.z, 0.0);
}
vec4 voronoi_position(vec4 coord)
{
return coord;
}
VoronoiOutput voronoi_f1(VoronoiParams params, vec3 coord)
{
vec3 cellPosition_f = floor(coord);
vec3 localPosition = coord - cellPosition_f;
ivec3 cellPosition = ivec3(cellPosition_f);
float minDistance = 8.0;
ivec3 targetOffset = ivec3(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++) {
ivec3 cellOffset = ivec3(i, j, k);
vec3 pointPosition = vec3(cellOffset) +
hash_int3_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_int3_to_vec3(cellPosition + targetOffset);
octave.Position = voronoi_position(targetPosition + cellPosition_f);
return octave;
}
VoronoiOutput voronoi_f1(VoronoiParams params, vec4 coord)
{
vec4 cellPosition_f = floor(coord);
vec4 localPosition = coord - cellPosition_f;
ivec4 cellPosition = ivec4(cellPosition_f);
float minDistance = 8.0;
ivec4 targetOffset = ivec4(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++) {
ivec4 cellOffset = ivec4(i, j, k, u);
vec4 pointPosition = vec4(cellOffset) +
hash_int4_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_int4_to_vec3(cellPosition + targetOffset);
octave.Position = voronoi_position(targetPosition + cellPosition_f);
return octave;
}
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vec3 coord)
{
vec3 cellPosition_f = floor(coord);
vec3 localPosition = coord - cellPosition_f;
ivec3 cellPosition = ivec3(cellPosition_f);
float smoothDistance = 0.0;
vec3 smoothColor = vec3(0.0);
vec3 smoothPosition = vec3(0.0);
float h = -1.0;
for (int k = -2; k <= 2; k++) {
for (int j = -2; j <= 2; j++) {
for (int i = -2; i <= 2; i++) {
ivec3 cellOffset = ivec3(i, j, k);
vec3 pointPosition = vec3(cellOffset) +
hash_int3_to_vec3(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
h = h == -1.0 ?
1.0 :
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_int3_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_f + smoothPosition);
return octave;
}
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vec4 coord)
{
vec4 cellPosition_f = floor(coord);
vec4 localPosition = coord - cellPosition_f;
ivec4 cellPosition = ivec4(cellPosition_f);
float smoothDistance = 0.0;
vec3 smoothColor = vec3(0.0);
vec4 smoothPosition = vec4(0.0);
float h = -1.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++) {
ivec4 cellOffset = ivec4(i, j, k, u);
vec4 pointPosition = vec4(cellOffset) +
hash_int4_to_vec4(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
h = h == -1.0 ?
1.0 :
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_int4_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_f + smoothPosition);
return octave;
}
VoronoiOutput voronoi_f2(VoronoiParams params, vec3 coord)
{
vec3 cellPosition_f = floor(coord);
vec3 localPosition = coord - cellPosition_f;
ivec3 cellPosition = ivec3(cellPosition_f);
float distanceF1 = 8.0;
float distanceF2 = 8.0;
ivec3 offsetF1 = ivec3(0);
vec3 positionF1 = vec3(0.0);
ivec3 offsetF2 = ivec3(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++) {
ivec3 cellOffset = ivec3(i, j, k);
vec3 pointPosition = vec3(cellOffset) +
hash_int3_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_int3_to_vec3(cellPosition + offsetF2);
octave.Position = voronoi_position(positionF2 + cellPosition_f);
return octave;
}
VoronoiOutput voronoi_f2(VoronoiParams params, vec4 coord)
{
vec4 cellPosition_f = floor(coord);
vec4 localPosition = coord - cellPosition_f;
ivec4 cellPosition = ivec4(cellPosition_f);
float distanceF1 = 8.0;
float distanceF2 = 8.0;
ivec4 offsetF1 = ivec4(0);
vec4 positionF1 = vec4(0.0);
ivec4 offsetF2 = ivec4(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++) {
ivec4 cellOffset = ivec4(i, j, k, u);
vec4 pointPosition = vec4(cellOffset) +
hash_int4_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_int4_to_vec3(cellPosition + offsetF2);
octave.Position = voronoi_position(positionF2 + cellPosition_f);
return octave;
}
float voronoi_distance_to_edge(VoronoiParams params, vec3 coord)
{
vec3 cellPosition_f = floor(coord);
vec3 localPosition = coord - cellPosition_f;
ivec3 cellPosition = ivec3(cellPosition_f);
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++) {
ivec3 cellOffset = ivec3(i, j, k);
vec3 vectorToPoint = vec3(cellOffset) +
hash_int3_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++) {
ivec3 cellOffset = ivec3(i, j, k);
vec3 vectorToPoint = vec3(cellOffset) +
hash_int3_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_distance_to_edge(VoronoiParams params, vec4 coord)
{
vec4 cellPosition_f = floor(coord);
vec4 localPosition = coord - cellPosition_f;
ivec4 cellPosition = ivec4(cellPosition_f);
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++) {
ivec4 cellOffset = ivec4(i, j, k, u);
vec4 vectorToPoint = vec4(cellOffset) +
hash_int4_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++) {
ivec4 cellOffset = ivec4(i, j, k, u);
vec4 vectorToPoint = vec4(cellOffset) +
hash_int4_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, vec3 coord)
{
vec3 cellPosition_f = floor(coord);
vec3 localPosition = coord - cellPosition_f;
ivec3 cellPosition = ivec3(cellPosition_f);
vec3 closestPoint = vec3(0.0);
ivec3 closestPointOffset = ivec3(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++) {
ivec3 cellOffset = ivec3(i, j, k);
vec3 pointPosition = vec3(cellOffset) +
hash_int3_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;
}
ivec3 cellOffset = ivec3(i, j, k) + closestPointOffset;
vec3 pointPosition = vec3(cellOffset) +
hash_int3_to_vec3(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = distance(closestPoint, pointPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPointToClosestPoint = pointPosition;
}
}
}
}
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
}
float voronoi_n_sphere_radius(VoronoiParams params, vec4 coord)
{
vec4 cellPosition_f = floor(coord);
vec4 localPosition = coord - cellPosition_f;
ivec4 cellPosition = ivec4(cellPosition_f);
vec4 closestPoint = vec4(0.0);
ivec4 closestPointOffset = ivec4(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++) {
ivec4 cellOffset = ivec4(i, j, k, u);
vec4 pointPosition = vec4(cellOffset) +
hash_int4_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;
}
ivec4 cellOffset = ivec4(i, j, k, u) + closestPointOffset;
vec4 pointPosition = vec4(cellOffset) +
hash_int4_to_vec4(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = distance(closestPoint, pointPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPointToClosestPoint = pointPosition;
}
}
}
}
}
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
}
float fractal_voronoi_distance_to_edge(VoronoiParams params, vec3 coord)
{
float amplitude = 1.0;
float max_amplitude = params.max_distance;
float scale = 1.0;
float dist = 8.0;
bool zero_input = params.detail == 0.0 || params.roughness == 0.0;
for (int i = 0; i <= int(ceil(params.detail)); ++i) {
float octave_distance = voronoi_distance_to_edge(params, coord * scale);
if (zero_input) {
dist = octave_distance;
break;
}
else if (float(i) <= params.detail) {
max_amplitude = mix(max_amplitude, params.max_distance / scale, amplitude);
dist = mix(dist, min(dist, 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, params.max_distance / scale, amplitude);
max_amplitude = mix(max_amplitude, lerp_amplitude, remainder);
float lerp_distance = mix(dist, min(dist, octave_distance / scale), amplitude);
dist = mix(dist, min(dist, lerp_distance), remainder);
}
}
}
if (params.normalize) {
dist /= max_amplitude;
}
return dist;
}
float fractal_voronoi_distance_to_edge(VoronoiParams params, vec4 coord)
{
float amplitude = 1.0;
float max_amplitude = params.max_distance;
float scale = 1.0;
float dist = 8.0;
bool zero_input = params.detail == 0.0 || params.roughness == 0.0;
for (int i = 0; i <= int(ceil(params.detail)); ++i) {
float octave_distance = voronoi_distance_to_edge(params, coord * scale);
if (zero_input) {
dist = octave_distance;
break;
}
else if (float(i) <= params.detail) {
max_amplitude = mix(max_amplitude, params.max_distance / scale, amplitude);
dist = mix(dist, min(dist, 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, params.max_distance / scale, amplitude);
max_amplitude = mix(max_amplitude, lerp_amplitude, remainder);
float lerp_distance = mix(dist, min(dist, octave_distance / scale), amplitude);
dist = mix(dist, min(dist, lerp_distance), remainder);
}
}
}
if (params.normalize) {
dist /= max_amplitude;
}
return dist;
}
VoronoiOutput fractal_voronoi_3d(VoronoiParams params, vec3 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;
for (int i = 0; i <= int(ceil(params.detail)); ++i) {
VoronoiOutput octave;
if (params.feature == SHD_VORONOI_F2) {
octave = voronoi_f2(params, coord * scale);
}
else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0) {
octave = voronoi_smooth_f1(params, coord * scale);
}
else {
octave = voronoi_f1(params, coord * scale);
}
if (zero_input) {
max_amplitude = 1.0;
Output = octave;
break;
}
else if (float(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 = Output.Position / params.scale;
return Output;
}
VoronoiOutput fractal_voronoi_4d(VoronoiParams params, vec4 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;
for (int i = 0; i <= int(ceil(params.detail)); ++i) {
VoronoiOutput octave;
if (params.feature == SHD_VORONOI_F2) {
octave = voronoi_f2(params, coord * scale);
}
else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0) {
octave = voronoi_smooth_f1(params, coord * scale);
}
else {
octave = voronoi_f1(params, coord * scale);
}
if (zero_input) {
max_amplitude = 1.0;
Output = octave;
break;
}
else if (float(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 = Output.Position / params.scale;
return Output;
}
vec3 tex_voronoi_3d(vec3 coord, float randomness, int metric, int outp, float scale, float exp, float w, float detail, float roughness, float lacunarity, float smoothness, int feature, int normalize)
{
VoronoiParams params;
params.feature = feature;
params.metric = metric;
params.scale = scale;
params.detail = clamp(detail, 0.0, 15.0);
params.roughness = clamp(roughness, 0.0, 1.0);
params.lacunarity = lacunarity;
params.smoothness = clamp(smoothness / 2.0, 0.0, 0.5);
params.exponent = exp;
params.randomness = clamp(randomness, 0.0, 1.0);
if (feature == SHD_VORONOI_F2) {
params.max_distance = (0.5 + 0.5 * params.randomness) * 2.0;
} else {
params.max_distance = 0.5 + 0.5 * params.randomness;
}
params.normalize = normalize == 1;
vec3 scaledCoord = coord * scale;
if (feature == SHD_VORONOI_DISTANCE_TO_EDGE) {
float dist = fractal_voronoi_distance_to_edge(params, scaledCoord);
if (outp == 0) return vec3(dist);
return vec3(0.0);
}
else if (feature == SHD_VORONOI_N_SPHERE_RADIUS) {
float radius = voronoi_n_sphere_radius(params, scaledCoord);
if (outp == 0) return vec3(radius);
return vec3(0.0);
}
else {
VoronoiOutput Output = fractal_voronoi_3d(params, scaledCoord);
if (outp == 0) return vec3(Output.Distance);
else if (outp == 1) return Output.Color;
return Output.Position.xyz;
}
}
vec3 tex_voronoi_4d(vec3 coord, float randomness, int metric, int outp, float scale, float exp, float w, float detail, float roughness, float lacunarity, float smoothness, int feature, int normalize)
{
VoronoiParams params;
params.feature = feature;
params.metric = metric;
params.scale = scale;
params.detail = clamp(detail, 0.0, 15.0);
params.roughness = clamp(roughness, 0.0, 1.0);
params.lacunarity = lacunarity;
params.smoothness = clamp(smoothness / 2.0, 0.0, 0.5);
params.exponent = exp;
params.randomness = clamp(randomness, 0.0, 1.0);
if (feature == SHD_VORONOI_F2) {
params.max_distance = (0.5 + 0.5 * params.randomness) * 2.0;
} else {
params.max_distance = 0.5 + 0.5 * params.randomness;
}
params.normalize = normalize == 1;
vec4 scaledCoord = vec4(coord * scale, w * scale);
if (feature == SHD_VORONOI_DISTANCE_TO_EDGE) {
float dist = fractal_voronoi_distance_to_edge(params, scaledCoord);
if (outp == 0) return vec3(dist);
return vec3(0.0);
}
else if (feature == SHD_VORONOI_N_SPHERE_RADIUS) {
float radius = voronoi_n_sphere_radius(params, scaledCoord);
if (outp == 0) return vec3(radius);
return vec3(0.0);
}
else {
VoronoiOutput Output = fractal_voronoi_4d(params, scaledCoord);
if (outp == 0) return vec3(Output.Distance);
else if (outp == 1) return Output.Color;
else if (outp == 2) return Output.Position.xyz;
return vec3(Output.Position.w);
}
}
vec3 tex_voronoi_1d(vec3 coord, float randomness, int metric, int outp, float scale, float exp, float w, float detail, float roughness, float lacunarity, float smoothness, int feature, int normalize) {
return tex_voronoi_3d(vec3(w, 0.0, 0.0), randomness, metric, outp, scale, exp, 0.0, detail, roughness, lacunarity, smoothness, feature, normalize);
}
vec3 tex_voronoi_2d(vec3 coord, float randomness, int metric, int outp, float scale, float exp, float w, float detail, float roughness, float lacunarity, float smoothness, int feature, int normalize) {
return tex_voronoi_3d(vec3(coord.x, coord.y, 0.0), randomness, metric, outp, scale, exp, 0.0, detail, roughness, lacunarity, smoothness, feature, normalize);
}
"""
str_tex_voronoi_4 = """
#define SHD_VORONOI_EUCLIDEAN 0
#define SHD_VORONOI_MANHATTAN 1
#define SHD_VORONOI_CHEBYCHEV 2
#define SHD_VORONOI_MINKOWSKI 3
#define SHD_VORONOI_F1 0
#define SHD_VORONOI_F2 1
#define SHD_VORONOI_SMOOTH_F1 2
#define SHD_VORONOI_DISTANCE_TO_EDGE 3
#define SHD_VORONOI_N_SPHERE_RADIUS 4
#define FLT_MAX 3.402823466e+38
vec4 safe_divide(vec4 a, float b)
{
return (b != 0.0) ? a / b : vec4(0.0);
}
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;
};
#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
#define mix_hash(a, b, c) \
{ \
a -= c; \
a ^= rot(c, 4); \
c += b; \
b -= a; \
b ^= rot(a, 6); \
a += c; \
c -= b; \
c ^= rot(b, 8); \
b += a; \
a -= c; \
a ^= rot(c, 16); \
c += b; \
b -= a; \
b ^= rot(a, 19); \
a += c; \
c -= b; \
c ^= rot(b, 4); \
b += a; \
}
#define final_hash(a, b, c) \
{ \
c ^= b; \
c -= rot(b, 14); \
a ^= c; \
a -= rot(c, 11); \
b ^= a; \
b -= rot(a, 25); \
c ^= b; \
c -= rot(b, 16); \
a ^= c; \
a -= rot(c, 4); \
b ^= a; \
b -= rot(a, 14); \
c ^= b; \
c -= rot(b, 24); \
}
uint v_hash_uint3(uint kx, uint ky, uint kz)
{
uint a, b, c;
a = b = c = 0xdeadbeefu + (3u << 2u) + 13u;
c += kz;
b += ky;
a += kx;
final_hash(a, b, c);
return c;
}
uint v_hash_uint4(uint kx, uint ky, uint kz, uint kw)
{
uint a, b, c;
a = b = c = 0xdeadbeefu + (4u << 2u) + 13u;
a += kx;
b += ky;
c += kz;
mix_hash(a, b, c);
a += kw;
final_hash(a, b, c);
return c;
}
#undef rot
#undef final_hash
#undef mix_hash
float v_hash_uint3_to_float(uint kx, uint ky, uint kz)
{
return float(v_hash_uint3(kx, ky, kz)) / float(0xFFFFFFFFu);
}
float v_hash_uint4_to_float(uint kx, uint ky, uint kz, uint kw)
{
return float(v_hash_uint4(kx, ky, kz, kw)) / float(0xFFFFFFFFu);
}
float v_hash_vec3_to_float(vec3 k)
{
return v_hash_uint3_to_float(floatBitsToUint(k.x), floatBitsToUint(k.y), floatBitsToUint(k.z));
}
float v_hash_vec4_to_float(vec4 k)
{
return v_hash_uint4_to_float(
floatBitsToUint(k.x), floatBitsToUint(k.y), floatBitsToUint(k.z), floatBitsToUint(k.w));
}
vec3 v_hash_vec3_to_vec3(vec3 k)
{
return vec3(
v_hash_vec3_to_float(k), v_hash_vec4_to_float(vec4(k, 1.0)), v_hash_vec4_to_float(vec4(k, 2.0)));
}
vec4 v_hash_vec4_to_vec4(vec4 k)
{
return vec4(v_hash_vec4_to_float(k.xyzw),
v_hash_vec4_to_float(k.wxyz),
v_hash_vec4_to_float(k.zwxy),
v_hash_vec4_to_float(k.yzwx));
}
vec3 v_hash_vec4_to_vec3(vec4 k)
{
return vec3(v_hash_vec4_to_float(k.xyzw), v_hash_vec4_to_float(k.zxwy), v_hash_vec4_to_float(k.wzyx));
}
float voronoi_distance(vec3 a, vec3 b, VoronoiParams params)
{
if (params.metric == SHD_VORONOI_EUCLIDEAN) {
return distance(a, b);
}
else if (params.metric == SHD_VORONOI_MANHATTAN) {
return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z);
}
else if (params.metric == 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 == 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 == SHD_VORONOI_EUCLIDEAN) {
return distance(a, b);
}
else if (params.metric == 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 == 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 == 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;
}
}
vec4 voronoi_position(vec3 coord)
{
return vec4(coord.x, coord.y, coord.z, 0.0);
}
vec4 voronoi_position(vec4 coord)
{
return coord;
}
VoronoiOutput voronoi_f1(VoronoiParams params, vec3 coord)
{
vec3 cellPosition = floor(coord);
vec3 localPosition = coord - cellPosition;
float minDistance = FLT_MAX;
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 +
v_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 = v_hash_vec3_to_vec3(cellPosition + targetOffset);
octave.Position = voronoi_position(targetPosition + cellPosition);
return octave;
}
VoronoiOutput voronoi_f1(VoronoiParams params, vec4 coord)
{
vec4 cellPosition = floor(coord);
vec4 localPosition = coord - cellPosition;
float minDistance = FLT_MAX;
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 +
v_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 = v_hash_vec4_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 = 0.0;
vec3 smoothColor = vec3(0.0);
vec3 smoothPosition = vec3(0.0);
float h = -1.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 +
v_hash_vec3_to_vec3(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
h = h == -1.0 ?
1.0 :
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 = v_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_smooth_f1(VoronoiParams params, vec4 coord)
{
vec4 cellPosition = floor(coord);
vec4 localPosition = coord - cellPosition;
float smoothDistance = 0.0;
vec3 smoothColor = vec3(0.0);
vec4 smoothPosition = vec4(0.0);
float h = -1.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 +
v_hash_vec4_to_vec4(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
h = h == -1.0 ?
1.0 :
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 = v_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, vec3 coord)
{
vec3 cellPosition = floor(coord);
vec3 localPosition = coord - cellPosition;
float distanceF1 = FLT_MAX;
float distanceF2 = FLT_MAX;
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 +
v_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 = v_hash_vec3_to_vec3(cellPosition + offsetF2);
octave.Position = voronoi_position(positionF2 + cellPosition);
return octave;
}
VoronoiOutput voronoi_f2(VoronoiParams params, vec4 coord)
{
vec4 cellPosition = floor(coord);
vec4 localPosition = coord - cellPosition;
float distanceF1 = FLT_MAX;
float distanceF2 = FLT_MAX;
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 +
v_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 = v_hash_vec4_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 = FLT_MAX;
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 +
v_hash_vec3_to_vec3(cellPosition + cellOffset) * params.randomness -
localPosition;
float distanceToPoint = dot(vectorToPoint, vectorToPoint);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
vectorToClosest = vectorToPoint;
}
}
}
}
minDistance = FLT_MAX;
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 +
v_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_distance_to_edge(VoronoiParams params, vec4 coord)
{
vec4 cellPosition = floor(coord);
vec4 localPosition = coord - cellPosition;
vec4 vectorToClosest = vec4(0.0);
float minDistance = FLT_MAX;
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 +
v_hash_vec4_to_vec4(cellPosition + cellOffset) * params.randomness -
localPosition;
float distanceToPoint = dot(vectorToPoint, vectorToPoint);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
vectorToClosest = vectorToPoint;
}
}
}
}
}
minDistance = FLT_MAX;
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 +
v_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, vec3 coord)
{
vec3 cellPosition = floor(coord);
vec3 localPosition = coord - cellPosition;
vec3 closestPoint = vec3(0.0);
vec3 closestPointOffset = vec3(0.0);
float minDistance = FLT_MAX;
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 +
v_hash_vec3_to_vec3(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = distance(pointPosition, localPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPoint = pointPosition;
closestPointOffset = cellOffset;
}
}
}
}
minDistance = FLT_MAX;
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 +
v_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;
}
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 = FLT_MAX;
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 +
v_hash_vec4_to_vec4(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = distance(pointPosition, localPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPoint = pointPosition;
closestPointOffset = cellOffset;
}
}
}
}
}
minDistance = FLT_MAX;
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 +
v_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;
}
float fractal_voronoi_distance_to_edge(VoronoiParams params, vec3 coord)
{
float amplitude = 1.0;
float max_amplitude = params.max_distance;
float scale = 1.0;
float dist = 8.0;
bool zero_input = params.detail == 0.0 || params.roughness == 0.0;
for (int i = 0; i <= int(ceil(params.detail)); ++i) {
float octave_distance = voronoi_distance_to_edge(params, coord * scale);
if (zero_input) {
dist = octave_distance;
break;
}
else if (float(i) <= params.detail) {
max_amplitude = mix(max_amplitude, params.max_distance / scale, amplitude);
dist = mix(dist, min(dist, 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, params.max_distance / scale, amplitude);
max_amplitude = mix(max_amplitude, lerp_amplitude, remainder);
float lerp_distance = mix(dist, min(dist, octave_distance / scale), amplitude);
dist = mix(dist, min(dist, lerp_distance), remainder);
}
}
}
if (params.normalize) {
dist /= max_amplitude;
}
return dist;
}
float fractal_voronoi_distance_to_edge(VoronoiParams params, vec4 coord)
{
float amplitude = 1.0;
float max_amplitude = params.max_distance;
float scale = 1.0;
float dist = 8.0;
bool zero_input = params.detail == 0.0 || params.roughness == 0.0;
for (int i = 0; i <= int(ceil(params.detail)); ++i) {
float octave_distance = voronoi_distance_to_edge(params, coord * scale);
if (zero_input) {
dist = octave_distance;
break;
}
else if (float(i) <= params.detail) {
max_amplitude = mix(max_amplitude, params.max_distance / scale, amplitude);
dist = mix(dist, min(dist, 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, params.max_distance / scale, amplitude);
max_amplitude = mix(max_amplitude, lerp_amplitude, remainder);
float lerp_distance = mix(dist, min(dist, octave_distance / scale), amplitude);
dist = mix(dist, min(dist, lerp_distance), remainder);
}
}
}
if (params.normalize) {
dist /= max_amplitude;
}
return dist;
}
VoronoiOutput fractal_voronoi_3d(VoronoiParams params, vec3 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;
for (int i = 0; i <= int(ceil(params.detail)); ++i) {
VoronoiOutput octave;
if (params.feature == SHD_VORONOI_F2) {
octave = voronoi_f2(params, coord * scale);
}
else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0) {
octave = voronoi_smooth_f1(params, coord * scale);
}
else {
octave = voronoi_f1(params, coord * scale);
}
if (zero_input) {
max_amplitude = 1.0;
Output = octave;
break;
}
else if (float(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;
}
VoronoiOutput fractal_voronoi_4d(VoronoiParams params, vec4 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;
for (int i = 0; i <= int(ceil(params.detail)); ++i) {
VoronoiOutput octave;
if (params.feature == SHD_VORONOI_F2) {
octave = voronoi_f2(params, coord * scale);
}
else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0) {
octave = voronoi_smooth_f1(params, coord * scale);
}
else {
octave = voronoi_f1(params, coord * scale);
}
if (zero_input) {
max_amplitude = 1.0;
Output = octave;
break;
}
else if (float(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;
}
vec3 tex_voronoi_3d(vec3 coord, float randomness, int metric, int outp, float scale, float exp, float w, float detail, float roughness, float lacunarity, float smoothness, int feature, int normalize)
{
VoronoiParams params;
params.feature = feature;
params.metric = metric;
params.scale = scale;
params.detail = clamp(detail, 0.0, 15.0);
params.roughness = clamp(roughness, 0.0, 1.0);
params.lacunarity = lacunarity;
params.smoothness = clamp(smoothness / 2.0, 0.0, 0.5);
params.exponent = exp;
params.randomness = clamp(randomness, 0.0, 1.0);
if (feature == SHD_VORONOI_F2) {
params.max_distance = voronoi_distance(vec3(0.0), vec3(0.5 + 0.5 * params.randomness), params) * 2.0;
} else if (feature == SHD_VORONOI_DISTANCE_TO_EDGE) {
params.max_distance = 0.5 + 0.5 * params.randomness;
} else {
params.max_distance = voronoi_distance(vec3(0.0), vec3(0.5 + 0.5 * params.randomness), params);
}
params.normalize = normalize == 1;
vec3 scaledCoord = coord * scale;
if (feature == SHD_VORONOI_DISTANCE_TO_EDGE) {
float dist = fractal_voronoi_distance_to_edge(params, scaledCoord);
if (outp == 0) return vec3(dist);
return vec3(0.0);
}
else if (feature == SHD_VORONOI_N_SPHERE_RADIUS) {
float radius = voronoi_n_sphere_radius(params, scaledCoord);
if (outp == 0) return vec3(radius);
return vec3(0.0);
}
else {
VoronoiOutput Output = fractal_voronoi_3d(params, scaledCoord);
if (outp == 0) return vec3(Output.Distance);
else if (outp == 1) return Output.Color;
return Output.Position.xyz;
}
}
vec3 tex_voronoi_4d(vec3 coord, float randomness, int metric, int outp, float scale, float exp, float w, float detail, float roughness, float lacunarity, float smoothness, int feature, int normalize)
{
VoronoiParams params;
params.feature = feature;
params.metric = metric;
params.scale = scale;
params.detail = clamp(detail, 0.0, 15.0);
params.roughness = clamp(roughness, 0.0, 1.0);
params.lacunarity = lacunarity;
params.smoothness = clamp(smoothness / 2.0, 0.0, 0.5);
params.exponent = exp;
params.randomness = clamp(randomness, 0.0, 1.0);
if (feature == SHD_VORONOI_F2) {
params.max_distance = voronoi_distance(vec4(0.0), vec4(0.5 + 0.5 * params.randomness), params) * 2.0;
} else if (feature == SHD_VORONOI_DISTANCE_TO_EDGE) {
params.max_distance = 0.5 + 0.5 * params.randomness;
} else {
params.max_distance = voronoi_distance(vec4(0.0), vec4(0.5 + 0.5 * params.randomness), params);
}
params.normalize = normalize == 1;
vec4 scaledCoord = vec4(coord * scale, w * scale);
if (feature == SHD_VORONOI_DISTANCE_TO_EDGE) {
float dist = fractal_voronoi_distance_to_edge(params, scaledCoord);
if (outp == 0) return vec3(dist);
return vec3(0.0);
}
else if (feature == SHD_VORONOI_N_SPHERE_RADIUS) {
float radius = voronoi_n_sphere_radius(params, scaledCoord);
if (outp == 0) return vec3(radius);
return vec3(0.0);
}
else {
VoronoiOutput Output = fractal_voronoi_4d(params, scaledCoord);
if (outp == 0) return vec3(Output.Distance);
else if (outp == 1) return Output.Color;
else if (outp == 2) return Output.Position.xyz;
return vec3(Output.Position.w);
}
}
vec3 tex_voronoi_1d(vec3 coord, float randomness, int metric, int outp, float scale, float exp, float w, float detail, float roughness, float lacunarity, float smoothness, int feature, int normalize) {
return tex_voronoi_3d(vec3(w, 0.0, 0.0), randomness, metric, outp, scale, exp, 0.0, detail, roughness, lacunarity, smoothness, feature, normalize);
}
vec3 tex_voronoi_2d(vec3 coord, float randomness, int metric, int outp, float scale, float exp, float w, float detail, float roughness, float lacunarity, float smoothness, int feature, int normalize) {
return tex_voronoi_3d(vec3(coord.x, coord.y, 0.0), randomness, metric, outp, scale, exp, 0.0, detail, roughness, lacunarity, smoothness, feature, normalize);
}
"""
str_tex_noise = """
//https://github.com/blender/blender/blob/main/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
uint rot(uint x, int k) {
return (x << k) | (x >> (32 - k));
}
void mix_hash(inout uint a, inout uint b, inout uint c) {
a -= c; a ^= rot(c, 4); c += b;
b -= a; b ^= rot(a, 6); a += c;
c -= b; c ^= rot(b, 8); b += a;
a -= c; a ^= rot(c, 16); c += b;
b -= a; b ^= rot(a, 19); a += c;
c -= b; c ^= rot(b, 4); b += a;
}
void final_hash(inout uint a, inout uint b, inout uint c) {
c ^= b; c -= rot(b, 14);
a ^= c; a -= rot(c, 11);
b ^= a; b -= rot(a, 25);
c ^= b; c -= rot(b, 16);
a ^= c; a -= rot(c, 4);
b ^= a; b -= rot(a, 14);
c ^= b; c -= rot(b, 24);
}
uint hash_uint(uint kx) {
uint a = 0xdeadbeefu + 17u + kx;
uint b = 0xdeadbeefu + 17u;
uint c = 0xdeadbeefu + 17u;
final_hash(a, b, c);
return c;
}
uint hash_uint2(uint kx, uint ky) {
uint a = 0xdeadbeefu + 21u + kx;
uint b = 0xdeadbeefu + 21u + ky;
uint c = 0xdeadbeefu + 21u;
final_hash(a, b, c);
return c;
}
uint hash_uint3(uint kx, uint ky, uint kz) {
uint a = 0xdeadbeefu + 25u + kx;
uint b = 0xdeadbeefu + 25u + ky;
uint c = 0xdeadbeefu + 25u + kz;
final_hash(a, b, c);
return c;
}
uint hash_uint4(uint kx, uint ky, uint kz, uint kw) {
uint a = 0xdeadbeefu + 29u + kx;
uint b = 0xdeadbeefu + 29u + ky;
uint c = 0xdeadbeefu + 29u + kz;
mix_hash(a, b, c);
a += kw;
final_hash(a, b, c);
return c;
}
float hash_float_to_float(float k) {
return float(hash_uint(floatBitsToUint(k))) / 4294967295.0;
}
float hash_vec2_to_float(vec2 k) {
return float(hash_uint2(floatBitsToUint(k.x), floatBitsToUint(k.y))) / 4294967295.0;
}
float hash_vec3_to_float(vec3 k) {
return float(hash_uint3(floatBitsToUint(k.x), floatBitsToUint(k.y), floatBitsToUint(k.z))) / 4294967295.0;
}
float hash_vec4_to_float(vec4 k) {
return float(hash_uint4(floatBitsToUint(k.x), floatBitsToUint(k.y), floatBitsToUint(k.z), floatBitsToUint(k.w))) / 4294967295.0;
}
float fade(float t) {
return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
}
float negate_if(float val, uint cond) {
return (cond != 0u) ? -val : val;
}
float noise_grad(uint hash, float x) {
uint h = hash & 15u;
float g = 1.0 + float(h & 7u);
return negate_if(g, h & 8u) * x;
}
float noise_grad(uint hash, float x, float y) {
uint h = hash & 7u;
float u = h < 4u ? x : y;
float v = 2.0 * (h < 4u ? y : x);
return negate_if(u, h & 1u) + negate_if(v, h & 2u);
}
float noise_grad(uint hash, float x, float y, float z) {
uint h = hash & 15u;
float u = h < 8u ? x : y;
float vt = ((h == 12u) || (h == 14u)) ? x : z;
float v = h < 4u ? y : vt;
return negate_if(u, h & 1u) + negate_if(v, h & 2u);
}
float noise_grad(uint hash, float x, float y, float z, float w) {
uint h = hash & 31u;
float u = h < 24u ? x : y;
float v = h < 16u ? y : z;
float s = h < 8u ? z : w;
return negate_if(u, h & 1u) + negate_if(v, h & 2u) + negate_if(s, h & 4u);
}
float noise_perlin(float x) {
float x_floor = floor(x);
int X = int(x_floor);
float fx = x - x_floor;
float u = fade(fx);
return mix(noise_grad(hash_uint(uint(X)), fx), noise_grad(hash_uint(uint(X + 1)), fx - 1.0), u);
}
float noise_perlin(vec2 vec) {
vec2 vec_floor = floor(vec);
ivec2 I = ivec2(vec_floor);
vec2 f = vec - vec_floor;
vec2 u = vec2(fade(f.x), fade(f.y));
float v00 = noise_grad(hash_uint2(uint(I.x), uint(I.y)), f.x, f.y);
float v10 = noise_grad(hash_uint2(uint(I.x + 1), uint(I.y)), f.x - 1.0, f.y);
float v01 = noise_grad(hash_uint2(uint(I.x), uint(I.y + 1)), f.x, f.y - 1.0);
float v11 = noise_grad(hash_uint2(uint(I.x + 1), uint(I.y + 1)), f.x - 1.0, f.y - 1.0);
return mix(mix(v00, v10, u.x), mix(v01, v11, u.x), u.y);
}
float noise_perlin(vec3 vec) {
vec3 vec_floor = floor(vec);
ivec3 I = ivec3(vec_floor);
vec3 f = vec - vec_floor;
vec3 u = vec3(fade(f.x), fade(f.y), fade(f.z));
float v000 = noise_grad(hash_uint3(uint(I.x), uint(I.y), uint(I.z)), f.x, f.y, f.z);
float v100 = noise_grad(hash_uint3(uint(I.x + 1), uint(I.y), uint(I.z)), f.x - 1.0, f.y, f.z);
float v010 = noise_grad(hash_uint3(uint(I.x), uint(I.y + 1), uint(I.z)), f.x, f.y - 1.0, f.z);
float v110 = noise_grad(hash_uint3(uint(I.x + 1), uint(I.y + 1), uint(I.z)), f.x - 1.0, f.y - 1.0, f.z);
float v001 = noise_grad(hash_uint3(uint(I.x), uint(I.y), uint(I.z + 1)), f.x, f.y, f.z - 1.0);
float v101 = noise_grad(hash_uint3(uint(I.x + 1), uint(I.y), uint(I.z + 1)), f.x - 1.0, f.y, f.z - 1.0);
float v011 = noise_grad(hash_uint3(uint(I.x), uint(I.y + 1), uint(I.z + 1)), f.x, f.y - 1.0, f.z - 1.0);
float v111 = noise_grad(hash_uint3(uint(I.x + 1), uint(I.y + 1), uint(I.z + 1)), f.x - 1.0, f.y - 1.0, f.z - 1.0);
return mix(mix(mix(v000, v100, u.x), mix(v010, v110, u.x), u.y), mix(mix(v001, v101, u.x), mix(v011, v111, u.x), u.y), u.z);
}
float noise_perlin(vec4 vec) {
vec4 vec_floor = floor(vec);
ivec4 I = ivec4(vec_floor);
vec4 f = vec - vec_floor;
vec4 u = vec4(fade(f.x), fade(f.y), fade(f.z), fade(f.w));
float v0 = mix(mix(mix(noise_grad(hash_uint4(uint(I.x), uint(I.y), uint(I.z), uint(I.w)), f.x, f.y, f.z, f.w), noise_grad(hash_uint4(uint(I.x + 1), uint(I.y), uint(I.z), uint(I.w)), f.x - 1.0, f.y, f.z, f.w), u.x), mix(noise_grad(hash_uint4(uint(I.x), uint(I.y + 1), uint(I.z), uint(I.w)), f.x, f.y - 1.0, f.z, f.w), noise_grad(hash_uint4(uint(I.x + 1), uint(I.y + 1), uint(I.z), uint(I.w)), f.x - 1.0, f.y - 1.0, f.z, f.w), u.x), u.y), mix(mix(noise_grad(hash_uint4(uint(I.x), uint(I.y), uint(I.z + 1), uint(I.w)), f.x, f.y, f.z - 1.0, f.w), noise_grad(hash_uint4(uint(I.x + 1), uint(I.y), uint(I.z + 1), uint(I.w)), f.x - 1.0, f.y, f.z - 1.0, f.w), u.x), mix(noise_grad(hash_uint4(uint(I.x), uint(I.y + 1), uint(I.z + 1), uint(I.w)), f.x, f.y - 1.0, f.z - 1.0, f.w), noise_grad(hash_uint4(uint(I.x + 1), uint(I.y + 1), uint(I.z + 1), uint(I.w)), f.x - 1.0, f.y - 1.0, f.z - 1.0, f.w), u.x), u.y), u.z);
float v1 = mix(mix(mix(noise_grad(hash_uint4(uint(I.x), uint(I.y), uint(I.z), uint(I.w + 1)), f.x, f.y, f.z, f.w - 1.0), noise_grad(hash_uint4(uint(I.x + 1), uint(I.y), uint(I.z), uint(I.w + 1)), f.x - 1.0, f.y, f.z, f.w - 1.0), u.x), mix(noise_grad(hash_uint4(uint(I.x), uint(I.y + 1), uint(I.z), uint(I.w + 1)), f.x, f.y - 1.0, f.z, f.w - 1.0), noise_grad(hash_uint4(uint(I.x + 1), uint(I.y + 1), uint(I.z), uint(I.w + 1)), f.x - 1.0, f.y - 1.0, f.z, f.w - 1.0), u.x), u.y), mix(mix(noise_grad(hash_uint4(uint(I.x), uint(I.y), uint(I.z + 1), uint(I.w + 1)), f.x, f.y, f.z - 1.0, f.w - 1.0), noise_grad(hash_uint4(uint(I.x + 1), uint(I.y), uint(I.z + 1), uint(I.w + 1)), f.x - 1.0, f.y, f.z - 1.0, f.w - 1.0), u.x), mix(noise_grad(hash_uint4(uint(I.x), uint(I.y + 1), uint(I.z + 1), uint(I.w + 1)), f.x, f.y - 1.0, f.z - 1.0, f.w - 1.0), noise_grad(hash_uint4(uint(I.x + 1), uint(I.y + 1), uint(I.z + 1), uint(I.w + 1)), f.x - 1.0, f.y - 1.0, f.z - 1.0, f.w - 1.0), u.x), u.y), u.z);
return mix(v0, v1, u.w);
}
float compatible_mod(float a, float b) {
return (b != 0.0) ? (a - float(int(a / b)) * b) : 0.0;
}
vec2 compatible_mod(vec2 a, float b) { return vec2(compatible_mod(a.x, b), compatible_mod(a.y, b)); }
vec3 compatible_mod(vec3 a, float b) { return vec3(compatible_mod(a.x, b), compatible_mod(a.y, b), compatible_mod(a.z, b)); }
vec4 compatible_mod(vec4 a, float b) { return vec4(compatible_mod(a.x, b), compatible_mod(a.y, b), compatible_mod(a.z, b), compatible_mod(a.w, b)); }
float snoise(float p) {
float precision_correction = 0.5 * float(abs(p) >= 1000000.0);
p = compatible_mod(p, 100000.0) + precision_correction;
return 0.25 * noise_perlin(p);
}
float snoise(vec2 p) {
vec2 precision_correction = 0.5 * vec2(float(abs(p.x) >= 1000000.0), float(abs(p.y) >= 1000000.0));
p = compatible_mod(p, 100000.0) + precision_correction;
return 0.6616 * noise_perlin(p);
}
float snoise(vec3 p) {
vec3 precision_correction = 0.5 * vec3(float(abs(p.x) >= 1000000.0), float(abs(p.y) >= 1000000.0), float(abs(p.z) >= 1000000.0));
p = compatible_mod(p, 100000.0) + precision_correction;
return 0.9820 * noise_perlin(p);
}
float snoise(vec4 p) {
vec4 precision_correction = 0.5 * vec4(float(abs(p.x) >= 1000000.0), float(abs(p.y) >= 1000000.0), float(abs(p.z) >= 1000000.0), float(abs(p.w) >= 1000000.0));
p = compatible_mod(p, 100000.0) + precision_correction;
return 0.8344 * noise_perlin(p);
}
#define DEFINE_NOISE_FRACTAL(T) \\\
float noise_fbm(T co, float detail, float roughness, float lacunarity, float offset, float gain, bool normalize) { \\\
T p = co; \\\
float fscale = 1.0; \\\
float amp = 1.0; \\\
float maxamp = 0.0; \\\
float sum = 0.0; \\\
for (int i = 0; i <= int(detail); i++) { \\\
float t = snoise(fscale * p); \\\
sum += t * amp; \\\
maxamp += amp; \\\
amp *= roughness; \\\
fscale *= lacunarity; \\\
} \\\
float rmd = detail - floor(detail); \\\
if (rmd != 0.0) { \\\
float t = snoise(fscale * p); \\\
float sum2 = sum + t * amp; \\\
return normalize ? mix(0.5 * sum / maxamp + 0.5, 0.5 * sum2 / (maxamp + amp) + 0.5, rmd) : mix(sum, sum2, rmd); \\\
} else { \\\
return normalize ? 0.5 * sum / maxamp + 0.5 : sum; \\\
} \\\
} \\\
float noise_multi_fractal(T co, float detail, float roughness, float lacunarity, float offset, float gain, bool normalize) { \\\
T p = co; \\\
float value = 1.0; \\\
float pwr = 1.0; \\\
for (int i = 0; i <= int(detail); i++) { \\\
value *= (pwr * snoise(p) + 1.0); \\\
pwr *= roughness; \\\
p *= lacunarity; \\\
} \\\
float rmd = detail - floor(detail); \\\
if (rmd != 0.0) { \\\
value *= (rmd * pwr * snoise(p) + 1.0); \\\
} \\\
return value; \\\
} \\\
float noise_hetero_terrain(T co, float detail, float roughness, float lacunarity, float offset, float gain, bool normalize) { \\\
T p = co; \\\
float pwr = roughness; \\\
float value = offset + snoise(p); \\\
p *= lacunarity; \\\
for (int i = 1; i <= int(detail); i++) { \\\
float increment = (snoise(p) + offset) * pwr * value; \\\
value += increment; \\\
pwr *= roughness; \\\
p *= lacunarity; \\\
} \\\
float rmd = detail - floor(detail); \\\
if (rmd != 0.0) { \\\
float increment = (snoise(p) + offset) * pwr * value; \\\
value += rmd * increment; \\\
} \\\
return value; \\\
} \\\
float noise_hybrid_multi_fractal(T co, float detail, float roughness, float lacunarity, float offset, float gain, bool normalize) { \\\
T p = co; \\\
float pwr = 1.0; \\\
float value = 0.0; \\\
float weight = 1.0; \\\
for (int i = 0; (weight > 0.001) && (i <= int(detail)); i++) { \\\
if (weight > 1.0) weight = 1.0; \\\
float signal = (snoise(p) + offset) * pwr; \\\
pwr *= roughness; \\\
value += weight * signal; \\\
weight *= gain * signal; \\\
p *= lacunarity; \\\
} \\\
float rmd = detail - floor(detail); \\\
if ((rmd != 0.0) && (weight > 0.001)) { \\\
if (weight > 1.0) weight = 1.0; \\\
float signal = (snoise(p) + offset) * pwr; \\\
value += rmd * weight * signal; \\\
} \\\
return value; \\\
} \\\
float noise_ridged_multi_fractal(T co, float detail, float roughness, float lacunarity, float offset, float gain, bool normalize) { \\\
T p = co; \\\
float pwr = roughness; \\\
float signal = offset - abs(snoise(p)); \\\
signal *= signal; \\\
float value = signal; \\\
float weight = 1.0; \\\
for (int i = 1; i <= int(detail); i++) { \\\
p *= lacunarity; \\\
weight = clamp(signal * gain, 0.0, 1.0); \\\
signal = offset - abs(snoise(p)); \\\
signal *= signal; \\\
signal *= weight; \\\
value += signal * pwr; \\\
pwr *= roughness; \\\
} \\\
return value; \\\
}
DEFINE_NOISE_FRACTAL(float)
DEFINE_NOISE_FRACTAL(vec2)
DEFINE_NOISE_FRACTAL(vec3)
DEFINE_NOISE_FRACTAL(vec4)
float random_float_offset(float seed) { return 100.0 + hash_float_to_float(seed) * 100.0; }
vec2 random_vec2_offset(float seed) { return vec2(100.0 + hash_vec2_to_float(vec2(seed, 0.0)) * 100.0, 100.0 + hash_vec2_to_float(vec2(seed, 1.0)) * 100.0); }
vec3 random_vec3_offset(float seed) { return vec3(100.0 + hash_vec2_to_float(vec2(seed, 0.0)) * 100.0, 100.0 + hash_vec2_to_float(vec2(seed, 1.0)) * 100.0, 100.0 + hash_vec2_to_float(vec2(seed, 2.0)) * 100.0); }
vec4 random_vec4_offset(float seed) { return vec4(100.0 + hash_vec2_to_float(vec2(seed, 0.0)) * 100.0, 100.0 + hash_vec2_to_float(vec2(seed, 1.0)) * 100.0, 100.0 + hash_vec2_to_float(vec2(seed, 2.0)) * 100.0, 100.0 + hash_vec2_to_float(vec2(seed, 3.0)) * 100.0); }
vec3 hash_float_to_vec3(float k) {
return vec3(hash_float_to_float(k), hash_vec2_to_float(vec2(k, 1.0)), hash_vec2_to_float(vec2(k, 2.0)));
}
vec3 hash_vec2_to_vec3(vec2 k) {
return vec3(hash_vec2_to_float(k), hash_vec3_to_float(vec3(k, 1.0)), hash_vec3_to_float(vec3(k, 2.0)));
}
vec3 hash_vec3_to_vec3(vec3 k) {
return vec3(hash_vec3_to_float(k), hash_vec4_to_float(vec4(k, 1.0)), hash_vec4_to_float(vec4(k, 2.0)));
}
vec3 hash_vec4_to_vec3(vec4 k) {
return vec3(hash_vec4_to_float(k.xyzw), hash_vec4_to_float(k.zxwy), hash_vec4_to_float(k.wzyx));
}
"""
# Based on noise created by Nikita Miropolskiy, nikat/2013
# Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
str_tex_musgrave = """
vec3 random3(const vec3 c) {
float j = 4096.0 * sin(dot(c, vec3(17.0, 59.4, 15.0)));
vec3 r;
r.z = fract(512.0 * j);
j *= 0.125;
r.x = fract(512.0 * j);
j *= 0.125;
r.y = fract(512.0 * j);
return r - 0.5;
}
float noise_tex(const vec3 p) {
const float F3 = 0.3333333;
const float G3 = 0.1666667;
vec3 s = floor(p + dot(p, vec3(F3)));
vec3 x = p - s + dot(s, vec3(G3));
vec3 e = step(vec3(0.0), x - x.yzx);
vec3 i1 = e * (1.0 - e.zxy);
vec3 i2 = 1.0 - e.zxy * (1.0 - e);
vec3 x1 = x - i1 + G3;
vec3 x2 = x - i2 + 2.0 * G3;
vec3 x3 = x - 1.0 + 3.0 * G3;
vec4 w;
w.x = max(0.6 - dot(x, x), 0.0);
w.y = max(0.6 - dot(x1, x1), 0.0);
w.z = max(0.6 - dot(x2, x2), 0.0);
w.w = max(0.6 - dot(x3, x3), 0.0);
w = w * w;
w = w * w;
vec4 d;
d.x = dot(random3(s), x);
d.y = dot(random3(s + i1), x1);
d.z = dot(random3(s + i2), x2);
d.w = dot(random3(s + 1.0), x3);
d *= w;
return clamp(dot(d, vec4(52.0)), 0.0, 1.0);
}
float tex_musgrave_f(const vec3 p, float detail, float distortion) {
// Apply distortion to the input coordinates smoothly with noise_tex
vec3 distorted_p = p + distortion * vec3(
noise_tex(p + vec3(5.2, 1.3, 7.1)),
noise_tex(p + vec3(1.7, 9.2, 3.8)),
noise_tex(p + vec3(8.3, 2.8, 4.5))
);
float value = 0.0;
float amplitude = 1.0;
float frequency = 1.0;
// Use 'detail' as number of octaves, clamped between 1 and 8
int octaves = int(clamp(detail, 1.0, 8.0));
for (int i = 0; i < octaves; i++) {
value += amplitude * noise_tex(distorted_p * frequency);
frequency *= 2.0;
amplitude *= 0.5;
}
return clamp(value, 0.0, 1.0);
}
"""
# col: the incoming color
# shift: a vector containing the hue shift, the saturation modificator, the value modificator and the mix factor in this order
# this does the following:
# make rgb col to hsv
# apply hue shift through addition, sat/val through multiplication
# return an rgb color, mixed with the original one
str_hue_sat = """
vec3 hsv_to_rgb(const vec3 c) {
const vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
vec3 rgb_to_hsv(const vec3 c) {
const vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
vec3 hue_sat(const vec3 col, const vec4 shift) {
vec3 hsv = rgb_to_hsv(col);
hsv.x += shift.x;
hsv.y *= shift.y;
hsv.z *= shift.z;
return mix(hsv_to_rgb(hsv), col, shift.w);
}
"""
# https://twitter.com/Donzanoid/status/903424376707657730
str_wavelength_to_rgb = """
vec3 wavelength_to_rgb(const float t) {
vec3 r = t * 2.1 - vec3(1.8, 1.14, 0.3);
return 1.0 - r * r;
}
"""
str_tex_magic = """
//https://github.com/blender/blender/blob/main/source/blender/gpu/shaders/material/gpu_shader_material_tex_magic.glsl
vec3 tex_magic(vec3 p, float distortion, int depth) {
p = mod(p, 6.2831853f);
float x = sin((p.x + p.y + p.z) * 5.0f);
float y = cos((-p.x + p.y - p.z) * 5.0f);
float z = -cos((-p.x - p.y + p.z) * 5.0f);
if (depth > 0) {
x *= distortion;
y *= distortion;
z *= distortion;
y = -cos(x - y + z);
y *= distortion;
if (depth > 1) {
x = cos(x - y - z);
x *= distortion;
if (depth > 2) {
z = sin(-x - y - z);
z *= distortion;
if (depth > 3) {
x = -cos(-x + y - z);
x *= distortion;
if (depth > 4) {
y = -sin(-x + y + z);
y *= distortion;
if (depth > 5) {
y = -cos(-x + y + z);
y *= distortion;
if (depth > 6) {
x = cos(x + y + z);
x *= distortion;
if (depth > 7) {
z = sin(x + y - z);
z *= distortion;
if (depth > 8) {
x = -cos(-x - y + z);
x *= distortion;
if (depth > 9) {
y = -sin(x - y + z);
y *= distortion;
}
}
}
}
}
}
}
}
}
}
if (distortion != 0.0f) {
distortion *= 2.0f;
x /= distortion;
y /= distortion;
z /= distortion;
}
return vec3(0.5f - x, 0.5f - y, 0.5f - z);
}
float tex_magic_f(vec3 p, float distortion, int depth) {
vec3 c = tex_magic(p, distortion, depth);
return (c.x + c.y + c.z) / 3.0f;
}
"""
str_tex_brick = """
vec3 tex_brick(vec3 p, const vec3 c1, const vec3 c2, const vec3 c3) {
p /= vec3(0.9, 0.49, 0.49) / 2;
if (fract(p.y * 0.5) > 0.5) p.x += 0.5;
p = fract(p);
vec3 b = step(p, vec3(0.95, 0.9, 0.9));
return mix(c3, c1, b.x * b.y * b.z);
}
float tex_brick_f(vec3 p) {
p /= vec3(0.9, 0.49, 0.49) / 2;
if (fract(p.y * 0.5) > 0.5) p.x += 0.5;
p = fract(p);
vec3 b = step(p, vec3(0.95, 0.9, 0.9));
return mix(1.0, 0.0, b.x * b.y * b.z);
}
"""
#https://github.com/blender/blender/blob/main/source/blender/gpu/shaders/material/gpu_shader_material_tex_brick.glsl
str_tex_brick_blender = """
float integer_noise(int n)
{
/* Integer bit-shifts for these calculations can cause precision problems on macOS.
* Using uint resolves these issues. */
uint nn;
nn = (uint(n) + 1013u) & 0x7fffffffu;
nn = (nn >> 13u) ^ nn;
nn = (uint(nn * (nn * nn * 60493u + 19990303u)) + 1376312589u) & 0x7fffffffu;
return 0.5f * (float(nn) / 1073741824.0f);
}
vec2 calc_brick_texture(vec3 p,
float mortar_size,
float mortar_smooth,
float bias,
float brick_width,
float row_height,
float offset_amount,
int offset_frequency,
float squash_amount,
int squash_frequency)
{
int bricknum, rownum;
float offset = 0.0f;
float x, y;
rownum = int(floor(p.y / row_height));
if (offset_frequency != 0 && squash_frequency != 0) {
brick_width *= (rownum % squash_frequency != 0) ? 1.0f : squash_amount; /* squash */
offset = (rownum % offset_frequency != 0) ? 0.0f : (brick_width * offset_amount); /* offset */
}
bricknum = int(floor((p.x + offset) / brick_width));
x = (p.x + offset) - brick_width * bricknum;
y = p.y - row_height * rownum;
float tint = clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0f, 1.0f);
float min_dist = min(min(x, y), min(brick_width - x, row_height - y));
if (min_dist >= mortar_size) {
return vec2(tint, 0.0f);
}
else if (mortar_smooth == 0.0f) {
return vec2(tint, 1.0f);
}
else {
min_dist = 1.0f - min_dist / mortar_size;
return vec2(tint, smoothstep(0.0f, mortar_smooth, min_dist));
}
}
vec3 tex_brick_blender(vec3 co,
vec3 color1,
vec3 color2,
vec3 mortar,
float scale,
float mortar_size,
float mortar_smooth,
float bias,
float brick_width,
float row_height,
float offset_amount,
float offset_frequency,
float squash_amount,
float squash_frequency)
{
vec2 f2 = calc_brick_texture(co * scale,
mortar_size,
mortar_smooth,
bias,
brick_width,
row_height,
offset_amount,
int(offset_frequency),
squash_amount,
int(squash_frequency));
float tint = f2.x;
float f = f2.y;
if (f != 1.0f) {
float facm = 1.0f - tint;
color1 = facm * color1 + tint * color2;
}
return mix(color1, mortar, f);
}
float tex_brick_blender_f(vec3 co,
vec3 color1,
vec3 color2,
vec3 mortar,
float scale,
float mortar_size,
float mortar_smooth,
float bias,
float brick_width,
float row_height,
float offset_amount,
float offset_frequency,
float squash_amount,
float squash_frequency)
{
vec2 f2 = calc_brick_texture(co * scale,
mortar_size,
mortar_smooth,
bias,
brick_width,
row_height,
offset_amount,
int(offset_frequency),
squash_amount,
int(squash_frequency));
float tint = f2.x;
float f = f2.y;
if (f != 1.0f) {
float facm = 1.0f - tint;
color1 = facm * color1 + tint * color2;
}
return f;
}
"""
str_tex_wave = """
float tex_wave_f(const vec3 p, const int type, const int d, const int profile, const float dist, const float detail, const float detail_scale, const float phase_offset, const float detail_roughness) {
vec3 cp = (p + 0.000001) * 0.999999;
float n;
if (type == 0) {
if (d == 0) n = cp.x * 20.0;
else if (d == 1) n = cp.y * 20.0;
else if (d == 2) n = cp.z * 20.0;
else n = (cp.x + cp.y + cp.z) * 10.0;
}
else {
vec3 rp = cp;
if (d == 0) rp *= vec3(0.0, 1.0, 1.0);
else if (d == 1) rp *= vec3(1.0, 0.0, 1.0);
else if (d == 2) rp *= vec3(1.0, 1.0, 0.0);
n = length(rp) * 20.0;
}
n += phase_offset;
if (dist != 0.0) {
n += dist * (noise_fbm(cp * detail_scale, detail, detail_roughness, 2.0, 0.0, 0.0, true) * 2.0 - 1.0);
}
if (profile == 0) {
return 0.5 + 0.5 * sin(n - 1.57079632679);
}
else if (profile == 1) {
n /= 6.28318530718;
return n - floor(n);
}
else {
n /= 6.28318530718;
return abs(2.0 * (n - floor(n + 0.5)));
}
}
"""
str_tex_gabor = """
uint hash_uint3(uint kx, uint ky, uint kz) {
uint a, b, c;
a = b = c = 0xdeadbeefu + (3u << 2u) + 13u;
c += kz;
b += ky;
a += kx;
c ^= b; c -= (b << 14u) | (b >> 18u);
a ^= c; a -= (c << 11u) | (c >> 21u);
b ^= a; b -= (a << 25u) | (a >> 7u);
c ^= b; c -= (b << 16u) | (b >> 16u);
a ^= c; a -= (c << 4u) | (c >> 28u);
b ^= a; b -= (a << 14u) | (a >> 18u);
c ^= b; c -= (b << 24u) | (b >> 8u);
return c;
}
uint hash_uint4(uint kx, uint ky, uint kz, uint kw) {
uint a, b, c;
a = b = c = 0xdeadbeefu + (4u << 2u) + 13u;
a += kx; b += ky; c += kz;
a -= c; a ^= (c << 4u) | (c >> 28u); c += b;
b -= a; b ^= (a << 6u) | (a >> 26u); a += c;
c -= b; c ^= (b << 8u) | (b >> 24u); b += a;
a -= c; a ^= (c << 16u) | (c >> 16u); c += b;
b -= a; b ^= (a << 19u) | (a >> 13u); a += c;
c -= b; c ^= (b << 4u) | (b >> 28u); b += a;
a += kw;
c ^= b; c -= (b << 14u) | (b >> 18u);
a ^= c; a -= (c << 11u) | (c >> 21u);
b ^= a; b -= (a << 25u) | (a >> 7u);
c ^= b; c -= (b << 16u) | (b >> 16u);
a ^= c; a -= (c << 4u) | (c >> 28u);
b ^= a; b -= (a << 14u) | (a >> 18u);
c ^= b; c -= (b << 24u) | (b >> 8u);
return c;
}
float hash_vec3_to_float(vec3 k) {
return float(hash_uint3(floatBitsToUint(k.x), floatBitsToUint(k.y), floatBitsToUint(k.z))) / float(0xFFFFFFFFu);
}
float hash_vec4_to_float(vec4 k) {
return float(hash_uint4(floatBitsToUint(k.x), floatBitsToUint(k.y), floatBitsToUint(k.z), floatBitsToUint(k.w))) / float(0xFFFFFFFFu);
}
vec2 hash_vec3_to_vec2(vec3 k) {
return vec2(hash_vec3_to_float(k.xyz), hash_vec3_to_float(k.zxy));
}
vec2 hash_vec4_to_vec2(vec4 k) {
return vec2(hash_vec4_to_float(k.xyzw), hash_vec4_to_float(k.zxwy));
}
vec3 hash_vec4_to_vec3(vec4 k) {
return vec3(hash_vec4_to_float(k.xyzw), hash_vec4_to_float(k.zxwy), hash_vec4_to_float(k.wzyx));
}
vec2 compute_2d_gabor_kernel(vec2 position, float frequency, float orientation) {
float distance_squared = dot(position, position);
float hann_window = 0.5 + 0.5 * cos(3.14159265359 * distance_squared);
float gaussian_envelop = exp(-3.14159265359 * distance_squared);
vec2 frequency_vector = frequency * vec2(cos(orientation), sin(orientation));
float angle = 6.28318530718 * dot(position, frequency_vector);
return gaussian_envelop * hann_window * vec2(cos(angle), sin(angle));
}
float compute_2d_gabor_standard_deviation() {
return sqrt(8.0 * 0.5 * 0.25);
}
vec2 compute_2d_gabor_noise_cell(vec2 cell, vec2 position, float frequency, float isotropy, float base_orientation) {
vec2 noise = vec2(0.0);
for (int i = 0; i < 8; ++i) {
vec3 seed_for_orientation = vec3(cell, float(i * 3));
vec3 seed_for_kernel_center = vec3(cell, float(i * 3 + 1));
vec3 seed_for_weight = vec3(cell, float(i * 3 + 2));
float random_orientation = (hash_vec3_to_float(seed_for_orientation) - 0.5) * 3.14159265359;
float orientation = base_orientation + random_orientation * isotropy;
vec2 kernel_center = hash_vec3_to_vec2(seed_for_kernel_center);
vec2 position_in_kernel_space = position - kernel_center;
if (dot(position_in_kernel_space, position_in_kernel_space) >= 1.0) continue;
float weight = hash_vec3_to_float(seed_for_weight) < 0.5 ? -1.0 : 1.0;
noise += weight * compute_2d_gabor_kernel(position_in_kernel_space, frequency, orientation);
}
return noise;
}
vec2 compute_2d_gabor_noise(vec2 coordinates, float frequency, float isotropy, float base_orientation) {
vec2 cell_position = floor(coordinates);
vec2 local_position = coordinates - cell_position;
vec2 sum = vec2(0.0);
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec2 cell_offset = vec2(float(i), float(j));
sum += compute_2d_gabor_noise_cell(cell_position + cell_offset, local_position - cell_offset, frequency, isotropy, base_orientation);
}
}
return sum;
}
vec2 compute_3d_gabor_kernel(vec3 position, float frequency, vec3 orientation) {
float distance_squared = dot(position, position);
float hann_window = 0.5 + 0.5 * cos(3.14159265359 * distance_squared);
float gaussian_envelop = exp(-3.14159265359 * distance_squared);
vec3 frequency_vector = frequency * orientation;
float angle = 6.28318530718 * dot(position, frequency_vector);
return gaussian_envelop * hann_window * vec2(cos(angle), sin(angle));
}
float compute_3d_gabor_standard_deviation() {
return sqrt(8.0 * 0.5 * (1.0 / (4.0 * 1.41421356237)));
}
vec3 compute_3d_orientation(vec3 orientation, float isotropy, vec4 seed) {
if (isotropy == 0.0) return orientation;
float inclination = acos(clamp(orientation.z, -1.0, 1.0));
float azimuth = sign(orientation.y) * acos(orientation.x / length(orientation.xy));
vec2 random_angles = hash_vec4_to_vec2(seed) * 3.14159265359;
inclination += random_angles.x * isotropy;
azimuth += random_angles.y * isotropy;
return vec3(sin(inclination) * cos(azimuth), sin(inclination) * sin(azimuth), cos(inclination));
}
vec2 compute_3d_gabor_noise_cell(vec3 cell, vec3 position, float frequency, float isotropy, vec3 base_orientation) {
vec2 noise = vec2(0.0);
for (int i = 0; i < 8; ++i) {
vec4 seed_for_orientation = vec4(cell, float(i * 3));
vec4 seed_for_kernel_center = vec4(cell, float(i * 3 + 1));
vec4 seed_for_weight = vec4(cell, float(i * 3 + 2));
vec3 orientation = compute_3d_orientation(base_orientation, isotropy, seed_for_orientation);
vec3 kernel_center = hash_vec4_to_vec3(seed_for_kernel_center);
vec3 position_in_kernel_space = position - kernel_center;
if (dot(position_in_kernel_space, position_in_kernel_space) >= 1.0) continue;
float weight = hash_vec4_to_float(seed_for_weight) < 0.5 ? -1.0 : 1.0;
noise += weight * compute_3d_gabor_kernel(position_in_kernel_space, frequency, orientation);
}
return noise;
}
vec2 compute_3d_gabor_noise(vec3 coordinates, float frequency, float isotropy, vec3 base_orientation) {
vec3 cell_position = floor(coordinates);
vec3 local_position = coordinates - cell_position;
vec2 sum = vec2(0.0);
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec3 cell_offset = vec3(float(i), float(j), float(k));
sum += compute_3d_gabor_noise_cell(cell_position + cell_offset, local_position - cell_offset, frequency, isotropy, base_orientation);
}
}
}
return sum;
}
vec3 tex_gabor_core(vec3 coordinates, float scale, float frequency, float anisotropy, float orientation_2d, vec3 orientation_3d, float type) {
vec3 scaled_coordinates = coordinates * scale;
float isotropy = 1.0 - clamp(anisotropy, 0.0, 1.0);
frequency = max(0.001, frequency);
vec2 phasor = vec2(0.0);
float standard_deviation = 1.0;
if (type == 0.0) {
phasor = compute_2d_gabor_noise(scaled_coordinates.xy, frequency, isotropy, orientation_2d);
standard_deviation = compute_2d_gabor_standard_deviation();
}
else if (type == 1.0) {
float len = length(orientation_3d);
vec3 orientation = len > 0.0 ? orientation_3d / len : vec3(0.0, 0.0, 1.0);
phasor = compute_3d_gabor_noise(scaled_coordinates, frequency, isotropy, orientation);
standard_deviation = compute_3d_gabor_standard_deviation();
}
float normalization_factor = 6.0 * standard_deviation;
float output_value = (phasor.y / normalization_factor) * 0.5 + 0.5;
float output_phase = (atan(phasor.y, phasor.x) + 3.14159265359) / 6.28318530718;
float output_intensity = length(phasor) / normalization_factor;
return vec3(output_value, output_phase, output_intensity);
}
float tex_gabor_value(vec3 coordinates, float scale, float frequency, float anisotropy, float orientation_2d, vec3 orientation_3d, float type) {
return tex_gabor_core(coordinates, scale, frequency, anisotropy, orientation_2d, orientation_3d, type).x;
}
float tex_gabor_phase(vec3 coordinates, float scale, float frequency, float anisotropy, float orientation_2d, vec3 orientation_3d, float type) {
return tex_gabor_core(coordinates, scale, frequency, anisotropy, orientation_2d, orientation_3d, type).y;
}
float tex_gabor_intensity(vec3 coordinates, float scale, float frequency, float anisotropy, float orientation_2d, vec3 orientation_3d, float type) {
return tex_gabor_core(coordinates, scale, frequency, anisotropy, orientation_2d, orientation_3d, type).z;
}
"""
str_brightcontrast = """
vec3 brightcontrast(const vec3 col, const float bright, const float contr) {
float a = 1.0 + contr;
float b = bright - contr * 0.5;
return max(a * col + b, 0.0);
}
"""
# https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/
# dielectric-dielectric
# approx pow(1.0 - dotNV, 7.25 / ior)
str_fresnel = """
float fresnel(float eta, float c) {
float g = eta * eta - 1.0 + c * c;
if (g < 0.0) return 1.0;
g = sqrt(g);
float a = (g - c) / (g + c);
float b = ((g + c) * c - 1.0) / ((g - c) * c + 1.0);
return 0.5 * a * a * (1.0 + b * b);
}
"""
# Save division like Blender does it. If dividing by 0, the result is 0.
# https://github.com/blender/blender/blob/df1e9b662bd6938f74579cea9d30341f3b6dd02b/intern/cycles/kernel/shaders/node_vector_math.osl
str_safe_divide = """
vec3 safe_divide(const vec3 a, const vec3 b) {
\treturn vec3((b.x != 0.0) ? a.x / b.x : 0.0,
\t (b.y != 0.0) ? a.y / b.y : 0.0,
\t (b.z != 0.0) ? a.z / b.z : 0.0);
}
"""
# https://github.com/blender/blender/blob/df1e9b662bd6938f74579cea9d30341f3b6dd02b/intern/cycles/kernel/shaders/node_vector_math.osl
str_project = """
vec3 project(const vec3 v, const vec3 v_proj) {
\tfloat lenSquared = dot(v_proj, v_proj);
\treturn (lenSquared != 0.0) ? (dot(v, v_proj) / lenSquared) * v_proj : vec3(0);
}
"""
# Adapted from godot engine math_funcs.h
str_wrap = """
float wrap(const float value, const float max, const float min) {
\tfloat range = max - min;
\treturn (range != 0.0) ? value - (range * floor((value - min) / range)) : min;
}
vec3 wrap(const vec3 value, const vec3 max, const vec3 min) {
\treturn vec3(wrap(value.x, max.x, min.x),
\t wrap(value.y, max.y, min.y),
\t wrap(value.z, max.z, min.z));
}
"""
str_blackbody = """
vec3 blackbody(const float temperature){
vec3 rgb = vec3(0.0, 0.0, 0.0);
vec3 r = vec3(0.0, 0.0, 0.0);
vec3 g = vec3(0.0, 0.0, 0.0);
vec3 b = vec3(0.0, 0.0, 0.0);
float t_inv = float(1.0 / temperature);
if (temperature >= 12000.0) {
rgb = vec3(0.826270103, 0.994478524, 1.56626022);
} else if(temperature < 965.0) {
rgb = vec3(4.70366907, 0.0, 0.0);
} else {
if (temperature >= 6365.0) {
vec3 r = vec3(3.78765709e+03, 9.36026367e-06, 3.98995841e-01);
vec3 g = vec3(-5.00279505e+02, -4.59745390e-06, 1.09090465e+00);
vec4 b = vec4(6.72595954e-13, -2.73059993e-08, 4.24068546e-04, -7.52204323e-01);
rgb = vec3(r.r * t_inv + r.g * temperature + r.b, g.r * t_inv + g.g * temperature + g.b, ((b.r * temperature + b.g) * temperature + b.b) * temperature + b.a );
} else if (temperature >= 3315.0) {
vec3 r = vec3(4.60124770e+03, 2.89727618e-05, 1.48001316e-01);
vec3 g = vec3(-1.18134453e+03, -2.18913373e-05, 1.30656109e+00);
vec4 b = vec4(-2.22463426e-13, -1.55078698e-08, 3.81675160e-04, -7.30646033e-01);
rgb = vec3(r.r * t_inv + r.g * temperature + r.b, g.r * t_inv + g.g * temperature + g.b, ((b.r * temperature + b.g) * temperature + b.b) * temperature + b.a );
} else if (temperature >= 1902.0) {
vec3 r = vec3(4.66849800e+03, 2.85655028e-05, 1.29075375e-01);
vec3 g = vec3(-1.42546105e+03, -4.01730887e-05, 1.44002695e+00);
vec4 b = vec4(-2.02524603e-11, 1.79435860e-07, -2.60561875e-04, -1.41761141e-02);
rgb = vec3(r.r * t_inv + r.g * temperature + r.b, g.r * t_inv + g.g * temperature + g.b, ((b.r * temperature + b.g) * temperature + b.b) * temperature + b.a );
} else if (temperature >= 1449.0) {
vec3 r = vec3(4.10671449e+03, -8.61949938e-05, 6.41423749e-01);
vec3 g = vec3(-1.22075471e+03, 2.56245413e-05, 1.20753416e+00);
vec4 b = vec4(0.0, 0.0, 0.0, 0.0);
rgb = vec3(r.r * t_inv + r.g * temperature + r.b, g.r * t_inv + g.g * temperature + g.b, ((b.r * temperature + b.g) * temperature + b.b) * temperature + b.a );
} else if (temperature >= 1167.0) {
vec3 r = vec3(3.37763626e+03, -4.34581697e-04, 1.64843306e+00);
vec3 g = vec3(-1.00402363e+03, 1.29189794e-04, 9.08181524e-01);
vec4 b = vec4(0.0, 0.0, 0.0, 0.0);
rgb = vec3(r.r * t_inv + r.g * temperature + r.b, g.r * t_inv + g.g * temperature + g.b, ((b.r * temperature + b.g) * temperature + b.b) * temperature + b.a );
} else {
vec3 r = vec3(2.52432244e+03, -1.06185848e-03, 3.11067539e+00);
vec3 g = vec3(-7.50343014e+02, 3.15679613e-04, 4.73464526e-01);
vec4 b = vec4(0.0, 0.0, 0.0, 0.0);
rgb = vec3(r.r * t_inv + r.g * temperature + r.b, g.r * t_inv + g.g * temperature + g.b, ((b.r * temperature + b.g) * temperature + b.b) * temperature + b.a );
}
}
return rgb;
}
"""
# Adapted from https://github.com/blender/blender/blob/594f47ecd2d5367ca936cf6fc6ec8168c2b360d0/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl
str_map_range_linear = """
float map_range_linear(const float value, const float fromMin, const float fromMax, const float toMin, const float toMax) {
if (fromMax != fromMin) {
return float(toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin));
}
else {
return float(0.0);
}
}
"""
str_map_range_stepped = """
float map_range_stepped(const float value, const float fromMin, const float fromMax, const float toMin, const float toMax, const float steps) {
if (fromMax != fromMin) {
float factor = (value - fromMin) / (fromMax - fromMin);
factor = (steps > 0.0) ? floor(factor * (steps + 1.0)) / steps : 0.0;
return float(toMin + factor * (toMax - toMin));
}
else {
return float(0.0);
}
}
"""
str_map_range_smoothstep = """
float map_range_smoothstep(const float value, const float fromMin, const float fromMax, const float toMin, const float toMax)
{
if (fromMax != fromMin) {
float factor = (fromMin > fromMax) ? 1.0 - smoothstep(fromMax, fromMin, value) :
smoothstep(fromMin, fromMax, value);
return float(toMin + factor * (toMax - toMin));
}
else {
return float(0.0);
}
}
"""
str_map_range_smootherstep = """
float safe_divide(float a, float b)
{
return (b != 0.0) ? a / b : 0.0;
}
float smootherstep(float edge0, float edge1, float x)
{
x = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0, 1.0);
return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
}
float map_range_smootherstep(const float value, const float fromMin, const float fromMax, const float toMin, const float toMax) {
if (fromMax != fromMin) {
float factor = (fromMin > fromMax) ? 1.0 - smootherstep(fromMax, fromMin, value) :
smootherstep(fromMin, fromMax, value);
return float(toMin + factor * (toMax - toMin));
}
else {
return float(0.0);
}
}
"""
str_rotate_around_axis = """
vec3 rotate_around_axis(const vec3 p, const vec3 axis, const float angle)
{
float costheta = cos(angle);
float sintheta = sin(angle);
vec3 r;
r.x = ((costheta + (1.0 - costheta) * axis.x * axis.x) * p.x) +
(((1.0 - costheta) * axis.x * axis.y - axis.z * sintheta) * p.y) +
(((1.0 - costheta) * axis.x * axis.z + axis.y * sintheta) * p.z);
r.y = (((1.0 - costheta) * axis.x * axis.y + axis.z * sintheta) * p.x) +
((costheta + (1.0 - costheta) * axis.y * axis.y) * p.y) +
(((1.0 - costheta) * axis.y * axis.z - axis.x * sintheta) * p.z);
r.z = (((1.0 - costheta) * axis.x * axis.z - axis.y * sintheta) * p.x) +
(((1.0 - costheta) * axis.y * axis.z + axis.x * sintheta) * p.y) +
((costheta + (1.0 - costheta) * axis.z * axis.z) * p.z);
return r;
}
"""
str_euler_to_mat3 = """
mat3 euler_to_mat3(vec3 euler)
{
float cx = cos(euler.x);
float cy = cos(euler.y);
float cz = cos(euler.z);
float sx = sin(euler.x);
float sy = sin(euler.y);
float sz = sin(euler.z);
mat3 mat;
mat[0][0] = cy * cz;
mat[0][1] = cy * sz;
mat[0][2] = -sy;
mat[1][0] = sy * sx * cz - cx * sz;
mat[1][1] = sy * sx * sz + cx * cz;
mat[1][2] = cy * sx;
mat[2][0] = sy * cx * cz + sx * sz;
mat[2][1] = sy * cx * sz - sx * cz;
mat[2][2] = cy * cx;
return mat;
}
"""