Created
February 7, 2024 15:33
-
-
Save jmschrack/484646fb093247a4e24c8cbd18dd63f0 to your computer and use it in GitHub Desktop.
SmoothDamp filter for js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Critically Damped Ease-In/Ease-Out Smoothing | |
| * reference: "Game Programming Gems 4" Chapter 1.10 (ISBN-13: 978-1584502951) | |
| * https://archive.org/details/game-programming-gems-4/mode/2up (page 96) | |
| * Originally named "SmoothCD", but Unity calls this "SmoothDamp" so we'll stick with that for easier time with google | |
| * If you want the filter to keep track of the delta time, use the "filter" function. If you just want to pass in the delta time, use "update" | |
| * I've modified this to run on an array (i.e. matrices), it makes 2 assumptions: | |
| * 1) Every value uses the same smoothTime and maxSpeed | |
| * 2) Every value can be modified independently of each other | |
| */ | |
| export class SmoothDampFilter { | |
| constructor({ smoothTime = 0.1, maxSpeed = Number.MAX_VALUE }) { | |
| super(); | |
| this.current = []; | |
| this.currentVelocity = []; | |
| console.log("SmoothDampFilter: smoothTime",smoothTime," maxSpeed:",maxSpeed); | |
| this.smoothTime = Math.max(smoothTime, 0.0001); | |
| this.maxSpeed = maxSpeed; | |
| this.maxChange = this.maxSpeed * this.smoothTime; | |
| this.negMaxChange=-1.0*this.maxChange | |
| this.omega = 2.0 / smoothTime; | |
| this.lastTime = 0; | |
| this.initialized = false; | |
| } | |
| reset() { | |
| this.initialized = false; | |
| } | |
| /** | |
| * | |
| * @param {number} timestamp Date.now() | |
| * @param {Array<number>} target | |
| * @returns | |
| */ | |
| filter(timestamp,target){ | |
| const deltaTime = (timestamp - this.lastTime)*0.001; | |
| this.update(deltaTime,target); | |
| this.lastTime = timestamp; | |
| } | |
| update(deltaTime, target) { | |
| //this.current is updated with the new matrix everytime | |
| if (!this.initialized) { | |
| this.currentVelocity= target.map(()=>0);//this.currentVelocity.fill(0, 0, target.length); | |
| this.current=target.map((value)=>{return value;}); | |
| //output.push(...target); | |
| this.initialized = true; | |
| } else { | |
| const deltaTime = (timestamp - this.lastTime)*0.001; | |
| const x = this.omega * deltaTime; | |
| const exp = 1.0 / (1.0 + x + 0.48 * x * x + 0.235 * x * x * x); | |
| //for (let i = 0; i < target.length; i++) { | |
| target.forEach((value,i)=>{ | |
| const originalTo = value; | |
| //clamp the change between negative and positive max change | |
| const change = Math.min(Math.max(this.current[i] - value, this.negMaxChange), this.maxChange); | |
| const _target = this.current[i] - change; | |
| const temp = (this.currentVelocity[i] + this.omega * change) * deltaTime; | |
| this.currentVelocity[i] = (this.currentVelocity[i] - this.omega * temp) * exp; | |
| let out = _target + (change + temp) * exp; | |
| if (originalTo - this.current[i] > 0.0 == out > originalTo) { | |
| out = originalTo; | |
| this.currentVelocity[i] = (out - originalTo) / deltaTime; | |
| } | |
| this.current[i] = out; | |
| }); | |
| } | |
| return this.current; | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment