Mitchell D. Harper

FX Artist
Open Shading Language | Non-Photorealistic Shading This page shows geometries shaded in such a way that they are intended to mimic the "look" of images recorded by a scanning electron microscope.
Rendered Images
Rendered Animation
Reference Images
I found several images I liked for various reasons, however, I chose the last image listed here. I love the "crumbly" texture of the inside and the chaotic and broken nature of the outer shell. Although it appears to be a simple image, the crumbling effect on the inside looks like it is going to be a challenge.
Technical Breakdown Pixar Visualizer Integrator
Shading Networks
Outside Shell Inside Goo
In this shader I used a lot of different noise nodes to alter the pattern of other noise nodes. While I was searching for more advanced forms of noise I was able to find the Houdini Alligator noise written in OSL under a Creative Commons license. (listed below). The pxrSeExpr essentially adds two noise patterns together and returns the results. In this shader I also used a lot of different noise nodes to alter the pattern of other noise nodes. I also used the Houdini Alligator noise node for a more complex noise pattern. The pxrSeExpr is a little more complex in this shader.

pxrSeExpr

 

resultF = floatInput1 + floatInput2;

resultF

pxrSeExpr

 

anze = floatInput2;

pnze = pow(floatInput1, 3);

combined = (anze + pnze);

resultF = (combined - 1);

resultF

Rings Backdrop
The "rings" shader is a basic displacement shader using pxrWorley and pxrFractal noise. The pxrWorley is controlling the displacement amount and the pxrFractal is controlling the displacement scalar. The backdrop shader is also pretty simple. Two noise nodes, one modulating the amount of displacement AND the frequency of the second noise node. The second noise node then modulates the displacement scalar value.
OSL Shaders

shader

simple_remap

(

    float input = 0,

    float outMin = 0,

    float outMax = 1,

    output float resultF = 0

)

{

 resultF = input * (outMax - outMin) + outMin;

}

 

 

 

 

shader

SEM_Edge

(

    color base = 1,

    color edge = color(1,0,0),

    float strength = 1,

    output color resultRGB = 0,

    output float resultF = 0)

{

 vector n = normalize(N);

 vector i = normalize(I);

 float  d = 1 - abs(dot(n, -i));

 

 d = pow(d, strength);

 resultRGB = mix(base, edge, d);

 resultF = d;

}

 

 

 

shader

SEM_Noise

(

    float freq = 8,

    float amplitude = 1,

    int   octaves = 3

       [[

       string label = "Details",

       ]],

    float height_clip = -1,

    int clipping = 1 [[ string widget = "checkBox"]],

    string spacename = "object",

    output float resultF = 0)

{

 point p = transform(spacename, P);

 

 int n;

 float FREQ = freq;

 float AMPL = amplitude;

 for(n = 0; n < octaves; n++) {

    resultF += noise("perlin", p * FREQ)/AMPL;

    FREQ *= 2;

    AMPL *= 2;

    }

 if(clipping > 0) {

    resultF -= height_clip;

    if(resultF < 0)

      resultF = 0;

    }

}

 

 

/*

 * 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

 

/// 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

(

    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 + 0.5;

    noiseValue = pow(noiseValue, attenuation);

 

    result = color(noiseValue);

}

 

 

 

Challenges and Technical Issues When I was creating the inside of the spore I used a lot of Mayas standard features. The overall shape of the inner part was a sphere, modified by a texture deformer, which was animated for the video. The "grit" covering the inner sphere was created in MASH. When I tried to batch render the images, all I was getting was the outer cages with NOTHING inside. After a bit of research I decided to export everything that was not rendering to an Alembic file. Everything rendered fine after replacing the non-rendering geometry with the Alembic. Even though we can do a lot with basic noise OSL nodes, I was really looking for a more complex noise pattern. I was able to find the Houdini Alligator noise written as an OSL under a Creative Commons license. This gave me amazing control of the noise patterns. Final Thoughts Even though we were barely scratching the surface of the OSL and SeExpr languages, I am fascinated by the control they provide. I have been doing a lot of "out of class" researching in both areas. I really think this is something I would like to know a lot better!