Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by MadJohny · Dec 19, 2013 at 10:44 AM · lerpaxisfloatmathfpressing

Mathf.Lerp not working as expected

Hi, I am trying to make a really simple task but for some reason it's not working, I simply want this:

  • When I'm clicking in a certain object, a float goes from it's current value to 1f, over half a second.

  • When I'm not clicking that one object, the float would go from it's current value to 0f, also over half a second.

The point of this is to simulate an Axis. For some reason, this isn't working as I expected:

 using UnityEngine;
 using System.Collections;
 
 public class Player : MonoBehaviour {
 
     public float Axis;
     public bool pressing = false;
 
     void Update () {
         if (pressing) {
                 Axis = Mathf.Lerp(Axis,1f,0.5f);
         }
         if (!pressing) {
             Axis = Mathf.Lerp(Axis,0f,0.5f);
         }
     }
 
     void OnMouseDown () {
         pressing = true;
     }
 
     void OnMouseUp () {
         pressing = false;
     }
 
     void OnGUI () {
         GUILayout.Label(Axis.ToString());
     }
 }

It works fine when I'm pressing, but when I stop pressing, it kinda goes insane and takes alot more time than when I'm pressing and some weird values appear like this: 1.455192E-11 and I fell like that isn't necessarie since when I'm pressing it always works perfectly, one more thing, should I use Time.deltaTime to make the Lerp exactly 0.5 seconds or does Lerp already does that automatically?

Thanks in advance.

Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image kihu · Dec 19, 2013 at 11:12 AM 0
Share

$$anonymous$$athf.lerp doesn't return values over time. It just returns one value, once.

According to this: http://docs.unity3d.com/Documentation/ScriptReference/$$anonymous$$athf.Lerp.html

'When t = 0.5 returns the average of a and b.'

So given Axis == 1f: Axis = $$anonymous$$athf.Lerp(1,0f,0.5f); // returns 0.5f

If you're still not pressing: Axis = $$anonymous$$athf.Lerp(0.5f, 0f, 0.5f); // returns 0.25f

If you're still not pressing: Axis = $$anonymous$$athf.Lerp(0.25f, 0f, 0.5f); // returns 0.125f

etc.

If computers could be infinitely precise, you wouldn't reach zero ever. I'd say the weird behavior you get partially comes from how Unity (or .NET or CPU) handles precision.

avatar image KellyThomas · Dec 19, 2013 at 11:16 AM 0
Share

Just a quick note: 1.455192E-11 is very close to zero.

2 Replies

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by thk123 · Dec 19, 2013 at 11:17 AM

I don't think lerp works quite how you think it does.

 Lerp(float from, float to, float t);

Means we choose the value that is at a ratio t between from and to. So when you are pressing, you are taking the point half way between Axis and 1.0f. So, suppose Axis starts at 0.0f then the sequence of values it will take is:

 frame  value
 [0]    0.0f
 [1]    0.5f; //half way between 0.0 and 1.0f
 [2]    0.75f // half way between 0.5 and 1.0f
 ...

Clearly this is not a linear interpolation. Instead, what you need to do is store the time that as progressed since pressing. Something like this:

 float timeSincePress;
 float axisStart;

 ...

 void Update()
 {
     timeSincePress += Time.deltaTime;
     if(pressing)
     {
         // here we set axis to be between axisStart and 1.0f
         // where timeSinceLastPress is the time since we pressed
         // and 0.5f is the total time we want it to take 
         // (so when time = 0.5, Axis will = 1.0)
         Axis = Mathf.lerp(axisStart, 1.0f, timeSincePress/0.5f)
     }
     ...
 }

 void OnMouseDown()
 {
     pressing = true;
     timeSincePress = 0.0f;
     axisStart = Axis;
 }

 ...

Still some things to fill in there (like what happens if the user holds the mouse down for more than 0.5 seconds? Currently, Axis will go past one, but hopefully that explains lerp a bit better :)

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image MadJohny · Dec 19, 2013 at 11:29 AM 0
Share

