ShaderGen

ShaderGen

Tools used:

  • Blender

  • Visual Studio Code

The Problem:

Building procedural materials is difficult due to a few essential missing nodes.

My Solution:

I developed a blender add-on that makes Blenders procedural material building capabilities considerably stronger

My Solution:

I developed a blender add-on that makes Blenders procedural material building capabilities considerably stronger

Project In-Depth Description:

Procedural Material Function Library for Blender using OSL

Introduction:

ShaderGen is a long-term project of mine that significantly enhances Blender's procedural material authoring capabilities. By implementing a collection of material functions using Open Shading Language (OSL), this project introduces a wide range of new nodes to blender's shader graph. It includes advanced noise generation algorithms, custom shader models that take advantage of cutting-edge techniques like Ray Marching, a recourse library of textures, grunge maps, and normal maps, and algorithmic utility nodes. These functions not only enable artists to achieve complex and realistic procedural materials, but they also offer image-processing effects that were previously challenging to achieve within the OSL framework. The project's compatibility with various digital content creation (DCC) platforms further promotes collaboration and interoperability in the CG industry.

Some Highlights Include:

  1. Advanced Noise Generation Algorithms:

    • Fractal Noise: A versatile noise generation algorithm capable of creating natural and organic patterns with controllable complexity and detail.

    • Perlin Noise: A classic noise function known for its smooth and coherent patterns, widely used in computer graphics for various effects.

    • Alligator Noise: An intriguing noise type that produces unique patterns resembling alligator skin, ideal for artistic and stylized materials.

    • Cell Noise: A useful function for generating cellular patterns, perfect for creating procedural textures like stone or concrete.

    • 4D Perlin Flow noise: a perlin noise with a flow parameter that morphs the noise instead of translating it. Based on the concept of rotating gradients and inspired by this paper published by the journal of computer graphics techniques

  2. Algorithmic Nodes for Enhanced Control:

    • Linear Ramp: Allows artists to create custom gradients for color transitions, providing precise control over material appearances.

    • Vector Warp: Introduces distortions and warping effects to procedural textures, adding organic and natural variation to the materials.

    • Bi-linear Ramp: A specialized ramp node for achieving smooth transitions between color values along two axes, facilitating complex material blending.

    • Primitive Shape: Enables the generation of basic geometric shapes procedurally, streamlining the material creation process.

    • Pseudo Histogram: Simulates histogram equalization effects to adjust the distribution of pixel intensities within textures, enhancing contrast and tonal balance.

    • Pseudo Contrast: A node for emulating contrast adjustments in procedural materials, creating visually striking and impactful results.

    • Quantize: Allows the quantization of procedural textures, useful for achieving pixelated or stylized looks.

    • Edge-Damage: Adds wear and tear effects to materials by simulating edge damage and weathering.

    • Blur: An innovative implementation of blurring effects within OSL, bypassing the limitations of neighboring pixel information.

  3. Custom Shading Models:

    • Arnold Standard Surface

    • Volumetric fire

    • custom Bxdf's


Benefits and Impact:

  1. Unprecedented Material Authoring Capabilities: The Procedural Material Function Library significantly expands Blender's material authoring possibilities by offering a diverse range of functions that were previously inaccessible or time-consuming to create.

  2. Realism and Artistic Control: Artists gain precise control over procedural textures and can achieve realistic materials with complex variations and details, empowering them to bring their artistic visions to life.

  3. Improved Image Processing in OSL: The implementation of blur, contrast, and histogram-like effects using OSL showcases novel techniques to overcome inherent limitations, further elevating Blender's procedural material capabilities.

  4. Cross-Platform Collaboration: The compatibility of OSL shaders with most DCC platforms fosters collaboration and enables seamless asset transfer across different software environments.

Conclusion:

The Procedural Material Function Library for Blender is a project that pushes the boundaries of material authoring in Blender. By introducing a comprehensive set of material functions using OSL, including advanced noise generation algorithms and algorithmic nodes, this project empowers artists to create intricate, realistic, and visually captivating procedural materials. The creative ability to achieve image processing effects within OSL opens up new possibilities, while the cross-platform compatibility promotes collaboration and interoperability within the CG community. This project stands as a testament to the power of innovation and its potential to elevate the capabilities of digital content creation tools like Blender.

