enceledean

Vector Curves

Recently I’ve put together a way to quickly, if imprecisely, create data curves to create more interesting range curves besides linear, by simply defining data ranges and not actual curves.

A standard method for data population in games is to have a min max range. With value t you can say lerp(x,y,t) to get a value in that range. But to create a non linear curve, you have to either define a curve somehow, or put t into something predefined like smoothstart(x,y,t) and be happy with that output.

My method is simple, which is to apply bezier (nested lerps) code to a vector3. You can use a vector of any length but I’ll stick with 3 for examples. With something like bezier(x,y,z,t) you can feed in 3 values to skew the results. I’m calling these Vector Curves. So vectorcurve(0,0,1) will produce values close (remember I said this was imprecise) to smoothstart(0,1,t), where values of t will generally skew towards 0 before sharply arriving at 1.

This has proved incredibly useful. My goal is to add low overhead code and use existing data types inside unity, and be able to quickly copy, paste, and evaluate large data sets. While you cannot see the actual curve and so are ceding some precision, the utility of it pays off very quickly.

Some outputs:

curve: (0.00, 0.50, 1.00) t: 0.3742928 output: 0.3742928
curve: (0.00, 1.00, 1.00) t: 0.2653239 output: 0.4602511
curve: (0.00, 0.00, 1.00) t: 0.5151407 output: 0.26537
curve: (0.00, 1.00, 5.00) t: 0.8593886 output: 3.934423

I am already using it to generate int values. By rounding the output of vectorcurve, I can supply float ranges that will sometimes skew towards outlier values. If I generally want results of a range 1 - 3 with a low chance for 4, I can supply (1, 3, 3.75). If the t value reaches past 3.5, it will round up to 4. I don’t know the exact distribution of this, but for my purposes that’s ok!

Rounded outputs:

curve: (0.00, 0.50, 1.00) t: 0.7941097 output: 1
curve: (1.00, 3.00, 3.75) t: 0.7621779 output: 3
curve: (1.00, 3.00, 3.75) t: 0.8675628 output: 4

Anyway, here’s the code below the fold, but any bezier code should work fine. I used the CatlikeCoding methods.


  public static float Vector2Curve(Vector2 curve, float t)
  {
    t = Mathf.Clamp01(t);
    return Mathf.Lerp(curve.x, curve.y, t);
  }

  public static float Vector3Curve(Vector3 curve, float t)
  {
    t = Mathf.Clamp01(t);
    float oneMinusT = 1f - t;
    return oneMinusT * oneMinusT * curve.x +
      2f * oneMinusT * t * curve.y +
      t * t * curve.z;
  }

  public static float Vector4Curve(Vector4 curve, float t)
  {
    t = Mathf.Clamp01(t);
    float oneMinusT = 1f - t;
    return oneMinusT * oneMinusT * oneMinusT * curve.x +
      3f * oneMinusT * oneMinusT * t * curve.y +
      3f * oneMinusT * t * t * curve.z +
      t * t * t * curve.w;
  }