Basic Mathf question?
After looking through the Mathf class in the maunal, I cannot find the method I'm looking for.
Basically I have two ranges of floats:
floatA = 5; floatB = 10;
floatC = 50; floatD = 100;
How can I return a number between floatC and floatD depending on what numbers floatA and floatB are?
For example lets say I'm creating a speedometer:
floatA = 0; (lowest speed) and floatB = 90; (max speed).
Depending on the speed of the vehicle, it should produce a float between floatC and floatD ..how can achieve this?
Produce a number between C and D how...? you want a value between C and D that is at the same ratio between the numbers as the speed is between low speed and high speed? Can you give an example result given the values you have in your question?
Given my example above: floatA = 0; (lowest speed) and floatB = 90; (max speed).
Lets say I'm creating the needle in my speedometer, depending on the vehicle speed the needle will point in a specific direction.
floatC = 0; (resting rotation) floatD = 180; (max speed rotation)
Lets say the speed is 45 mph.. the needle's rotation should be somewhere in between floatC and floatD. This is actually for a speedometer, however I don't want someone to do the work for me. I'm just asking which method in $$anonymous$$athf would be the best choice for this...
Did you take a look at:
https://forum.unity.com/threads/re-map-a-number-from-one-range-to-another.119437/
Example: Speed $$anonymous$$in/$$anonymous$$ax: 0, 90
Needle Angle $$anonymous$$in/$$anonymous$$ax: 0, 180
If speed is 45 then needle angle would 90.
if speed is 22 then needle angel would be 45.
Just examples ty again
Answer by Bunny83 · Feb 25, 2020 at 05:00 PM
What you are looking for is a method which is usually called "map" in other languages. However Mathf doesn't have such a method. Though what map does is actually the chained result of Mathf.InverseLerp and Mathf.Lerp.
So a reference implementation would be
public static class MapFunctionExtension
{
public static float Map(this float aValue, float aFromMin, float aFromMax, float aToMin, float aToMax)
{
return Mathf.Lerp(aToMin, aToMax, Mathf.InverseLerp(aFromMin, aFromMax, aValue);
}
}
With this extension you can simply do
float speed = 10;
float mapped = speed.Map(0, 90, 5, 25);
This will map the value speed from the range 0 - 90 to the range 5 - 25. So in the case of the value 10 we get back a value of 7.2222
Of course this is just an example implementation. A better solution is to implement the whole mapping in one function since method calls are not for free.
public static class MapFunctionExtension
{
public static float Map(this float aValue, float aFromMin, float aFromMax, float aToMin, float aToMax)
{
// value between 0 and 1
float t = (aValue - aFromMin) / (aFromMax - aFromMin);
// clamp t to the 0-1 range
if (t < 0f) t = 0f;
else if (t > 1f) t = 1f;
// lerp back to the new range
return aToMin * (1-t) + aToMax * (t);
}
}
This would do pretty much the same as the above method but more efficient. Note there are no safety checks when min and max have the same value. Though this should never be the case anyways. Just for reference, this is how Unity implemented InverseLerp, Lerp and Clamp01.
I appreciate the in-depth answer...this is exactly what I was looking for. Thank you again!
Note a more common way to lerp a value is to use
aTo$$anonymous$$in + t * (aTo$$anonymous$$ax - aTo$$anonymous$$in);
However using aTo$$anonymous$$in * (1-t) + aTo$$anonymous$$ax * (t);
is more numerically stable and ensures to return aTo$$anonymous$$ax at a t value of 1f. With the first way that's not guaranteed for a relatively large range and a small $$anonymous$$ value.
Answer by Bonfire-Boy · Feb 25, 2020 at 05:07 PM
Think of it as two calculations.
First, you want to find out what proportion of the distance your number is between A and B.
Second, you want to apply that proportion to the interval (C, D).
These 2 calculations can be performed using Mathf.InverseLerp and Mathf.Lerp respectively.
Assuming a dial-type speedometer, where what you're looking for is the angle for a given speed, you want something like this...
float minSpeed = 0; float maxSpeed = 100;
float minAngle = 50; float maxAngle = 170;
float AngleForSpeed(float speed)
{
float t = Mathf.InverseLerp( minSpeed, maxSpeed, speed);
return Mathf.Lerp(minAngle, maxAngle, t);
}
This is also a very good option. I wish I can mark both of you as correct answers, I appreciate both answers. I'm going to let Bunny83 keep the answer since he answered first, however your response definitely helped me realize there are a few ways to achieve my goal
Your answer
Follow this Question
Related Questions
Unit Circle Coordinates 0 Answers
Rotation Direction 2 Answers
Problems with instantiated objects in a circle formation 0 Answers
Mathf.Clamp does not work at all. 1 Answer
3 by 1 grid with mathf.round and ScreenToWorldPoint 1 Answer