Create Simple Alien Skin with Open Shading Language (OSL)

In today’s post, we are going to use Open Shading Language (OSL) to make a slimy, translucent alien skin. The inspiration for this shader can be found on Youtube (cycles nodes). The full code is below. In addition, check out our Github repository, which has this shader plus several others. If you need a refresher on OSL, check out our intro to OSL post.

final image of slimy alien OSL shader

The Shader Model

The shader model is fairly simple.

BSDF = specular + diffuse + translucent

We add a clear coat on time to give it the overall shininess.

Specular

Specular is the easiest. We have two input factors that we use for specularity: specular and roughness. We feed these into the microfacet_ggx function. Specular is the amount of specularity. Roughness determines how rough the surface is. This affects whether the light bounces directly back to the view or not.

// Specular
closure color finalSpecular = microfacet_ggx(N, roughness) * specular;

Remember that N is a globally defined variable in OSL that describes the normal of the surface at the point being shaded.

specular only part of the shader

Diffuse

The diffuse is also fairly simple:

// Diffuse    
closure color finalDiffuse = diffuse(N) * (1-specular)*(1-transparency)*baseColor;

We simply multiply diffuse(N) by the base color and then give it a weighting that depends on the amount of specularity and transparency.

Translucent

The translucent component is the most complicated. We use the noise function to mix between translucent and transparent.

// Transparent/Translucent
closure color finalTransparent;
float mixNoise = 0.15*noise("usimplex",P*2);
if(mixNoise < 0.75)
{
  finalTransparent = fleckColor*translucent(N) * (mixNoise * 2) * (1-specular)*transparency;
}
else
{
  finalTransparent = transparent()*(1-specular)*transparency;
}

We use the usimplex option, which is unsigned (values between 0 and 1). We multiply the point by 2, which scales the noise larger.

If the noise is less than 0.75, we use translucent(). If it is greater than or equal we use transparent. Note that usimplex has an average value of 0.5, so in most cases, the value will be less than 0.75. We weight the output, depending on the specularity and the input transparency factor.

transparent part of shader

Clear Coat

The final step is to add a clear coat. We use the input ior (index of refraction) factor and the normal in a function called simple_fresnel. The OSL standard includes a fresnel function; however, it is more complicated than we need. Therefore, I added my own simple_fresnel function that is based on the same function in the Surface Car Paint OSL script from CG Lion.

We use another microfacet_ggx with a roughness of 0 multiplied by the output of the simple_fresnel equation (we call this the clear coat weight).

Full Code

Here is the full code:

// Simple Fresnel: Based on Surface Car Paint at https://cg-lion.com/2020/07/25/freebie-advanced-car-paint-osl-shader/
float simple_fresnel(normal nrm, float ior)
{
    float r = pow( ( 1.0 - ior ) / ( 1.0 + ior ), 2.0 );
    return r + ( 1.0 - r ) * pow( 1.0 - fabs( dot( -I, nrm ) ), 5.0 );
}

shader alien(
    color baseColor=color(0,1.0,0),
    color fleckColor=color(0.336,0,1.0),
    float roughness=0.2,
    float transparency=0.75,
    float specular=0.25,
    float ior=1.6,
    float clearCoat=1.0,
    output closure color bsdf=diffuse(N))
{
    // Diffuse    
    closure color finalDiffuse = diffuse(N) * (1-specular)*(1-transparency)*baseColor;
    
    // Transparent/Translucent
    closure color finalTransparent;
    float mixNoise = 0.15*noise("usimplex",P*2);
    if(mixNoise < 0.75)
    {
        finalTransparent = fleckColor*translucent(N) * (mixNoise * 2) * (1-specular)*transparency;
    }
    else
    {
        finalTransparent = transparent()*(1-specular)*transparency;
    }
    
    // Specular
    closure color finalSpecular = microfacet_ggx(N, roughness) * specular;

    // Clear Coat
    float clearCoatWeight = simple_fresnel(N,ior) * clearCoat;
    bsdf =  finalSpecular + finalDiffuse + finalTransparent;
    bsdf = bsdf * (1-clearCoatWeight) + microfacet_ggx(N,0) * clearCoatWeight;
}

Conclusion

This is a fun shader that is not too complicated to understand. I would love to see renders that you create using this shader. Drop a link in the comments.