Jump to content
  • Advertisement
  • 08/21/18 03:56 AM

    A Brief Introduction to Lerp

    General and Gameplay Programming

    mattdesl

    Linear interpolation (sometimes called 'lerp' or 'mix') is a really handy function for creative coding, game development and generative art.

    The function interpolates within the range [start..end] based on a 't' parameter, where 't' is typically within a [0..1] range.

    carbon (24).png

     

    For example, divide 'loop time' by 'loop duration' and you get a 't' value between 0.0 and 1.0.

    Now you can map this 't' value to a new range, such as `lerp(20, 50, t)` to gradually increase a circle's radius, or `lerp(20, 10, t)` to gradually decrease its line thickness.

    2018.08.19-22.40.29.gif

     

    Another example: you can use linear interpolation to smoothly animate from one coordinate to another. Define a start point (x1, y1) and end point (x2, y2), then interpolate the 'x' and 'y' dimensions separately to find the computed point in between.

    2018.08.19-22.41.19.gif

     

    Or use linear interpolation to spring toward a moving target. Each frame, interpolate from the current value to the target value with a small 't' parameter, such as 0.05.

    It's like saying: walk 5% toward the target each frame.

    2018.08.19-22.40.53.gif

     

    A more advanced example, but built on the same concept, is interpolating from one color (red) to another (blue).

    To do this, we interpolate the (R, G, B) or (H, S, L) channels of the color individually, just like we would with a 2D or 3D coordinate.

    2018.08.19-22.39.52.gif

     

    Another quick example is to choose a random point along a line segment.

    There are lots of ways to use linear interpolation, and lots more types of interpolation (cubic, bilinear, etc). These concepts also lead nicely into areas like: curves, splines and parametric equations.

    carbon (25).png

     

    Source code for each of these examples is available here: https://gist.github.com/mattdesl/3675c85a72075557dbb6b9e3e04a53d9

     

    About the author:
    Matt DesLauriers is a creative coder and generative artist based in London. He combines code and emergent systems to make art for the web, print media, and physical installations.

     

    Note:
    This brief introduction to lerp was originally published as a Twitter thread and is republished here with the kind permission of the original author.

    [Wayback Machine Archive]



      Report Article


    User Feedback


    Very cool article! :) I use linear interpolation to smooth out visual movement, it works very nicely with variable render rates. It's also nice for visual effects like shown above. :) 

    Thanks for sharing!

    Share this comment


    Link to comment
    Share on other sites

    Nice article! I loved the visual examples.

    I can't say how many times lerp has been the tool of choice to achieve zillions of nice looking effects using shaders, plus is the basis of rasterization!

    Keep the good work :)

    Share this comment


    Link to comment
    Share on other sites

    Note that your "springing toward" example (lerping a fraction of the remaining distance each time) is highly frame-rate dependent.  So if your game isn't frame-rate locked (i.e. web-games running on machines with different monitor refresh rates, or even a locked 60 fps game running on a machine too slow to support it) different people may see different behaviors.  The spaceship rotation in George Prosser's DRILL_BIT, for instance, is much harder to use on a slow machine.

    And the way you're doing it, scaling by the deltaTime, will only partly correct for that.  For instance, if your framerate is twice as fast (deltaTime is half the length) then you actually need the square root of the rate (you lerp twice in the same time, essentially multiplying by the factor twice, i.e. squaring it).  In the general case you need Math.pow:

    // Return a lerp factor for the given frame time which will result in
    // the value getting convergenceFraction of the way to the target in
    // smoothTime time units.  I usually just use 0.9 or 0.95 for the fraction
    // and vary the smoothTime to get the effect I want.
    function smoothOver(dt, smoothTime, convergenceFraction) {
    	return 1 - Math.pow(1 - convergenceFraction, dt / smoothTime)
    }

    For further adventures in non-linear interpolation things, Squirrel Eiserloh's Fast and Funky 1D Non-linear Transformations GDC talk is well worth a watch.  Although note that with his later (curved) functions, he only mumbles once that he's "normalizing" them (meaning scaling them up so they are exactly one unit tall).  Without knowing that, if you try to use some of the formulas he gives as written, you'll end up with something very flat that does almost nothing.  But he gives a good intuitive introduction to how to think about constructing some of these things.

    Share this comment


    Link to comment
    Share on other sites


    Create an account or sign in to comment

    You need to be a member in order to leave a comment

    Create an account

    Sign up for a new account in our community. It's easy!

    Register a new account

    Sign in

    Already have an account? Sign in here.

    Sign In Now

  • Advertisement
  • Advertisement
  • Latest Featured Articles

  • Featured Blogs

  • Advertisement
  • Popular Now

  • Similar Content

    • By RidiculousName
      I have a class for the NPCs in my game. Each NPC has an athleticism attribute that ranges from zero to one-thousand. I am randomly generating this value. I want 70%-80% people to have a roughly average amount of athleticism, somewhere close to 500.
      Is there some algorithm I can apply that will skew the randomly determined athleticism score so that it's usually close to 500, but always returns a few scores that are either much lower or a lot higher?
    • By DiligentDev
      Hello!
      I recently added a new Diligent Engine tutorial that demonstrates the usage of compute shaders and may be useful on its own. The example app implements a simple GPU particle system that consists of a number of spherical particles moving in random directions and encountering elastic collisions. The simulation and collision detection is performed on the GPU by compute shaders. To accelerate collision detection, the shader subdivides the screen into bins and for every bin creates a list of particles residing in the bin. The number of bins is the same as the number of particles and the bins are distributed evenly on the screen, thus every bin on average contains one particle. The size of the particle does not exceed the bin size, so a particle should only be tested for collision against particles residing in its own or eight neighboring bins, resulting in O(1) algorithmic complexity.
      The full description of the implementation of the method is here.

    • By WeedWilly
      Hey smart people. I'm trying to understand server replay/server reconciliation where the server keeps a list of inputs and game snapshots and goes "back in time" to apply inputs that should have been applied back then, then re-simulates to the present (I think that's all correct, that is my current understanding of it).
      So my biggest confusions about it aren't necessarily how to implement the algorithm, but more what the purpose of the algorithm is (what problems does this prevent?) and when should the algorithm kick in.
      My current understanding of server replay is based on this article https://medium.com/@qingweilim/how-do-multiplayer-game-sync-their-state-part-2-d746fa303950 , and it's really the only one I can find on it.
       
      So my questions:
      - what is the purpose of server replay? My guess is that it makes sure player1's inputs at tickX are executed before player2's input at tickX+1 despite player1's much greater ping. Or does the server always reconcile, not just when inputs are received out of order?
      - when should the server reconcile? I think the answer to the first question will kind of answer this one, but I guess I'm just confused, because couldn't the server just constantly reconcile, since the server is going to receive inputs a few ticks late always just because of ping?
      Thanks!
    • By Sword7
      I am developing my orbital flight simulator (space simulator) myself.
      I am figuring how to write a routine to generate/create Gaussian star/glare texture for starry sky.  I googled for that but can't find any source so far.  I only found it in open-source Celestia code but it did not explain clearly.
      Does anyone know any good source in books or website that provides coding for creating Gaussian star/glare texture?
      Tim
    • By congard
      Hello! I created a camera based on quaternions, but when I turn the camera, an unwanted roll appears. I would not like to lose my freedom of movement using, for example, Euler angles, since there is a need to add roll from time to time. If I use Euler angles, then, as far as I know, I can get a gimbal lock.
      Code:
      struct FreeCamera : public BaseCamera { float pitch = 0, yaw = 0, roll = 0; void updateView(); private: glm::quat qCamera; }; struct FreeCameraController: public BaseCameraController { float sensitivityPitch = 0.0025f, sensitivityYaw = 0.0025f, sensitivityRoll = 0.0025f; void mouseMove(const float x, const float y, const float z = 0); inline void setMousePos(const float x, const float y, const float z = 0) { lastMousePos = glm::vec3(x, y, z); } private: glm::vec3 lastMousePos = glm::vec3(0.0f); }; void FreeCamera::updateView() { // temporary frame quaternion from pitch, yaw, roll glm::quat qPYR = glm::quat(glm::vec3(pitch, yaw, roll)); // reset values pitch = yaw = roll = 0; // update qCamera qCamera = qPYR * qCamera; qCamera = glm::normalize(qCamera); glm::mat4 rotate = glm::mat4_cast(qCamera); glm::mat4 translate = glm::mat4(1.0f); translate = glm::translate(translate, -pos); view = rotate * translate; } void FreeCameraController::mouseMove(const float x, const float y, const float z) { glm::vec3 dCoord = glm::vec3(x, y, z) - lastMousePos; ((FreeCamera*)camera)->yaw = dCoord.x * sensitivityYaw; ((FreeCamera*)camera)->pitch = dCoord.y * sensitivityPitch; ((FreeCamera*)camera)->roll = dCoord.z * sensitivityRoll; lastMousePos = glm::vec3(x, y, z); } Is it possible to reset unwanted roll? Thanks in advance for the help!
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!