// these are shaping functions taken from various places of https://flong.com // Polynominal shaping float blinn_wyvill_cos_approx(float x) { float x2 = x*x; float x4 = x2*x2; float x6 = x4*x2; float fa = ( 4.0/9.0); float fb = (17.0/9.0); float fc = (22.0/9.0); return fa*x6 - fb*x4 + fc*x2; } // TODO: factor out clamping float double_cubic_seat(float x, vec2 ab) { float epsilon = 0.00001; float min_param_a = 0.0 + epsilon; float max_param_a = 1.0 - epsilon; float min_param_b = 0.0; float max_param_b = 1.0; float a = clamp(ab.x, min_param_a, max_param_a); float b = clamp(ab.y, min_param_b, max_param_b); if (x <= a){ return b - b*pow(1.-x/a, 3.0); } return b + (1.-b)*pow((x-a)/(1.-a), 3.0); } float double_cubic_seat_linear_blend(float x, vec2 ab) { float epsilon = 0.00001; float min_param_a = 0.0 + epsilon; float max_param_a = 1.0 - epsilon; float min_param_b = 0.0; float max_param_b = 1.0; float a = clamp(ab.x, min_param_a, max_param_a); float b = clamp(ab.y, min_param_b, max_param_b); b = 1.0 - b; if (x<=a){ return b*x + (1.-b)*a*(1.-pow(1.-x/a, 3.)); } return b*x + (1.-b)*(a + (1.-a)*pow((x-a)/(1.-a), 3.)); } float double_odd_polynomial_seat(float x, float a, float b, float n) { float epsilon = 0.00001; float min_param_a = 0.0 + epsilon; float max_param_a = 1.0 - epsilon; float min_param_b = 0.0; float max_param_b = 1.0; a = clamp(a, min_param_a, max_param_a); b = clamp(b, min_param_b, max_param_b); float p = 2.*n + 1.; if (x <= a){ return b - b*pow(1.-x/a, p); } return b + (1.-b)*pow((x-a)/(1.-a), p); } float double_poly_sigmoid(float x, float a, float b, float n) { if(mod(n, 2.) == 0.) { if(x <= 0.5) { return pow(2.0*x, n)/2.0; } return 1.0 - pow(2.*(x-1.), n)/2.0; } else { if (x<=0.5){ return pow(2.0*x, n)/2.0; } return 1.0 + pow(2.0*(x-1.), n)/2.0; } } float quad_through_point(float x, vec2 ab) { float epsilon = 0.00001; float min_param_a = 0.0 + epsilon; float max_param_a = 1.0 - epsilon; float min_param_b = 0.0; float max_param_b = 1.0; float a = clamp(ab.x, min_param_a, max_param_a); float b = clamp(ab.y, min_param_b, max_param_b); float A = (1.-b)/(1.-a) - (b/a); float B = (A*(a*a)-b)/a; float y = A*(x*x) - B*(x); y = clamp(0., 1., y); return y; } // exponential shaping float exp_easing(float x, float a) { float e = 0.00001; a = clamp(a, 0.+e, 1.-e); if (a < 0.5) { a = 2.0*(a); return pow(x, a); } a = 2.*(a-.5); return pow(x, 1./(1.-a)); } float double_exp_seat(float x, float a) { float e = 0.00001; a = clamp(a, .0+e, 1.-e); if (x<=0.5) { return pow(2.*x, 1.-a)/2.0; } return 1. - pow(2.*(1.-x), 1.-a)/2.; } float double_exp_sigmoid(float x, float a) { float e = 0.00001; a = 1.-clamp(a, .0+e, 1.-e); if (x<=0.5){ return pow(2.0*x, 1.0/a)/2.0; } return 1.0 - (pow(2.0*(1.0-x), 1.0/a))/2.0; } float normalized_log_sigmoid(float x, float a) { float e = 0.0001; a = 1./(1.-clamp(a, 0.+e, 1.-e)) - 1.; float b = 1.0 / (1.0 + exp(a)); float c = 1.0 / (1.0 + exp(0.-a)); a = 1. / (1. + exp(0. -((x-.5)*a*2.))); return (a-b)/(c-b); } // bezier shaping float quad_bezier(float x, vec2 ab) { float e = 0.00001; float a = clamp(ab.x, 0., 1.); float b = clamp(ab.y, 0., 1.); if (a == 0.5) a += e; float om2a = 1. - 2.*a; float t = (sqrt(a*a + om2a*x) - a)/om2a; return (1.-2.*b)*(t*t) + (2.*b)*t; } // cubic bezier begin float slope_from_t(float t, float A, float B, float C) { return 1.0/(3.0*A*t*t + 2.0*B*t + C); } float x_from_t(float t, float A, float B, float C, float D) { return A*(t*t*t) + B*(t*t) + C*t + D; } float y_from_t(float t, float E, float F, float G, float H) { return E*(t*t*t) + F*(t*t) + G*t + H; } float cubic_bezier(float x, vec2 a, vec2 b) { float y0a = 0.00; float x0a = 0.00; float y1a = a.y; float x1a = a.x; float y2a = b.y; float x2a = b.x; float y3a = 1.00; float x3a = 1.00; float A = x3a - 3.*x2a + 3.*x1a - x0a; float B = 3.*x2a - 6.*x1a + 3.*x0a; float C = 3.*x1a - 3.*x0a; float D = x0a; float E = y3a - 3.*y2a + 3.*y1a - y0a; float F = 3.*y2a - 6.*y1a + 3.*y0a; float G = 3.*y1a - 3.*y0a; float H = y0a; float currentt = x; for (int i=0; i < 5; i++){ float currentx = x_from_t(currentt, A, B, C, D); float currentslope = slope_from_t(currentt, A, B, C); currentt -= (currentx - x)*(currentslope); currentt = clamp(currentt, 0., 1.); } float y = y_from_t(currentt, E, F, G, H); return y; } // cubic bezier end // cubic bezier through points (requires cubic bezier) begin float b0 (float t){ return (1.-t)*(1.-t)*(1.-t); } float b1 (float t){ return 3.*t* (1.-t)*(1.-t); } float b2 (float t){ return 3.*t*t* (1.-t); } float b3 (float t){ return t*t*t; } float findx(float t, float x0, float x1, float x2, float x3) { return x0*b0(t) + x1*b1(t) + x2*b2(t) + x3*b3(t); } float findy(float t, float y0, float y1, float y2, float y3) { return y0*b0(t) + y1*b1(t) + y2*b2(t) + y3*b3(t); } float cubic_bezier_through(float x, vec2 a, vec2 b) { float y = 0.; float e = 0.00001; float minp = 0. + e; float maxp = 1. - e; a = clamp(a, minp, maxp); b = clamp(b, minp, maxp); float x0 = 0.; float y0 = 0.; float x4 = a.x; float y4 = a.y; float x5 = b.x; float y5 = b.y; float x3 = 1.; float y3 = 1.; float x1,y1,x2,y2; // arbitrary but reasonable float t1 = 0.3; float t2 = 0.7; float b0t1 = b0(t1); float b1t1 = b1(t1); float b2t1 = b2(t1); float b3t1 = b3(t1); float b0t2 = b0(t2); float b1t2 = b1(t2); float b2t2 = b2(t2); float b3t2 = b3(t2); float ccx = x4 - x0*b0t1 - x3*b3t1; float ccy = y4 - y0*b0t1 - y3*b3t1; float ffx = x5 - x0*b0t2 - x3*b3t2; float ffy = y5 - y0*b0t2 - y3*b3t2; x2 = (ccx - (ffx*b1t1)/b1t2) / (b2t1 - (b1t1*b2t2)/b1t2); y2 = (ccy - (ffy*b1t1)/b1t2) / (b2t1 - (b1t1*b2t2)/b1t2); x1 = (ccx - x2*b2t1) / b1t1; y1 = (ccy - y2*b2t1) / b1t1; x1 = clamp(x1, minp, maxp); x2 = clamp(x2, minp, maxp); y = cubic_bezier(x, vec2(x1,y1), vec2(x2,y2)); return clamp(y, 0., 1.); } // cubic bezier through points end // Circular shaping float circ_ease_in (float x){ return 1. - sqrt(1. - x*x); } float circ_ease_out (float x){ return sqrt(1. - pow(1. - x, 2.)); } float double_circ_seat(float x, float a) { a = clamp(a, 0., 1.); if (x<=a){ return sqrt(pow(a, 2.) - pow(x-a, 2.)); } return 1. - sqrt(pow(1.-a, 2.) - pow(x-a, 2.)); } float double_circ_sigmoid(float x, float a) { a = clamp(a, 0., 1.); if (x<=a){ return a - sqrt(pow(a, 2.) - pow(x, 2.)); } return a + sqrt(pow(1.-a, 2.) - pow(x-1., 2.)); } float double_ellip_seat(float x, vec2 ab) { float e = 0.00001; float a = clamp(ab.x, 0.+e, 1.+e); float b = clamp(ab.y, 0., 1.); if (x<=a){ return (b/a) * sqrt(pow(a, 2.) - pow(x-a, 2.)); } return 1.-((1.-b)/(1.-a))*sqrt(pow(1.-a, 2.)-pow(x-a,2.)); } float double_ellip_sigmoid(float x, vec2 ab) { float e = 0.00001; float a = clamp(ab.x, 0.+e, 1.+e); float b = clamp(ab.y, 0., 1.); if (x<=a){ return b * (1. - (sqrt(pow(a, 2.) - pow(x, 2.))/a)); } return b+((1.-b)/(1.-a))*sqrt(pow(1.-a,2.)-pow(x-1.,2.)); }