More info on the individual shaders below…


This documentation is not complete and will be expanded over time to include missing nodes**

4 way gradient ramp

4 way bilinear color gradient ramp

shader ramp4(
    output color result = color(0.0, 0.0, 0.0),
    color valuetl = color(0, 0, 0),
    color valuetr = color(0, 0, 0),
    color valuebl = 0,
    color valuebr = 0,
    vector texcoord = vector(0.0, 0.0, 0.0)
)
{
    // Extract the UV coordinates
    float U = texcoord[0];
    float V = texcoord[1];

    // Perform bilinear interpolation
    color valueTop = mix(valuetl, valuetr, U);
    color valueBottom = mix(valuebl, valuebr, U);
    result = mix(valueBottom, valueTop, V);
}


Cell Noise

A modified cellular noise, based off the built in callnoise function

shader cellnoise2d(
    output color result = color(0, 0, 0),
    float period = 0,
    vector texcoord = vector(0, 0, 0),
)
{
    // Calculate the cell coordinates
    vector cellCoord = floor(texcoord);
    
    // Calculate the subcell coordinates
    vector subCell = texcoord - cellCoord;
    
    // Calculate the nearest integer cell coordinates
    vector nearestCell = floor(texcoord + 0.5);
    
    // Calculate the distance vectors to the nearest cell and its neighbors
    vector diffCell = vector(period, period, period) - mod(nearestCell, vector(period, period, period));
    
    // Calculate the nearest cell value
    float cellValue = noise("cell", nearestCell);

    // Calculate the distances to the 4 neighbors
    float dNW = length(subCell + vector(-1,  1, 0) - diffCell);
    float dNE = length(subCell + vector( 1,  1, 0) - diffCell);
    float dSW = length(subCell + vector(-1, -1, 0) - diffCell);
    float dSE = length(subCell + vector( 1, -1, 0) - diffCell);

    // Find the two closest neighbors
    float minDist1 = min(min(dNW, dNE), min(dSW, dSE));
    float minDist2 = min(max(dNW, dNE), max(dSW, dSE));
    
    // Calculate the distance to the border of the cell
    float borderDist = min(minDist1, minDist2);
    
    // Normalize the border distance and use it as the noise value
    cellValue = borderDist / diffCell[0];

    // Set the result based on the number of output channels
    result = cellValue;
}

Alligator noise

This is the same alligator noise from SideFX Houdini, translated and with minor edits to run in Blender

//Alligator Noise is provided by Side Effects Software Inc. and is licensed
/// under a Creative Commons Attribution-ShareAlike 4.0 International License
/*
 * Copyright (c) 2016
 *  Side Effects Software Inc.  All rights reserved.
 *
 * Redistribution and use of Houdini Development Kit samples in source and
 * binary forms, with or without modification, are permitted provided that the
 * following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. The name of Side Effects Software may not be used to endorse or
 *    promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *----------------------------------------------------------------------------
 */
  
/// 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
///
/// further modification by Scott Clayton
/// contact: scottclayton@skiff.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 [0 - 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." ]],
     
    output color result = 0.0
) {
    point objectPosition = transform("object", P);
    point startPosition = start_frequency * objectPosition - start_offset;
     
    float noiseValue = fractalAlligatorNoise3D(startPosition, lacunarity, gain, octaves);
     
    noiseValue = 0.5 * noiseValue;
    noiseValue = pow(noiseValue, attenuation);
     
    result = color(noiseValue);
}

Fractal Noise

The Fractal noise is simply a sum of multiple perlin noise at varying freq and amplitude

shader fractal2d(
    output color result = color(0, 0, 0),
    float amplitude = 1.0,
    int octaves = 3,
    float lacunarity = 2.0,
    float diminish = 0.5,
    float period = 0,
    vector texcoord = vector(0, 0, 0),
)
{
    // Initialize variables for the noise generation
    float freq = 1.0;
    float amp = amplitude;
    color mynoise = color(0, 0, 0);

    // Loop through octaves and sum Perlin noise values
    for (int i = 0; i < octaves; i++)
    {
        mynoise += amp * noise("perlin", freq * texcoord);
        freq *= lacunarity;
        amp *= diminish;
    }

    // Normalize the result to the range [-1, 1] and apply amplitude
    result = 2.0 * (mynoise - 0.5) * amplitude;
}

