Hacker Newsnew | past | comments | ask | show | jobs | submit | EsportToys's commentslogin

A middleground is to use fixed timesteps with the closed form solution. Then the integration factors can be statically precomputed as constants, and every frame becomes just a 2x2 matrix multiplication.

And even if you are to calculate the integration factors based on dynamic frame rates, they only need to be computed just once per frame for all objects that share the same damping configuration.


Closed-form (non-iterative) PID solution:

https://www.desmos.com/calculator/mu80ttc9aa

   function sprung_response(t,pos,vel,k,c,m)
      local decay = c/2/m
      local omega = math.sqrt(k/m)
      local resid = decay*decay-omega*omega
      local scale = math.sqrt(math.abs(resid))
      local T1,T0 = t , 1
      if resid<0 then
         T1,T0 = math.sin( scale*t)/scale , math.cos( scale*t)
      elseif resid>0 then
         T1,T0 = math.sinh(scale*t)/scale , math.cosh(scale*t)
      end
      local dissipation = math.exp(-decay*t)
      local evolved_pos = dissipation*( pos*(T0+T1*decay) + vel*(   T1      ) )
      local evolved_vel = dissipation*( pos*(-T1*omega^2) + vel*(T0-T1*decay) )
     return evolved_pos , evolved_vel
   end
For anticipation, just add an extra initial velocity in the opposite direction and let the closed-form solution handle the time evolution. The main trick here is to keep both position and velocity as state. There is no need to “step through the simulation”.


Material Design 3's "motion physics system" uses damped harmonic oscillators, too. The parameters (undamped angular frequency omega0 and damping ratio zeta) they use are on this page:

https://m3.material.io/styles/motion/overview/how-it-works


