在 CSS3 过渡中,您可以将计时函数指定为 'cubic-bezier:(0.25, 0.3, 0.8, 1.0)' 在该字符串中,您仅指定沿曲线的点 P1 和 P2 的 XY,因为 P0 和 P3 是始终分别为 (0.0, 0.0) 和 (1.0, 1.0)。
根据 Apple 的网站:x [is] 表示为整体持续时间的一部分,y 表示为整体变化的一部分
我的问题是如何将其映射回 javascript 中的传统一维 T 值?
--
在 CSS3 过渡中,您可以将计时函数指定为 'cubic-bezier:(0.25, 0.3, 0.8, 1.0)' 在该字符串中,您仅指定沿曲线的点 P1 和 P2 的 XY,因为 P0 和 P3 是始终分别为 (0.0, 0.0) 和 (1.0, 1.0)。
根据 Apple 的网站:x [is] 表示为整体持续时间的一部分,y 表示为整体变化的一部分
我的问题是如何将其映射回 javascript 中的传统一维 T 值?
--
稍微浏览一下 webkit-source,以下代码将为 CSS3 过渡中使用的隐式曲线提供正确的 T 值:
希望这对某人有帮助!
function loop(){
var t = (now - animationStartTime) / ( animationDuration*1000 );
var curve = new UnitBezier(Bx, By, Cx, Cy);
var t1 = curve.solve(t, UnitBezier.prototype.epsilon);
var s1 = 1.0-t1;
// Lerp using solved T
var finalPosition.x = (startPosition.x * s1) + (endPosition.x * t1);
var finalPosition.y = (startPosition.y * s1) + (endPosition.y * t1);
}
/**
* Solver for cubic bezier curve with implicit control points at (0,0) and (1.0, 1.0)
*/
function UnitBezier(p1x, p1y, p2x, p2y) {
// pre-calculate the polynomial coefficients
// First and last control points are implied to be (0,0) and (1.0, 1.0)
this.cx = 3.0 * p1x;
this.bx = 3.0 * (p2x - p1x) - this.cx;
this.ax = 1.0 - this.cx -this.bx;
this.cy = 3.0 * p1y;
this.by = 3.0 * (p2y - p1y) - this.cy;
this.ay = 1.0 - this.cy - this.by;
}
UnitBezier.prototype.epsilon = 1e-6; // Precision
UnitBezier.prototype.sampleCurveX = function(t) {
return ((this.ax * t + this.bx) * t + this.cx) * t;
}
UnitBezier.prototype.sampleCurveY = function (t) {
return ((this.ay * t + this.by) * t + this.cy) * t;
}
UnitBezier.prototype.sampleCurveDerivativeX = function (t) {
return (3.0 * this.ax * t + 2.0 * this.bx) * t + this.cx;
}
UnitBezier.prototype.solveCurveX = function (x, epsilon) {
var t0;
var t1;
var t2;
var x2;
var d2;
var i;
// First try a few iterations of Newton's method -- normally very fast.
for (t2 = x, i = 0; i < 8; i++) {
x2 = this.sampleCurveX(t2) - x;
if (Math.abs (x2) < epsilon)
return t2;
d2 = this.sampleCurveDerivativeX(t2);
if (Math.abs(d2) < epsilon)
break;
t2 = t2 - x2 / d2;
}
// No solution found - use bi-section
t0 = 0.0;
t1 = 1.0;
t2 = x;
if (t2 < t0) return t0;
if (t2 > t1) return t1;
while (t0 < t1) {
x2 = this.sampleCurveX(t2);
if (Math.abs(x2 - x) < epsilon)
return t2;
if (x > x2) t0 = t2;
else t1 = t2;
t2 = (t1 - t0) * .5 + t0;
}
// Give up
return t2;
}
// Find new T as a function of Y along curve X
UnitBezier.prototype.solve = function (x, epsilon) {
return this.sampleCurveY( this.solveCurveX(x, epsilon) );
}
您想找到任何时间值 t [0,1] 的 [0,1] 值吗?三次贝塞尔曲线有一个定义明确的方程。维基百科页面:http ://en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B.C3.A9zier_curves
所以我不必输入他们的(可能是 LaTeX 格式的)公式,我从http://local.wasp.uwa.edu.au/~pbourke/geometry/bezier/index2.html复制粘贴了相同的公式. 这也有一个 C 实现,通过快速阅读,应该很容易移植到 javascript:
B(u) = P0 * ( 1 - u )3 + P1 * 3 * u * ( 1 - u )2 + P2 * 3 * u2 * ( 1 - u ) + P3 * u3
他在该页面上调用 mu 是您的时间变量 t。
编辑:如果你不想做数学,看起来有人已经用 javascript 编写了一个小型实用程序库来做基本的贝塞尔曲线数学:https ://github.com/sporritt/jsBezier 。pointOnCurve(curve, location) 看起来正是您所要求的。
我已经尝试搜索了很多时间和表格,并且很明显我已经达到了一个简单而快速的目标。诀窍是以这种形式获得三次贝塞尔函数: P(u) = u^3(c0 + 3c1 -3c2 +c3) + u^2(3c0 -6c1 +3c2) + u(-3c0 +3c1) + c0其中 ci 是控制点。另一部分是使用二分搜索从 x 中搜索 y。
static public class CubicBezier {
private BezierCubic bezier = new BezierCubic();
public CubicBezier(float x1, float y1, float x2, float y2) {
bezier.set(new Vector3(0,0,0), new Vector3(x1,y1,0), new Vector3(x2,y2,0), new Vector3(1,1,1));
}
public float get(float t) {
float l=0, u=1, s=(u+l)*0.5f;
float x = bezier.getValueX(s);
while (Math.abs(t-x) > 0.0001f) {
if (t > x) { l = s; }
else { u = s; }
s = (u+l)*0.5f;
x = bezier.getValueX(s);
}
return bezier.getValueY(s);
}
};
public class BezierCubic {
private float[][] cpoints = new float[4][3];
private float[][] polinom = new float[4][3];
public BezierCubic() {}
public void set(Vector3 c0, Vector3 c1, Vector3 c2, Vector3 c3) {
setPoint(0, c0);
setPoint(1, c1);
setPoint(2, c2);
setPoint(3, c3);
generate();
}
public float getValueX(float u) {
return getValue(0, u);
}
public float getValueY(float u) {
return getValue(1, u);
}
public float getValueZ(float u) {
return getValue(2, u);
}
private float getValue(int i, float u) {
return ((polinom[0][i]*u + polinom[1][i])*u + polinom[2][i])*u + polinom[3][i];
}
private void generate() {
for (int i=0; i<3; i++) {
float c0 = cpoints[0][i], c1 = cpoints[1][i], c2 = cpoints[2][i], c3 = cpoints[3][i];
polinom[0][i] = c0 + 3*(c1 - c2) + c3;
polinom[1][i] = 3*(c0 - 2*c1 + c2);
polinom[2][i] = 3*(-c0 + c1);
polinom[3][i] = c0;
}
}
private void setPoint(int i, Vector3 v) {
cpoints[i][0] = v.x;
cpoints[i][1] = v.y;
cpoints[i][2] = v.z;
}
}