Perlin Noise

A simple perlin noise implementation

shader perlinnoise(
    output color result = color(0, 0, 0),
    float amplitude = 1.0,
    float pivot = 0.0,
    float period = 0,
    vector texcoord = vector(0, 0, 0),
)
{
    // Calculate the noise value at the given texture coordinates
    color noiseValue = noise("perlin", texcoord * vector(period, period, period)) * amplitude + pivot;
    
    // Set the result based on the number of output channels
    result = noiseValue;
}

Blur

A blur effect. especially dificult since osl does not provide access to neighboring pixels

/*
based off a redshift shader written by Edward Darby Edelen
*/

vector gaussianFromUniform(vector vec_in){
    float u2_sin;
    float u2_cos;

    sincos(M_2PI * vec_in.y, u2_sin, u2_cos);
    float r = sqrt(-2 * log(vec_in.x));
    return vector(r * u2_cos, r * u2_sin, 0);
}

shader Blur(
    float aniso = 0,
    float rotation = 0,
    vector direction = vector(0,1,0),
    vector tangent_in = vector(0, 0, 0),
    float amount = 10,
    output vector UV_offset = vector(0, 0, 0),
)
{
    
    vector anisovec = vector(1 + aniso, 1 - aniso, 0);

    vector myrandom = gaussianFromUniform(noise("perlin", vector(1) - P));
    vector off = gaussianFromUniform(noise("hash", P)) + vector(0,0,myrandom.x);
    vector uv_blur_direct = direction * vector(1,1,0);

    float blur_length = length(uv_blur_direct);
    vector uv_space = vector(0.001);

    uv_blur_direct /= blur_length;

    float uv_blur_rotate = atan2(uv_blur_direct.y, uv_blur_direct.x);
    vector uv_blur_vec = (off.x) * vector(blur_length,0,0);

    UV_offset = rotate(uv_blur_vec, uv_blur_rotate, vector(0,0,1)) * amount * uv_space;

}

Warp

A warping effect that distorts a texture based on a vector input. It is made to run over the UV's and not the texture itself

shader warp(
  point project = point(u, v, 0),
  color distort = 0,
  matrix mytransform = 1,
  output point uvw = 0
)
{
    uvw = transform(1/mytransform, project)+distort;
}

we can also slightly modify the blur shader to achieve an alternative warp…

vector gaussianFromUniform(vector vec_in){
    float u2_sin;
    float u2_cos;

    sincos(M_2PI * vec_in.y, u2_sin, u2_cos);
    float r = sqrt(-2 * log(vec_in.x));
    return vector(r * u2_cos, r * u2_sin, 0);
}

shader altwarp(
    float aniso = 0,
    float rotation = 0,
    vector direction = vector(0,1,0),
    vector tangent_in = vector(0, 0, 0),
    float amount = 10,
    output vector UV_offset = vector(0, 0, 0),
)
{
    
    vector anisovec = vector(1 + aniso, 1 - aniso, 0);

    vector myrandom = gaussianFromUniform(noise("perlin", vector(1) - P));
    vector off = gaussianFromUniform(noise("perlin", P)) + vector(0,0,myrandom.x);
    vector uv_blur_direct = direction * vector(1,1,0);

    float blur_length = length(uv_blur_direct);
    vector uv_space = vector(0.001);

    uv_blur_direct /= blur_length;

    float uv_blur_rotate = atan2(uv_blur_direct.y, uv_blur_direct.x);
    vector uv_blur_vec = (off.x) * vector(blur_length,0,0);

    UV_offset = rotate(uv_blur_vec, uv_blur_rotate, vector(0,0,1)) * amount * uv_space;

}


Linear ramp

A simple linear ramp

shader ramplr(
    output color result = 0,
    color valuel = color(0, 0, 0),
    color valuer = color(0, 0, 0),
    vector texcoord = 0
)
{
    // Extract the U coordinate
    float U = texcoord[0];

    // Perform linear interpolation between valuel and valuer based on U
    result = mix(color(valuel), color(valuer), U);
}

