3

I am currently trying to simulate ballistics on an object, that is otherwise not affected by physics. To be precise, I have a rocket-like projectile, that is following an parabolic arc from origin to target with a Lerp. To make it more realistic, I want it not to move at constant speed, but to slow down towards the climax and speed up on its way back down.

I have used the Mathf.Smoothstep function to do the exact opposite of what i need on other objects, i.e. easing in and out of the motion.

So my question is: How do I get an inverted Smoothstep?

I found out that what i would need is actually the inverted formula to smoothstep [ x * x*(3 - 2*x) ], but being not exactly a math genius, I have no idea how to do that. All I got from online calculators was some pretty massive new function, which I'm afraid would not be very efficient.

So maybe there is a function that comes close to an inverted smoothstep, but isn't as complex to compute.

Any help on this would be much appreciated

Thanks in advance,

Tux

hippietrail
  • 15,848
  • 18
  • 99
  • 158
Tuxedomask
  • 53
  • 2
  • 6

4 Answers4

5

Correct formula is available here: https://www.shadertoy.com/view/MsSBRh

Solution by Inigo Quilez and TinyTexel

Flt SmoothCubeInv(Flt y)
{
   if(y<=0)return 0;
   if(y>=1)return 1;
   return 0.5f-Sin(asinf(1-2*y)/3);
}
Esenthel
  • 499
  • 4
  • 17
3

I had a similar problem. For me, mirroring the curve in y = x worked:

enter image description here

So an implementation example would be:

float Smooth(float x) {
    return x + (x - (x * x * (3.0f - 2.0f * x)));
}

This function has no clamping, so that may have to be added if x can go outside the 0 to 1 interval.

Wolfram Alpha example

FeatureCreep
  • 1,784
  • 1
  • 19
  • 23
  • 1
    This may be a suitable approximation for some, but it is definitely not an exact inverse. [This answer](https://stackoverflow.com/a/52572849/9310672) shows the exact derived inverse. – Caleb Miller Feb 28 '22 at 03:32
2

If you're moving transforms, it is often a good idea to user iTween or similar animation libraries instead of controlling animation yourself. They have a an easy API and you can set up easing mode too.

But if you need this as a math function, you can use something like this:

y = 0.5 + (x > 0.5 ? 1 : -1) * Mathf.Pow(Mathf.Abs(2x - 1),p)/2

Where p is the measure of steepness that you want. Here's how it looks:

graph

Max Yankov
  • 12,551
  • 12
  • 67
  • 135
0

You seem to want a regular parabola. See the graph of this function:

http://www.wolframalpha.com/input/?i=-%28x%2A2-1%29%5E2%2B1

Which is the graph that seems to do what you want: -(x*2-1)^2+1

It goes from y=0 to y=1 and then back again between x=0 and x=1, staying a bit at the top around x=0.5 . It's what you want, if I understood it correctly.

Other ways to write this function, according to wolfram alpha, would be -(4*(x-1)*x) and (4-4*x)*x

Hope it helps.

jbernardo
  • 159
  • 7
  • First off, thanks for your reply. But, as i am using a lerp-like function to measure the point at which the object is on its way from origin (0) to destination (1), I need a function that starts in 0|0 and ends in 1|1, like Smoothstep does. But instead of easing in then out, i need to ease out and back in, which is the smoothstep function mirrored on the 45° diagonal aka the invesion. Here's what Wolfram Alpha gives as the inverted function to Smoothstep: http://www.wolframalpha.com/input/?i=the%20inverse%20function%20of%20x%20*%20x*(3%20-%202*x)%20is But I need a simplified form of that – Tuxedomask Feb 26 '15 at 13:42
  • @Tuxedomask the inverse function you just sent me does not start in 0|0 and end in 1|1. – jbernardo Feb 26 '15 at 13:53
  • @Tuxedomask. Can you send me a graph of a function that does what you say? – jbernardo Feb 26 '15 at 13:54
  • @jibernardo: it does for the relevant range of [0;1] The graph shows the common smoothstep function _x * x*(3 - 2*x)_ (red) which is built into unity, as well as its inverted version (blue) EDIT: ok, apparently copy/paste doesnt work, so here's a new link: http://shar.es/1Ww17W – Tuxedomask Feb 26 '15 at 14:42
  • @Tuxedomask I've checked your link. The blue plot doesn't represent a function in real terms. A function converts a x value into a single y. If I ask you what y the function would give you for x=0.5, it could be one of two values on that plot. Also, if you press the Result Area on the link you sent me, you can see that the function has a real and imaginary part. It's a complex function. I think that's not quite what you want. – jbernardo Feb 28 '15 at 01:18
  • You're right, i guess. As I said, I am not exactly a maths genius. However, as mentioned in the original post, I don't need an exact inversion of the original function, or any inversion for that matter. I just need a function that produces the same values for the [0;1] range as the inversion does. (that is, the y-values between 0 and 1 - along the 45° diagonal). In other frameworks (i.e. jQuery), there is a function called EaseOutIn that does that. I couldn't figure out the equasion behind it, though. – Tuxedomask Mar 03 '15 at 12:24
  • @Tuxedomask No Idea what that function is. Tried looking, for it, but no function is named exactly like that. http://api.jqueryui.com/easings/ Which one do you mean? – jbernardo Mar 03 '15 at 22:09
  • ok, so i fund this site to generate the function I need: http://www.timotheegroleau.com/Flash/experiments/easing_function_generator.htm . With the out-in-cubic preset i tinkered around and the points working (not perfectly, but close) are _P1=0.5, P2=0.3, P3=0.7, P4=0.5_. Anyhow, it works with 4 variables instead of just x and I haven't been able to break it down yet. – Tuxedomask Mar 04 '15 at 13:30
  • 1
    @Tuxedomask To help you break it down, if t is between 0 and 1, ts=t*t, tc=t*t*t. t means time; ts means time squared; tc means time cubic. This line "var ts=(t/=d)*t;" does two things: it divides t by d, and squares it ( "t/=d" is the same as "t=t/d" ). b is a starting point and c is the height of the curve. So, if your t is already between 0 and 1, do it like this: var ts=t*t; var tc=ts*t; return b+c*(5*tc*ts + -12.5*ts*ts + 13*tc + -7*ts + 2.5*t); If you want an output between 0 and 1, I think you can ditch b and c, but I haven't tested it. Hope this helps. – jbernardo Mar 04 '15 at 20:17