Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Mapping or scaling values to a new range

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

  1. seejayjames

    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!
     
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    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)
    7.         return to;
    8.     return (to - from) * ((value - from2) / (to2 - from2)) + from;
    9. }
    --Eric
     
  3. seejayjames

    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

    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

    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){
    5.             return to;
    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

    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

    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

    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

    Batuhan13

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

    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

    CaseyHofland

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

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,354
    No, this topic is specifically not about InverseLerp. We all already know about that.

    --Eric
     
  13. CaseyHofland

    CaseyHofland

    Joined:
    Mar 18, 2016
    Posts:
    388
    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