Edge Wear

Edge detection using inverted ambient occlusion


This one was actually done with Native Blender shader nodes, not osl code, but I thought I would include it anyway


Project In-Depth Description:

Procedural Material Function Library for Blender using OSL

Introduction:

ShaderGen is a long-term project of mine that significantly enhances Blender's procedural material authoring capabilities. By implementing a collection of material functions using Open Shading Language (OSL), this project introduces a wide range of new nodes to blender's shader graph. It includes advanced noise generation algorithms, custom shader models that take advantage of cutting-edge techniques like Ray Marching, a recourse library of textures, grunge maps, and normal maps, and algorithmic utility nodes. These functions not only enable artists to achieve complex and realistic procedural materials, but they also offer image-processing effects that were previously challenging to achieve within the OSL framework. The project's compatibility with various digital content creation (DCC) platforms further promotes collaboration and interoperability in the CG industry.

Some Highlights Include:

  1. Advanced Noise Generation Algorithms:

    • Fractal Noise: A versatile noise generation algorithm capable of creating natural and organic patterns with controllable complexity and detail.

    • Perlin Noise: A classic noise function known for its smooth and coherent patterns, widely used in computer graphics for various effects.

    • Alligator Noise: An intriguing noise type that produces unique patterns resembling alligator skin, ideal for artistic and stylized materials.

    • Cell Noise: A useful function for generating cellular patterns, perfect for creating procedural textures like stone or concrete.

    • 4D Perlin Flow noise: a perlin noise with a flow parameter that morphs the noise instead of translating it. Based on the concept of rotating gradients and inspired by this paper published by the journal of computer graphics techniques

  2. Algorithmic Nodes for Enhanced Control:

    • Linear Ramp: Allows artists to create custom gradients for color transitions, providing precise control over material appearances.

    • Vector Warp: Introduces distortions and warping effects to procedural textures, adding organic and natural variation to the materials.

    • Bi-linear Ramp: A specialized ramp node for achieving smooth transitions between color values along two axes, facilitating complex material blending.

    • Primitive Shape: Enables the generation of basic geometric shapes procedurally, streamlining the material creation process.

    • Pseudo Histogram: Simulates histogram equalization effects to adjust the distribution of pixel intensities within textures, enhancing contrast and tonal balance.

    • Pseudo Contrast: A node for emulating contrast adjustments in procedural materials, creating visually striking and impactful results.

    • Quantize: Allows the quantization of procedural textures, useful for achieving pixelated or stylized looks.

    • Edge-Damage: Adds wear and tear effects to materials by simulating edge damage and weathering.

    • Blur: An innovative implementation of blurring effects within OSL, bypassing the limitations of neighboring pixel information.

  3. Custom Shading Models:

    • Arnold Standard Surface

    • Volumetric fire

    • custom Bxdf's


Benefits and Impact:

  1. Unprecedented Material Authoring Capabilities: The Procedural Material Function Library significantly expands Blender's material authoring possibilities by offering a diverse range of functions that were previously inaccessible or time-consuming to create.

  2. Realism and Artistic Control: Artists gain precise control over procedural textures and can achieve realistic materials with complex variations and details, empowering them to bring their artistic visions to life.

  3. Improved Image Processing in OSL: The implementation of blur, contrast, and histogram-like effects using OSL showcases novel techniques to overcome inherent limitations, further elevating Blender's procedural material capabilities.

  4. Cross-Platform Collaboration: The compatibility of OSL shaders with most DCC platforms fosters collaboration and enables seamless asset transfer across different software environments.

Conclusion:

The Procedural Material Function Library for Blender is a project that pushes the boundaries of material authoring in Blender. By introducing a comprehensive set of material functions using OSL, including advanced noise generation algorithms and algorithmic nodes, this project empowers artists to create intricate, realistic, and visually captivating procedural materials. The creative ability to achieve image processing effects within OSL opens up new possibilities, while the cross-platform compatibility promotes collaboration and interoperability within the CG community. This project stands as a testament to the power of innovation and its potential to elevate the capabilities of digital content creation tools like Blender.

More info on the individual shaders below…


This documentation is not complete and will be expanded over time to include missing nodes**

