Useful functions
This is a collection of functions used in game development that often come in handy.
Linear interpolation
float Lerp(float a, float b, float t)
{
return a * (1 - t) + b * t;
}
Exponential interpolation
Linear interpolation for multiplicative quantities like pitch, scale, zoom, etc.
// Source: Freya Holmér
float Eerp(float a, float b, float t)
{
return a * float.Exp(t * float.Log(b/a));
}
Exponential decay
Exponential decay interpolation over given time interval. Good values for decay
sit between 1 and 25, from slow to fast.
// Source: Freya Holmér
float ExpDecay(float a, float b, float decay, float dt)
{
return b + (a-b) * float.Exp(-decay * dt);
}
Map
Maps a value s
in range a1
-a2
to b1
-b2
.
float Map(float a1, float a2, float b1, float b2, float s)
{
return b1 + (s - a1) * (b2 - b1) / (a2 - a1);
}
Smooth approach
Smoothly transitions from pastPosition
to targetPosition
given a speed
and deltaTime
. Good values for speed
hover around 20.
// Source: luispedrofonseca
float SmoothApproach(float pastPosition, float pastTargetPosition, float targetPosition, float speed, float deltaTime)
{
var t = deltaTime * speed;
var v = (targetPosition - pastTargetPosition) / t;
var f = pastPosition - pastTargetPosition + v;
return targetPosition - v + f * float.Exp(-t);
}
float SmoothApproach(float pastPosition, float targetPosition, float speed, float deltaTime)
{
// if past target position isn't known, this is fine too
return SmoothApproach(pastPosition, targetPosition, targetPosition, speed, deltaTime);
}
Snap
Snap a value to increments of snapSize
.
float Snap(float x, float snapSize)
{
return float.Round(x / snapSize) * snapSize;
}
Smoothstep
Maps a value x
from range edge0
-edge1
to 0-1 with smooth easing. Sometimes referred to as the “most useful function”.
float Smoothstep(float edge0, float edge1, float x)
{
var t = float.Clamp((x - edge0) / (edge1 - edge0), 0, 1);
return t * t * (3f - 2f * t);
}
HSV - RGB conversion
Functions to convert HSV to RBG and back. All values range from 0 to 1, even hue.
void GetHsv(Vector3 rgb, out float h, out float s, out float v)
{
float R = rgb.X;
float G = rgb.Y;
float B = rgb.Z;
float max = float.Max(R, float.Max(G, B));
float min = float.Min(R, float.Min(G, B));
float delta = max - min;
if (delta == 0)
h = 0;
else if (max == R)
h = ((G - B) / delta) % 6;
else if (max == G)
h = (B - R) / delta + 2;
else // max == B
h = (R - G) / delta + 4;
h /= 6;
if (h < 0)
h += 1;
s = max == 0 ? 0 : delta / max;
v = max;
}
Vector3 FromHsv(float h, float s, float v)
{
float r = 0, g = 0, b = 0;
float i = (int)(h * 6);
float f = h * 6 - i;
float p = v * (1 - s);
float q = v * (1 - f * s);
float t = v * (1 - (1 - f) * s);
switch (((int)i) % 6)
{
case 0:
r = v; g = t; b = p;
break;
case 1:
r = q; g = v; b = p;
break;
case 2:
r = p; g = v; b = t;
break;
case 3:
r = p; g = q; b = v;
break;
case 4:
r = t; g = p; b = v;
break;
case 5:
r = v; g = p; b = q;
break;
}
return new Vector3(r, g, b);
}
Blackbody temperature to RGB
Assuming an ideal blackbody radiator, this function returns the RGB approximation (ranged 0 to 1) of the given temperature in Kelvin.
Vector3 BlackbodyToColor(float kelvin)
{
var temp = kelvin / 100;
var color = new Vector3();
if (temp <= 66)
{
color.X = 255;
color.Y = temp;
color.Y = 99.4708025861f * float.Log(color.Y) - 161.1195681661f;
if (temp <= 19)
color.Z = 0;
else
{
color.Z = temp - 10;
color.Z = 138.5177312231f * float.Log(color.Z) - 305.0447927307f;
}
}
else
{
color.X = temp - 60;
color.X = 329.698727446f * float.Pow(color.X, -0.1332047592f);
color.Y = temp - 60;
color.Y = 288.1221695283f * float.Pow(color.Y, -0.0755148492f);
color.Z = 255f;
}
return new Vector3(
color.X / 255f,
color.Y / 255f,
color.Z / 255f
);
}
Open explorer
Opens explorer on most systems.
void OpenExplorer(string path)
{
string executable;
if (OperatingSystem.IsWindows())
executable = "explorer";
else if (OperatingSystem.IsMacOS())
executable = "open";
else if (OperatingSystem.IsLinux())
executable = "xdg-open";
else return;
System.Diagnostics.Process.Start(executable, path);
}
Open browser
Opens browser on most systems.
void OpenBrowser(string url)
{
try
{
System.Diagnostics.Process.Start(url);
}
catch (Exception)
{
if (OperatingSystem.IsWindows())
{
url = url.Replace("&", "^&");
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true });
}
else if (OperatingSystem.IsMacOS())
System.Diagnostics.Process.Start("open", url);
else if (OperatingSystem.IsLinux())
System.Diagnostics.Process.Start("xdg-open", url);
else
throw;
}
}