Mapping or scaling values to a new range

Hi all, searched around a bit and didn’t find anything, but certainly could have missed it.

Wondering if there’s a built-in function which can take a value and scale/map it to a different range, where you can set the input and output ranges. For example:

inputLow = 1, inputHigh = 5
outputLow = 10, outputHigh = 100

if you send in 1, you’ll get 10; if you send in 3, you’ll get 60; if you send in 5, you’ll get 100.

So it’s an offset-plus-scale, all in one. I suppose you can just roll your own each time, but wondering if it exists already as a function (and maybe with exponential scaling?)

I know other languages have this, just wondering if it was something obvious I missed…maybe some trick with Lerp?

Thanks!

You can use a Lerp/InverseLerp combo:

var result = Mathf.Lerp (10, 100, Mathf.InverseLerp (1, 5, 3));

Or a function I wrote to do this a while ago, which has the advantage of a little better performance in addition to somewhat simpler syntax:

var result = SuperLerp (10, 100, 1, 5, 3);

function SuperLerp (from : float, to : float, from2 : float, to2 : float, value : float) {
	if (value <= from2)
		return from;
	else if (value >= to2)
		return to;
	return (to - from) * ((value - from2) / (to2 - from2)) + from;
}

–Eric

7 Likes

Ah, that’s it! I had that formula around somewhere (from Max/MSP “scale” object) but couldn’t remember it exactly. Same as processing’s “map” function. Might be nice to have it as a built-in function in Unity like “Mathf.Map” or something.

Interesting about the Lerp/InverseLerp combo idea too, I’ll have to experiment with that.

Thanks for the info!

1 Like

These solutions didn’t work for me after translating them to C#
I ported a solution I found on stackoverflow. Maybe this is useful for somebody else

public float scale(float OldMin, float OldMax, float NewMin, float NewMax, float OldValue){

    float OldRange = (OldMax - OldMin);
    float NewRange = (NewMax - NewMin);
    float NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin;

    return(NewValue);
}

Usage:

float scaleMe = 0.5F;
float scaled = scale(0F, 1F, 10F, 20F, scaleMe);

Returns: 15

8 Likes

Thanks Eric5h5, I needed that as well. I rewrote the function in C# and called it Map for simplicity (hopefully not affecting any reserved names, though it seems to work fine).

public float Map(float from, float to, float from2, float to2, float value){
        if(value <= from2){
            return from;
        }else if(value >= to2){
            return to;
        }else{
            return (to - from) * ((value - from2) / (to2 - from2)) + from;
        }
    }
Debug.Log(Map(0,10,0,1024,500));

Hey @PeterWilkinson ,
Somehow the code above didn’t work for me, but the actual Arduino map function works well with minor modification (changing long datatype to double) - at least in my application.

    public double Map(double x, double in_min, double in_max, double out_min, double out_max)
    {
        return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
    }
6 Likes

Since its back up top, animation curves are another way of mapping values between ranges with a bit more flexibility.

'twas the same for me, and Arduino / C++ is probably the function most people will recognize
But if I may add to it:

    using System;

    public double Map(double x, double in_min, double in_max, double out_min, double out_max, bool clamp = false)
    {
        if (clamp) x = Math.Max(in_min, Math.Min(x, in_max));
        return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
    }

Set clamp to true and you’ll be ensured your value is clamped in between in_min and in_max. A neat little parameter for a neat little function.

4 Likes

Thanks it is working great =)

I’m surprised there isn’t a fit function as part of Mathf. Both “fit” and “fit01.”

fit01 would be Mathf.InverseLerp

No, this topic is specifically not about InverseLerp. We all already know about that.

–Eric

But then what is fit01? I would expect “fit 20 to 0 and 1, based on 10 and 30”. That would be Mathf.InverseLerp(10, 30, 20); // = 0.5f