Skip to content

Instantly share code, notes, and snippets.

@josimard
Last active March 19, 2025 22:27
Show Gist options
  • Select an option

  • Save josimard/5737f3488fdfa2d207d68de282904479 to your computer and use it in GitHub Desktop.

Select an option

Save josimard/5737f3488fdfa2d207d68de282904479 to your computer and use it in GitHub Desktop.

Revisions

  1. Jo Simard revised this gist Apr 12, 2019. 1 changed file with 0 additions and 2 deletions.
    2 changes: 0 additions & 2 deletions InterpolationLibrary.cpp
    Original file line number Diff line number Diff line change
    @@ -10,7 +10,6 @@ FVector UInterpolationLibrary::VectorSpringInterpCD(FVector Current, FVector Tar
    {
    const FVector n1 = Velocity - (Current - Target) * (InterpSpeed * InterpSpeed * DeltaTime);
    const float n2 = 1.f + InterpSpeed * DeltaTime;
    Velocity = n1 / (n2 * n2);
    if (MaxVelocity > 0.f)
    {
    Velocity = (n1 / (n2 * n2)).GetClampedToMaxSize(MaxVelocity);
    @@ -50,7 +49,6 @@ FQuat UInterpolationLibrary::QuatSpringInterpCD(FQuat Current, FQuat Target, FVe

    const FVector4 n1 = Velocity - (currentVector - targetVector) * (InterpSpeed * InterpSpeed * DeltaTime);
    const float n2 = 1.f + InterpSpeed * DeltaTime;
    Velocity = n1 / (n2 * n2);

    if (MaxVelocity > 0.f)
    {
  2. Jo Simard revised this gist Apr 12, 2019. No changes.
  3. Jo Simard created this gist Apr 12, 2019.
    69 changes: 69 additions & 0 deletions InterpolationLibrary.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,69 @@
    #include "InterpolationLibrary.h"
    #include "Kismet/KismetMathLibrary.h"

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Critically Damped Spring Interpolations (ie: Similar to Unity's SmoothDamp, but will less operations)
    // Inspired from Keijiro's code: https://github.com/keijiro/SmoothingTest
    // Math reference: http://mathproofs.blogspot.jp/2013/07/critically-damped-spring-smoothing.html

    FVector UInterpolationLibrary::VectorSpringInterpCD(FVector Current, FVector Target, FVector& Velocity, float DeltaTime, float InterpSpeed, float MaxVelocity)
    {
    const FVector n1 = Velocity - (Current - Target) * (InterpSpeed * InterpSpeed * DeltaTime);
    const float n2 = 1.f + InterpSpeed * DeltaTime;
    Velocity = n1 / (n2 * n2);
    if (MaxVelocity > 0.f)
    {
    Velocity = (n1 / (n2 * n2)).GetClampedToMaxSize(MaxVelocity);
    }
    else
    {
    Velocity = n1 / (n2 * n2);
    }
    return Current + Velocity * DeltaTime;
    }

    float UInterpolationLibrary::FloatSpringInterpCD(float Current, float Target, float& Velocity, float DeltaTime, float InterpSpeed, float MaxVelocity)
    {
    const float n1 = Velocity - (Current - Target) * (InterpSpeed * InterpSpeed * DeltaTime);
    const float n2 = 1.f + InterpSpeed * DeltaTime;

    Velocity = (MaxVelocity > 0.f) ? FMath::Min(n1 / (n2 * n2), MaxVelocity) : n1 / (n2 * n2);

    return Current + Velocity * DeltaTime;
    }

    FRotator UInterpolationLibrary::RotatorSpringInterpCD(FRotator Current, FRotator Target, FVector4& Velocity, float DeltaTime, float InterpSpeed, float MaxVelocity)
    {
    return QuatSpringInterpCD(Current.Quaternion(), Target.Quaternion(), Velocity, DeltaTime, InterpSpeed, MaxVelocity).Rotator();
    }

    FQuat UInterpolationLibrary::QuatSpringInterpCD(FQuat Current, FQuat Target, FVector4& Velocity, float DeltaTime, float InterpSpeed, float MaxVelocity)
    {
    // Here would it be better to make operations directly on FQuat?
    // I can't find FQuat operators code to check, so I prefer those conversions...
    FVector4 currentVector = QuatToVector4(Current);
    FVector4 targetVector = QuatToVector4(Target);

    // We can use either of vtarget/-vtarget. Use closer one.
    // If using FQuat, might FQuat::Squad() be usesul here?
    if (Dot4(currentVector, targetVector) < 0.f) targetVector = -targetVector;

    const FVector4 n1 = Velocity - (currentVector - targetVector) * (InterpSpeed * InterpSpeed * DeltaTime);
    const float n2 = 1.f + InterpSpeed * DeltaTime;
    Velocity = n1 / (n2 * n2);

    if (MaxVelocity > 0.f)
    {
    Velocity = ClampVector4(n1 / (n2 * n2), MaxVelocity);
    }
    else
    {
    Velocity = n1 / (n2 * n2);
    }
    // Apply delta on current
    currentVector = (currentVector + Velocity * DeltaTime);

    // Normalizing gave odd results, it looks fine this way but don't ask me why...
    return FQuat(currentVector.X, currentVector.Y, currentVector.Z, currentVector.W);
    }

    70 changes: 70 additions & 0 deletions InterpolationLibrary.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,70 @@
    #pragma once

    #include "CoreMinimal.h"
    #include "Kismet/BlueprintFunctionLibrary.h"
    #include "InterpolationLibrary.generated.h"

    /**
    * Interpolation library
    * @see Unreal Engine built-in interpolations: https://api.unrealengine.com/INT/BlueprintAPI/Math/Interpolation/index.html
    */
    UCLASS()
    class UInterpolationLibrary : public UBlueprintFunctionLibrary
    {
    GENERATED_BODY()

    public:

    /**
    * Critically Damped Spring Interpolation (ie: Similar to Unity's SmoothDamp, but will less operations)
    */
    UFUNCTION(BlueprintPure, Category = "Math|Interpolation", meta = (Keywords = "interp vinterp vectorspringinterp lerp smoothdamp"))
    static FVector VectorSpringInterpCD(FVector Current, FVector Target, UPARAM(ref) FVector& Velocity, float DeltaTime, float InterpSpeed = 10.f, float MaxVelocity = 0.f);

    /**
    * Critically Damped Spring Interpolation (ie: Similar to Unity's SmoothDamp, but will less operations)
    */
    UFUNCTION(BlueprintPure, Category = "Math|Interpolation", meta = (Keywords = "interp finterp floatspringinterp lerp smoothdamp"))
    static float FloatSpringInterpCD(float Current, float Target, UPARAM(ref) float& Velocity, float DeltaTime, float InterpSpeed = 10.f, float MaxVelocity = 0.f);

    /**
    * Critically Damped Spring Interpolation
    */
    UFUNCTION(BlueprintCallable, Category = "Math|Interpolation", meta = (Keywords = "rinterp smoothdamp"))
    static FRotator RotatorSpringInterpCD(FRotator Current, FRotator Target, UPARAM(ref) FVector4& Velocity, float DeltaTime, float InterpSpeed = 10.f, float MaxVelocity = 0.f);

    /**
    * Critically Damped Spring Interpolation
    */
    UFUNCTION(BlueprintPure, Category = "Math|Interpolation", meta = (Keywords = "fquat smoothdamp"))
    static FQuat QuatSpringInterpCD(FQuat Current, FQuat Target, UPARAM(ref) FVector4& Velocity, float DeltaTime, float InterpSpeed = 10.f, float MaxVelocity = 0.f);


    // Utility methods
    private:

    FORCEINLINE static FVector4 QuatToVector4(const FQuat& Quat)
    {
    return FVector4(Quat.X, Quat.Y, Quat.Z, Quat.W);
    }

    FORCEINLINE static FVector4 ClampVector4(FVector4 Target, float MaxSize)
    {
    if (MaxSize < KINDA_SMALL_NUMBER)
    {
    return FVector4(0.f, 0.f, 0.f, 0.f);
    }

    const float VSq = Target.SizeSquared();
    if (VSq > FMath::Square(MaxSize))
    {
    const float Scale = MaxSize * FMath::InvSqrt(VSq);
    return FVector4(Target.X*Scale, Target.Y*Scale, Target.Z*Scale, Target.W*Scale);
    }
    else
    {
    return Target;
    }
    }

    };