This is good! Although I'd also say that initial velocity doesn't quite cover what I was talking about in the post -- even anticipation arguably can start from 0 velocity, accelerate backwards, decelerate, then accelerate in the opposite direction. Imo, any sudden change in velocity should by default be avoided (there are always valid uses where breaking that expectation is good, but I'd want it smooth by default.)

That could possibly be done by incrementally changing force to move it back first, then forward, or to model this as a PD controller following an input with some baked in reversal before moving forward. That can still be closed-form (state response to a known input will be; Laplace transforms can help there), but still would need a bit of effort to model and tune to look right.


You wouldn't really need an incremental force: a step-function force (first backward for some time steps, then instantly forward) will still produce a continuous velocity curve.


true! I suppose you'd risk getting some oscillations in the anticipation depending on the scale of the force, but that could be desirable, or might not happen if the scale is small enough, and certainly makes the math a little easier


You can trivially calculate the time-to-peak overshoot using the closed form equation. It’s the first (0-indexed) zero of the velocity response, i.e. happens at t = (pi / scale)

And obviously it would only apply for the underdamped case.


Wow, this is excellent!

Is there a name for this kind of motion? I'd love to use it sometime.


It’s the general solution to a damped harmonic oscillator/mass-spring-damper system:

    m * x’’ + c * x’ + k * x = f(t)
See https://web.archive.org/web/20230604215211/https://esporttoy...


Wow. This is so good. I would never imagine using PID control for animation motion. Saving this.


Wow, this is great!


How did you even find this site; did you make it?


Seconded for Love2D, here's a sample of how simple it is to quickly whip up something in it:

https://github.com/EsportToys/wireworld-love


I was going to write that Love2D had an unusual drawback if you wanted to teach it to a 9-year-old: lots of third-party libraries had sexualized names.

However, this is outdated, and none of the recommended libraries can raise unwelcome questions with their names: https://love2d.org/wiki/Category:Libraries


On that page I see entries such as:

  - Grease
  - HUMP
  - Lovetoys
  - Löve Bone
  - Gspöt
  - Möan
  - fLUIds
To be fair, I doubt most children will question the names! And this is a small enough subset of the libraries that one can just avoid them.


Speaking of 2nd-order linear ODEs w/ const factor (a.k.a. mass-spring-damper systems), I wrote a blog post[0] deriving all possible general solutions in a concise matrix that makes it easily implementable in code.

The following is the complete solution in Lua:

   function sprung_response(t,pos,vel,k,c,m)
      local decay = c/2/m
      local omega = math.sqrt(k/m)
      local resid = decay*decay-omega*omega
      local scale = math.sqrt(math.abs(resid))
      local T1,T0 = t , 1
      if resid<0 then
         T1,T0 = math.sin( scale*t)/scale , math.cos( scale*t)
      elseif resid>0 then
         T1,T0 = math.sinh(scale*t)/scale , math.cosh(scale*t)
      end
      local dissipation = math.exp(-decay*t)
      local evolved_pos = dissipation*( pos*(T0+T1*decay) + vel*(   T1      ) )
      local evolved_vel = dissipation*( pos*(-T1*omega^2) + vel*(T0-T1*decay) )
     return evolved_pos , evolved_vel
   end
[0] https://esporttoys.pages.dev/2022/11/21/damped


This is a good example. That was math heavy, it took me too long to parse for basic understanding and honestly I am not sure I got it right. The LUA code was easy to understand even though those variable names force you to read all the code, and guess what is what.

It has been a long time since I did diff eq at work, and I agree with the PDF the more I knew the less I understood. I dont know why I need to have the math tainted by the unclean reality to understand, and if that hinders my understanding of them.


My grad school was basically working through F=Ma-Cv-Kx in all it's expanding varied glory, working up to full blown finite element analysis.

Ultimately it all comes down to choosing the most convenient basis functions for the questions you're answering.


> My grad school was basically working through F=Ma-Cv-Kx in all it's expanding varied glory, working up to full blown finite element analysis.

If I'm understanding correctly, you want another = there for a standard damped spring: F = ma = -Cv - Kx.


F is a forcing function, not the resultant force. It’s often arranged this way with all the derivatives on one side (as opposed to having the resultant force, ma, on one side of the equality by itself) so that it matches the general form of a non-homogeneous second-order linear differential equation.

(At least I assume this is what the original commenter meant!).


Ah, that makes more sense. Thanks!


Actuall you're missing ClipCursor as another way of moving the cursor.

Also, mouse_event is just a wrapper around what's basically SendInput(mouse)


The friction/acceleration awkwardness can be solved by using a physically based timestep-independent formulation, which I implemented in TPMouse[0] and explained its derivation in a previous comment reply[1].

The gist of it is that the solution to a linearly damped particle is a linear system, so the x and y components can be calculated completely independently and the analytic solution is just an exponential of time.

It is a special case of the timestep-independent damped harmonic oscillator, which I previously wrote a blogpost about [10].

Namely it is the "unsprung" special case under "Overdamped"

The very same formulation is also what I used to implement LibreScroll[11] to add inertial scrolling to any mouse.

[0] https://github.com/EsportToys/TPMouse

[1] https://www.reddit.com/r/Trackballs/comments/ym9q2t/tpmouse_...

[10] https://news.ycombinator.com/item?id=35899215

[11] https://news.ycombinator.com/item?id=36783942


And for Windows, my https://github.com/EsportToys/TPMouse was inspired by warpd itself but more focused on making direct cursor motion more usable using momentum.


Shameless plug, but you may like the Inertia Mode of my TPMouse script[0] if you need a keyboard-based workflow systemwide.

[0] https://github.com/EsportToys/TPMouse


Try running the exe version with wine and see if it works on your system -- this uses only very old/stable WinAPIs so I'd imagine that wine would have it well-covered by now.


> There are two novels that can change a bookish fourteen-year old's life: The Lord of the Rings and Atlas Shrugged. One is a childish fantasy that often engenders a lifelong obsession with its unbelievable heroes, leading to an emotionally stunted, socially crippled adulthood, unable to deal with the real world. The other, of course, involves orcs.

http://kfmonkey.blogspot.com/2009/03/ephemera-2009-7.html


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: