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