Mapping or scaling values to a new range

Discussion in 'Scripting' started by seejayjames, Apr 28, 2013.

1. seejayjames

Joined:
Jan 28, 2013
Posts:
664
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!

Volunteer ModeratorModerator

Joined:
Jul 19, 2006
Posts:
32,354
You can use a Lerp/InverseLerp combo:

Code (csharp):
1. 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:

Code (csharp):
1. var result = SuperLerp (10, 100, 1, 5, 3);
2.
3. function SuperLerp (from : float, to : float, from2 : float, to2 : float, value : float) {
4.     if (value <= from2)
5.         return from;
6.     else if (value >= to2)
8.     return (to - from) * ((value - from2) / (to2 - from2)) + from;
9. }
--Eric

3. seejayjames

Joined:
Jan 28, 2013
Posts:
664
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!

nachoman81 likes this.
4. yourulenl

Joined:
Jun 20, 2014
Posts:
1
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
Code (csharp):
1. public float scale(float OldMin, float OldMax, float NewMin, float NewMax, float OldValue){
2.
3.     float OldRange = (OldMax - OldMin);
4.     float NewRange = (NewMax - NewMin);
5.     float NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin;
6.
7.     return(NewValue);
8. }
Usage:
Code (csharp):
1. float scaleMe = 0.5F;
2. float scaled = scale(0F, 1F, 10F, 20F, scaleMe);
Returns: 15

Trellace, suIly, Batuhan13 and 4 others like this.
5. PeterWilkinson

Joined:
Dec 4, 2012
Posts:
5
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).

Code (CSharp):
1. public float Map(float from, float to, float from2, float to2, float value){
2.         if(value <= from2){
3.             return from;
4.         }else if(value >= to2){
6.         }else{
7.             return (to - from) * ((value - from2) / (to2 - from2)) + from;
8.         }
9.     }
Code (CSharp):
1. Debug.Log(Map(0,10,0,1024,500));

Last edited: Mar 26, 2015
6. moshangmusic

Joined:
Jul 16, 2015
Posts:
9
Hey @EID,
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.
Code (csharp):
1.
2.     public double Map(double x, double in_min, double in_max, double out_min, double out_max)
3.     {
4.         return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
5.     }
6.

7. Kiwasi

Joined:
Dec 5, 2013
Posts:
16,860
Since its back up top, animation curves are another way of mapping values between ranges with a bit more flexibility.

8. CaseyHofland

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

Code (csharp):
1.
2.     using System;
3.
4.     public double Map(double x, double in_min, double in_max, double out_min, double out_max, bool clamp = false)
5.     {
6.         if (clamp) x = Math.Max(in_min, Math.Min(x, in_max));
7.         return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
8.     }
9.
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.

9. Batuhan13

Joined:
Apr 9, 2017
Posts:
117
Thanks it is working great =)

10. toonlets

Joined:
Apr 3, 2021
Posts:
10
I'm surprised there isn't a fit function as part of Mathf. Both "fit" and "fit01."

11. CaseyHofland

Joined:
Mar 18, 2016
Posts:
388
fit01 would be Mathf.InverseLerp

Volunteer ModeratorModerator

Joined:
Jul 19, 2006
Posts:
32,354
``Mathf.InverseLerp(10, 30, 20); // = 0.5f``