Smoothstep

A plot of the smoothstep(x) and smootherstep(x) functions, using 0 as the left edge and 1 as the right edge

Smoothstep is a family of sigmoid-like interpolation and clamping functions commonly used in computer graphics[1][2] and video game engines.[3]

The function depends on three parameters, the input x, the "left edge" and the "right edge", with the left edge being assumed smaller than the right edge. The function receives a real number x as an argument and returns 0 if x is less than or equal to the left edge, 1 if x is greater than or equal to the right edge, and smoothly interpolates, using a Hermite polynomial, between 0 and 1 otherwise. The slope of the smoothstep function is zero at both edges. This is convenient for creating a sequence of transitions using smoothstep to interpolate each segment as an alternative to using more sophisticated or expensive interpolation techniques.

With no salient loss of generality, the left edge may be set to 0 and the right edge to 1. Then the general form for smoothstep is

is identical to the clamping function:

The characteristic "S"-shaped sigmoid curve is obtained with only for integers N ≥ 1. The order of the polynomial in the general smoothstep is 2N + 1. With N = 1, the slopes or first derivatives of the smoothstep are equal to zero at the left and right edge (x = 0 and x = 1), where the curve is appended to the constant or saturated levels. With higher integer N, the second and higher derivatives are zero at the edges, making the polynomial functions as flat as possible and the splice to the limit values of 0 or 1 more seamless.

In HLSL and GLSL, smoothstep implements the , the cubic Hermite interpolation after clamping:

Again, assuming that the left edge is 0, the right edge is 1, with the transition between edges taking place where 0 ≤ x ≤ 1.

A C/C++ example implementation provided by AMD[4] follows.

float smoothstep(float edge0, float edge1, float x) {
  // Scale, bias and saturate x to 0..1 range
  x = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); 
  // Evaluate polynomial
  return x * x * (3 - 2 * x);
}

float clamp(float x, float lowerlimit, float upperlimit) {
  if (x < lowerlimit)
    x = lowerlimit;
  if (x > upperlimit)
    x = upperlimit;
  return x;
}

Variations

Ken Perlin suggests[5] an improved version of the smoothstep function, which has zero 1st- and 2nd-order derivatives at x = 0 and x = 1:

C/C++ reference implementation:

float smootherstep(float edge0, float edge1, float x) {
  // Scale, and clamp x to 0..1 range
  x = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
  // Evaluate polynomial
  return x * x * x * (x * (x * 6 - 15) + 10);
}

float clamp(float x, float lowerlimit, float upperlimit) {
  if (x < lowerlimit)
    x = lowerlimit;
  if (x > upperlimit)
    x = upperlimit;
  return x;
}

Origin

3rd-order equation

Starting with a generic third-order polynomial function and its first derivative:

Applying the desired values for the function at both endpoints:

Applying the desired values for the first derivative of the function at both endpoints:

Solving the system of 4 unknowns formed by the last 4 equations result in the values of the polynomial coefficients:

This results in the third-order "smoothstep" function:

5th-order equation

Starting with a generic fifth-order polynomial function, its first derivative and its second derivative:

Applying the desired values for the function at both endpoints:

Applying the desired values for the first derivative of the function at both endpoints:

Applying the desired values for the second derivative of the function at both endpoints:

Solving the system of 6 unknowns formed by the last 6 equations result in the values of the polynomial coefficients:

This results in the fifth-order "smootherstep" function:

7th-order equation

Also called "smootheststep", the 7th-order equation was derived by Kyle McDonald and first posted to Twitter[6] with a derivation on GitHub:[7]

Generalization to higher-order equations

Smoothstep polynomials are generalized, with 0 ≤ x ≤ 1 as

where N determines the order of the resulting polynomial function, which is 2N + 1. The first seven smoothstep polynomials, with 0 ≤ x ≤ 1, are

It can be shown that the smoothstep polynomials that transition from 0 to 1 when x transitions from 0 to 1 can be simply mapped to odd-symmetry polynomials

where

and

The argument of RN(x) is −1 ≤ x ≤ 1 and is appended to the constant −1 on the left and +1 at the right.

An implementation of in Javascript:[8]

// Generalized smoothstep
function generalSmoothStep(N, x) {
  x = clamp(x, 0, 1); // x must be equal to or between 0 and 1
  var result = 0;
  for (var n = 0; n <= N; ++n)
    result += pascalTriangle(-N - 1, n) *
              pascalTriangle(2 * N + 1, N - n) *
              Math.pow(x, N + n + 1));
  return result;
}

// Returns binomial coefficient without explicit use of factorials,
// which can't be used with negative integers
function pascalTriangle(a, b) {
  var result = 1; 
  for(var i = 0; i < b; ++i)
    result *= (a - i) / (i + 1);
  return result;
}

function clamp(x, lowerlimit, upperlimit) {
  if (x < lowerlimit)
    x = lowerlimit;
  if (x > upperlimit)
    x = upperlimit;
  return x;
}

References

  1. Smoothstep at Microsoft Developer Network.
  2. GLSL Language Specification, Version 1.40.
  3. Unity game engine SmoothStep documentation.
  4. ATI R3x0 Pixel Shaders.
  5. Texturing and Modeling, Third Edition: A Procedural Approach.
  6. @kcimc (25 March 2015). "smootheststep(t)=-20*t^7+70*t^6-84*t^5+35*t^4 // when smootherstep's second derivative isn't enough" (Tweet) via Twitter.
  7. Kyle McDonald (27 March 2015). "Derivation of 7th-order smoothstep function with zeros in third derivative". Github.com. Retrieved 20 December 2015.
  8. http://stackoverflow.com/questions/41195063/general-smoothstep-equation/.
This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.