Remapping functions

Close Experiment

Remapping functions

When writing shader or during1 any procedural creation process (texturing, modeling, shading, animation...) you often find yourself modifying signals in different ways so they behave the way you need. It is common to use smoothstep() to threshold some values, or pow() to shape a signal, or clamp() to clip it, mod() to make it repeat, a mix() to blend between two signals, exp() for attenuatation, etc etc. All these functions are often conveniently available by default in most languages. However there are some operations that are also relativelly used that don't come by default in any language. The following is a list of some of the functions (of families of functions rather) that I find myself using over and over again. You can the Graphoy links in each so you can explore them interactively:

Almost Identity V1

Imagine you don't want to modify a signal unless it's drops to zero or close to it, in which case you want to replace the value with a small possitive constant. Then, rather than clamping the value and introduce a discontinuity, you can smoothly blend the signal into the desired clipped value. So, let m be the threshold (anything above m stays unchanged), and n the value things will take when the signal is zero. Then, the following function does the soft clipping 2 (in a cubic fashion):

float almostIdentity( float x, float m, float n )
{
    if( x>m ) return x;
    float a = 2.0*n - m;
    float b = 2.0*m - 3.0*n;
    float t = x/m;
    return (a*t + b)*t*t + n;
}

Almost Identity V2

A different way to achieve a near identity is through the square root of a biased square. I saw this technique first in a shader by user "omeometo" in Shadertoy. This approach can be a bit slower than the cubic above, depending on the hardware, but I find myself using it a lot these days, specially for "smooth mirroring" shapes, since it behaves almost like the absolute value of x. While it has zero derivative, it has a non-zero second derivative, so keep an eye in case it causes problems in your application.

float almostIdentity( float x, float n )
{
    return sqrt(x*x+n*n);
}
  1. A footnote!
  2. Another footnote!