4 way gradient ramp

4 way bilinear color gradient ramp

shader ramp4(
    output color result = color(0.0, 0.0, 0.0),
    color valuetl = color(0, 0, 0),
    color valuetr = color(0, 0, 0),
    color valuebl = 0,
    color valuebr = 0,
    vector texcoord = vector(0.0, 0.0, 0.0)
)
{
    // Extract the UV coordinates
    float U = texcoord[0];
    float V = texcoord[1];

    // Perform bilinear interpolation
    color valueTop = mix(valuetl, valuetr, U);
    color valueBottom = mix(valuebl, valuebr, U);
    result = mix(valueBottom, valueTop, V);
}


Cell Noise

A modified cellular noise, based off the built in callnoise function

shader cellnoise2d(
    output color result = color(0, 0, 0),
    float period = 0,
    vector texcoord = vector(0, 0, 0),
)
{
    // Calculate the cell coordinates
    vector cellCoord = floor(texcoord);
    
    // Calculate the subcell coordinates
    vector subCell = texcoord - cellCoord;
    
    // Calculate the nearest integer cell coordinates
    vector nearestCell = floor(texcoord + 0.5);
    
    // Calculate the distance vectors to the nearest cell and its neighbors
    vector diffCell = vector(period, period, period) - mod(nearestCell, vector(period, period, period));
    
    // Calculate the nearest cell value
    float cellValue = noise("cell", nearestCell);

    // Calculate the distances to the 4 neighbors
    float dNW = length(subCell + vector(-1,  1, 0) - diffCell);
    float dNE = length(subCell + vector( 1,  1, 0) - diffCell);
    float dSW = length(subCell + vector(-1, -1, 0) - diffCell);
    float dSE = length(subCell + vector( 1, -1, 0) - diffCell);

    // Find the two closest neighbors
    float minDist1 = min(min(dNW, dNE), min(dSW, dSE));
    float minDist2 = min(max(dNW, dNE), max(dSW, dSE));
    
    // Calculate the distance to the border of the cell
    float borderDist = min(minDist1, minDist2);
    
    // Normalize the border distance and use it as the noise value
    cellValue = borderDist / diffCell[0];

    // Set the result based on the number of output channels
    result = cellValue;
}

Alligator noise

This is the same alligator noise from SideFX Houdini, translated and with minor edits to run in Blender

//Alligator Noise is provided by Side Effects Software Inc. and is licensed
/// under a Creative Commons Attribution-ShareAlike 4.0 International License
/*
 * Copyright (c) 2016
 *  Side Effects Software Inc.  All rights reserved.
 *
 * Redistribution and use of Houdini Development Kit samples in source and
 * binary forms, with or without modification, are permitted provided that the
 * following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. The name of Side Effects Software may not be used to endorse or
 *    promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *----------------------------------------------------------------------------
 */
  
/// 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
///
/// further modification by Scott Clayton
/// contact: scottclayton@skiff.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 [0 - 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." ]],
     
    output color result = 0.0
) {
    point objectPosition = transform("object", P);
    point startPosition = start_frequency * objectPosition - start_offset;
     
    float noiseValue = fractalAlligatorNoise3D(startPosition, lacunarity, gain, octaves);
     
    noiseValue = 0.5 * noiseValue;
    noiseValue = pow(noiseValue, attenuation);
     
    result = color(noiseValue);
}

Fractal Noise

The Fractal noise is simply a sum of multiple perlin noise at varying freq and amplitude

shader fractal2d(
    output color result = color(0, 0, 0),
    float amplitude = 1.0,
    int octaves = 3,
    float lacunarity = 2.0,
    float diminish = 0.5,
    float period = 0,
    vector texcoord = vector(0, 0, 0),
)
{
    // Initialize variables for the noise generation
    float freq = 1.0;
    float amp = amplitude;
    color mynoise = color(0, 0, 0);

    // Loop through octaves and sum Perlin noise values
    for (int i = 0; i < octaves; i++)
    {
        mynoise += amp * noise("perlin", freq * texcoord);
        freq *= lacunarity;
        amp *= diminish;
    }

    // Normalize the result to the range [-1, 1] and apply amplitude
    result = 2.0 * (mynoise - 0.5) * amplitude;
}