I think I can simply use a $$anonymous$$athf.Clamp right? to fix the issue about going past one. Anyway in timeSinceLastPress += Time.deltaTime did you meant timeSincePress? because I don't find where you assign that one variable.

edit: actually axis doesn't go past one

avatar image thk123 · Dec 19, 2013 at 11:42 AM 0
Share

Yup did mean timeSincePress, and yeah, clamping the value would do., if your saying it already does, I guess Unity's lerp already does the clamp, I guess we all learn something :)

avatar image emalb · Dec 19, 2013 at 11:54 AM 0
Share

$$anonymous$$athf.Lerp reference.

"Interpolates between a and b by t. t is clamped between 0 and 1."

So yup, Unity clamps the third parameter on the way in.

avatar image
1

Answer by emalb · Dec 19, 2013 at 11:32 AM

Lerp doesn't do what you think.

What it does is return a value that's between the first two parameters, using the third parameter to specify how far between.

 Axis = Mathf.Lerp(Axis, 1f, 0.5f);

The above usage will set Axis to be half way between what Axis currently is and 1, because you're passing in 0.5 as the third parameter.

Assuming Axis starts off at zero (and this is currently not reliable because you have not initialised it in your script) then we can look at what will happen to it if we run the above code repeatedly (ie. over a few frames.)

  • 1st frame: Axis changes from 0.0 to 0.5.

  • 2nd frane: Axis changes from 0.5 to 0.75.

  • 3rd frame: Axis changes from 0.75 to 0.875.

  • 4th frame: Axis changes from 0.875 to 0.9375.

And so on.

This demonstrates three things:

1: Using 0.5 does not directly tell anything to happen over a certain amount of time. It controls the speed of change by saying how big a step Axis will change by each time you call lerp. Using 0.5 means step by half the difference between the first two parameters.

2: If you are running at a high frame rate then it will still take the same number of frames to change Axis, but it will happen a lot quicker. This is why you see the use of Time.deltaTime coming into some of the examples.

 Axis = Mathf.Lerp(Axis, 1f, 0.5f * Time.deltaTime);

This will make the behaviour frame rate independent by adjusting the third parameter to reflect how long it's been since the last update. Once you have this setup, you can try using different values in place of the 0.5 to tune the speed of the lerp and get the behaviour that you want.

3: When using lerp like this your Axis value will increase by a smaller and smaller amount as it approaches the second parameter. It's important to appreciate this because what it means is that it's not sensible to rely on a lerped value actually reaching the target. It just gets closer and closer, but more and more gradually with each update. This means that you should always check for reaching the top end by using a slightly more tolerant check, as follows...

 Axis = Mathf.Lerp(Axis, 1f, 0.5f * Time.deltaTime);
 
 if ((1f - Axis) < 0.01f)
 {
     // Got there - well, near enough!
 }

The trouble you're having when you're not pressing is related to point 3. It is actually lerping towards zero, but the value is getting so small that ToString() has started to represent it in scientific notation. The E-11 in the ouput can be interpreted as "really, really, really tiny". 1.455192E-11 is just a compact way of writing 0.00000000001455192. Your Axis has shot towards zero very quickly, but it won't actually ever get there because each time lerp is called, it's taking a smaller step towards zero than the previous time. In fact, the step is half the size each time because of your use of 0.5. Try running your above code with a value of 0.005 instead of 0.5 and you'll see in your output that the value of Axis still ends up in scientific notation, but it will take a lot longer because it's being adjusted by a much smaller step each frame.

Well... I hope this helps. Good luck. :)

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

22 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Using MathF Lerp on a float, please help! 1 Answer

Problem with lerping Y axis 0 Answers

Lerp a Object along X and Z axis only. 3 Answers

Is there a way to smoothly transition between two floats, with it slowing down towards the end 1 Answer

How can i pause gradually from timeScale 1.0 to 0.0 over a second? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges