/// Alligator Noise is provided by Side Effects Software Inc. and is licensed
/// under a Creative Commons Attribution-ShareAlike 4.0 International License.
///
/// Author: "Side Effects Software Inc"
/// Source: "http://www.sidefx.com/docs/hdk15.0/alligator_2alligator_8_c-example.html"
/// License: "http://creativecommons.org/licenses/by-sa/4.0/"
///
/// Translated and modified by Ivan Mavrov, Chaos Group Ltd. 2016
/// Contact: ivan.mavrov@chaosgroup.com
/// 3D Alligator noise implementation.
/// Returned values are in the [0, 1] range.
float alligatorNoise3D(point position) {
vector cellOffsets[27] = {
vector( 0, 0, 0),
vector( 1, 0, 0),
vector( 1, 1, 0),
vector( 0, 1, 0),
vector(-1, 1, 0),
vector(-1, 0, 0),
vector(-1, -1, 0),
vector( 0, -1, 0),
vector( 1, -1, 0),
vector( 0, 0, -1),
vector( 1, 0, -1),
vector( 1, 1, -1),
vector( 0, 1, -1),
vector(-1, 1, -1),
vector(-1, 0, -1),
vector(-1, -1, -1),
vector( 0, -1, -1),
vector( 1, -1, -1),
vector( 0, 0, 1),
vector( 1, 0, 1),
vector( 1, 1, 1),
vector( 0, 1, 1),
vector(-1, 1, 1),
vector(-1, 0, 1),
vector(-1, -1, 1),
vector( 0, -1, 1),
vector( 1, -1, 1)
};
point iPosition = floor(position);
float firstReverseSmoothPointDistance = 0.0;
float secondReverseSmoothPointDistance = 0.0;
for (int cellIndex = 0; cellIndex < 27; ++cellIndex) {
point cellOrigin = iPosition + cellOffsets[cellIndex];
vector cellPointOffset = cellnoise(cellOrigin, 0.0);
point cellPointPosition = cellOrigin + cellPointOffset;
float cellPointDistance = distance(position, cellPointPosition);
if (cellPointDistance < 1.0) {
float reverseSmoothDistance = smoothstep(0.0, 1.0, 1.0 - cellPointDistance);
float distanceMultiplier = float(cellnoise(cellOrigin, 1.0));
reverseSmoothDistance *= distanceMultiplier;
if (firstReverseSmoothPointDistance < reverseSmoothDistance) {
secondReverseSmoothPointDistance = firstReverseSmoothPointDistance;
firstReverseSmoothPointDistance = reverseSmoothDistance;
} else {
if (secondReverseSmoothPointDistance < reverseSmoothDistance) {
secondReverseSmoothPointDistance = reverseSmoothDistance;
}
}
}
}
return firstReverseSmoothPointDistance - secondReverseSmoothPointDistance;
}
/// 3D Fractal Alligator noise implementation.
/// Returned values are in the [-1, 1] range.
float fractalAlligatorNoise3D(
point position,
float lacunarity, // Houdini 2.0
float gain, // Houdini rough
int octaveCount // Houdini turbulence - 1
) {
float noiseValue = 0.0;
float amplitude = 1.0;
for (int octave = 0; octave < octaveCount; ++octave) {
noiseValue += amplitude * (alligatorNoise3D(position) - 0.5);
position *= lacunarity;
amplitude *= gain;
}
return noiseValue;
}
shader FractalAlligatorNoise
[[ string description = "Fractal Alligator noise" ]]
(
float start_frequency = 1.0
[[ string description = "Initial sampling position multiplier that affects the overall granularity." ]],
vector start_offset = vector(0.0)
[[ string description = "Offsets the initial sampling position effectively shifting the pattern in the specified direction." ]],
float lacunarity = 2.0
[[ string description = "Position (frequency) multiplier per iteration." ]],
float gain = 0.5
[[ string description = "Amplitude multiplier per iteration." ]],
int octaves = 8
[[ string description = "Number of fractal iterations." ]],
float attenuation = 1.0
[[ string description = "The power of the falloff applied to the final result." ]],
string spacename = "object",
output color result = 0.0
) {
point objectPosition = transform(spacename, P);
point startPosition = start_frequency * objectPosition - start_offset;
float noiseValue = fractalAlligatorNoise3D(startPosition, lacunarity, gain, octaves);
noiseValue = 0.5 * noiseValue + 0.5;
noiseValue = pow(noiseValue, attenuation);
result = color(noiseValue);
}