Perlin Noise

A simple perlin noise implementation

shader perlinnoise(
    output color result = color(0, 0, 0),
    float amplitude = 1.0,
    float pivot = 0.0,
    float period = 0,
    vector texcoord = vector(0, 0, 0),
)
{
    // Calculate the noise value at the given texture coordinates
    color noiseValue = noise("perlin", texcoord * vector(period, period, period)) * amplitude + pivot;
    
    // Set the result based on the number of output channels
    result = noiseValue;
}

Blur

A blur effect. especially dificult since osl does not provide access to neighboring pixels

/*
based off a redshift shader written by Edward Darby Edelen
*/

vector gaussianFromUniform(vector vec_in){
    float u2_sin;
    float u2_cos;

    sincos(M_2PI * vec_in.y, u2_sin, u2_cos);
    float r = sqrt(-2 * log(vec_in.x));
    return vector(r * u2_cos, r * u2_sin, 0);
}

shader Blur(
    float aniso = 0,
    float rotation = 0,
    vector direction = vector(0,1,0),
    vector tangent_in = vector(0, 0, 0),
    float amount = 10,
    output vector UV_offset = vector(0, 0, 0),
)
{
    
    vector anisovec = vector(1 + aniso, 1 - aniso, 0);

    vector myrandom = gaussianFromUniform(noise("perlin", vector(1) - P));
    vector off = gaussianFromUniform(noise("hash", P)) + vector(0,0,myrandom.x);
    vector uv_blur_direct = direction * vector(1,1,0);

    float blur_length = length(uv_blur_direct);
    vector uv_space = vector(0.001);

    uv_blur_direct /= blur_length;

    float uv_blur_rotate = atan2(uv_blur_direct.y, uv_blur_direct.x);
    vector uv_blur_vec = (off.x) * vector(blur_length,0,0);

    UV_offset = rotate(uv_blur_vec, uv_blur_rotate, vector(0,0,1)) * amount * uv_space;

}

Warp

A warping effect that distorts a texture based on a vector input. It is made to run over the UV's and not the texture itself

shader warp(
  point project = point(u, v, 0),
  color distort = 0,
  matrix mytransform = 1,
  output point uvw = 0
)
{
    uvw = transform(1/mytransform, project)+distort;
}

we can also slightly modify the blur shader to achieve an alternative warp…

vector gaussianFromUniform(vector vec_in){
    float u2_sin;
    float u2_cos;

    sincos(M_2PI * vec_in.y, u2_sin, u2_cos);
    float r = sqrt(-2 * log(vec_in.x));
    return vector(r * u2_cos, r * u2_sin, 0);
}

shader altwarp(
    float aniso = 0,
    float rotation = 0,
    vector direction = vector(0,1,0),
    vector tangent_in = vector(0, 0, 0),
    float amount = 10,
    output vector UV_offset = vector(0, 0, 0),
)
{
    
    vector anisovec = vector(1 + aniso, 1 - aniso, 0);

    vector myrandom = gaussianFromUniform(noise("perlin", vector(1) - P));
    vector off = gaussianFromUniform(noise("perlin", P)) + vector(0,0,myrandom.x);
    vector uv_blur_direct = direction * vector(1,1,0);

    float blur_length = length(uv_blur_direct);
    vector uv_space = vector(0.001);

    uv_blur_direct /= blur_length;

    float uv_blur_rotate = atan2(uv_blur_direct.y, uv_blur_direct.x);
    vector uv_blur_vec = (off.x) * vector(blur_length,0,0);

    UV_offset = rotate(uv_blur_vec, uv_blur_rotate, vector(0,0,1)) * amount * uv_space;

}


Linear ramp

A simple linear ramp

shader ramplr(
    output color result = 0,
    color valuel = color(0, 0, 0),
    color valuer = color(0, 0, 0),
    vector texcoord = 0
)
{
    // Extract the U coordinate
    float U = texcoord[0];

    // Perform linear interpolation between valuel and valuer based on U
    result = mix(color(valuel), color(valuer), U);
}

Edge Wear

Edge detection using inverted ambient occlusion


This one was actually done with Native Blender shader nodes, not osl code, but I thought I would include it anyway