Last active
December 14, 2020 18:48
-
-
Save nothke/7874dfd6deb62b2bb1066a5f889583cc to your computer and use it in GitHub Desktop.
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
| // Thanks to https://twitter.com/jon_barron/status/1318946131078909952 | |
| // | |
| using UnityEngine; | |
| public static class CurveUtils | |
| { | |
| // From pico8 example by @otikik | |
| public static float BiasGain(float x, float s, float t) | |
| { | |
| const float E = float.Epsilon; | |
| if (x < t) | |
| return (t * x) / (x + (1.0f / s - 1.0f) * (t - x) + E); | |
| else | |
| return 1.0f + (1.0f - t) * (x - 1.0f) / (1.0f - x - (1.0f / s - 1.0f) * (t - x) + E); | |
| } | |
| #if UNSAFE // Microoptimization, use only in unsafe context | |
| // From @TommyEttinger's java implementation | |
| public static unsafe float BiasGainBranchless(float x, float s, float t) | |
| { | |
| const float E = float.Epsilon; | |
| float d = t - x; | |
| int f = *((int*)&d) >> 31; | |
| int n = f | 1; | |
| return ((t * n - f) * (x + f)) / (E - f + (x + (1 - s) * d) * n) - f; | |
| } | |
| #endif | |
| // From Mikko Mononen: https://gist.github.com/memononen/df1728511aed9e410d871bbff0a58c83 | |
| /// <summary> | |
| /// Schlick Bias-Gain curve wIth 2D inflection point. Get slope values from GetInflectionSlopes() before evaluating. | |
| /// </summary> | |
| public static float BiasGainInflection(float x, float ix, float iy, float sa, float sb) | |
| { | |
| const float EPS = 1e-6f; | |
| if (x < ix) | |
| return (iy * x) / (x + sa * (ix - x) + EPS); | |
| else | |
| return ((1 - iy) * (x - 1)) / ((1 - x) - sb * (ix - x) + EPS) + 1.0f; | |
| } | |
| /// <summary> | |
| /// Call this outside the evaluation loop, and use the slope parameters for BiasGainInflection() | |
| /// </summary> | |
| /// <param name="cx">Control point x</param> | |
| /// <param name="cy">Control point y</param> | |
| /// <param name="ix">Inflection point x</param> | |
| /// <param name="iy">Inflection point y</param> | |
| /// <param name="slopea">First slope parameter</param> | |
| /// <param name="slopeb">Second slope parameter</param> | |
| public static void GetInflectionSlopes( | |
| float cx, float cy, float ix, float iy, | |
| out float slopea, out float slopeb) | |
| { | |
| float slope = (iy - cy) / (ix - cx); // Second control point controls slope | |
| slopea = slope * ((ix - 0) / (iy - 0)); | |
| slopeb = slope * ((1 - ix) / (1 - iy)); | |
| } | |
| } | |
| public class SchlickBiasGainTest : MonoBehaviour | |
| { | |
| public enum Method { BiasGain, BiasGainInflection }; | |
| public Method method; | |
| [Range(0, 1)] | |
| public float s = 0.8f; | |
| [Range(0, 1)] | |
| public float t = 0.3f; | |
| public Vector2 inflectionPoint = new Vector2(0.4f, 0.4f); | |
| public Vector2 controlPoint = new Vector2(0.9f, 0.52f); | |
| const int NUM_POINTS = 100; | |
| void OnDrawGizmos() | |
| { | |
| Vector2 prev = Vector2.zero; | |
| CurveUtils.GetInflectionSlopes( | |
| controlPoint.x, controlPoint.y, inflectionPoint.x, inflectionPoint.y, | |
| out float slopea, out float slopeb); | |
| for (int i = 0; i < NUM_POINTS + 1; i++) | |
| { | |
| float x = (float)i / NUM_POINTS; | |
| float y; | |
| switch (method) | |
| { | |
| case Method.BiasGain: | |
| y = CurveUtils.BiasGain(x, s, t); | |
| break; | |
| case Method.BiasGainInflection: | |
| y = CurveUtils.BiasGainInflection( | |
| x, inflectionPoint.x, inflectionPoint.y, slopea, slopeb); | |
| break; | |
| default: y = 0; break; | |
| } | |
| Vector2 p = new Vector2(x, y); | |
| Gizmos.DrawLine(prev, p); | |
| prev = p; | |
| } | |
| Gizmos.color = Color.yellow; | |
| Gizmos.DrawSphere(inflectionPoint, 0.01f); | |
| Gizmos.color = Color.red; | |
| Gizmos.DrawSphere(controlPoint, 0.01f); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment