Javascript:360 度旋转和矩阵组合的问题
Javascript: issue with 360deg rotations and matrix composition
我之前问过关于正确的 (计算和组成矩阵)的问题,现在我面临一个老问题,我没想到这仍然是一个大问题。
基本上 360 度/720 度只是零,我不知道如何修改以下函数来解决这个问题。
CSSMatrix.Rotate = function(rx, ry, rz){
rx *= Math.PI / 180;
ry *= Math.PI / 180;
rz *= Math.PI / 180;
// minus sin() because of right-handed system
var cosx = Math.cos(rx), sinx = - Math.sin(rx);
var cosy = Math.cos(ry), siny = - Math.sin(ry);
var cosz = Math.cos(rz), sinz = - Math.sin(rz);
var m = new CSSMatrix();
m.m11 = m.a = cosy * cosz;
m.m12 = m.b = -cosy * sinz;
m.m13 = siny;
m.m21 = m.c = sinx * siny * cosz + cosx * sinz;
m.m22 = m.d = cosx * cosz - sinx * siny * sinz;
m.m23 = - sinx * cosy;
m.m31 = sinx * sinz - cosx * siny * cosz;
m.m32 = sinx * cosz + cosx * siny * sinz;
m.m33 = cosx * cosy;
return m;
};
当使用 360 度旋转(在任何轴上)组成矩阵时,CSSMatrix.rotate()
方法正在创建一个旋转矩阵,对于每个角度值,我们得到 angle * Math.PI / 180
然后其他正弦/余弦运算,但是矩阵结果不同于常规 rotateX(360deg)
的计算变换。
在这里查看我的小提琴,其中相同的代码 doesn't work properly with 360deg angle and working properly 角度不同于 360 度。
请问我该如何解决?
这里的问题是 CSSMatrix
polyfill 代码支持的精度。它最多支持 6 位小数并将任何较小的值(正或负)截断为 0,即任何小于 0.000001 的值都将转换为 0。
在你的 fiddle 中,如果你只是应用 rotateX(360deg)
转换,它会转换成这个 matrix3d:
matrix3d(1, 0, 0, 0, 0, 1, -2.44929e-16, 0, 0, 2.44929e-16, 1, 0, 0, 0, 0, 1)
polyfill 将 -2.44929e-16
和 2.44929e-16
转换为 0
从而生成此 matrix3d:
matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
提高 polyfill 代码中的小数精度可以解决此问题。将 line 35 从:
CSSMatrix.SMALL_NUMBER = 1e-6;
至
CSSMatrix.SMALL_NUMBER = 1e-20; // 20 decimal point precision
我已在 this fiddle.
中修复了该问题
编辑:关于评论中有关应用沿 2 个轴旋转时生成的不同矩阵的问题:这是因为 fiddle 中使用的 compose
函数应用沿所有轴的旋转同时 - 这相当于单个 rotate3d(x, y, z)
调用。
但是通过 CSS 在 fiddle 中应用的变换分别在 X 轴和 Z 轴上旋转,这相当于应用 rotate(x, 0, 0)
,然后应用 rotate(0, 0, z)
。
这可以通过更改 fiddle 中的 compose
函数并比较 polyfill 生成的 matrix3d 与浏览器生成的 matrix3d 来验证。
我之前问过关于正确的
基本上 360 度/720 度只是零,我不知道如何修改以下函数来解决这个问题。
CSSMatrix.Rotate = function(rx, ry, rz){
rx *= Math.PI / 180;
ry *= Math.PI / 180;
rz *= Math.PI / 180;
// minus sin() because of right-handed system
var cosx = Math.cos(rx), sinx = - Math.sin(rx);
var cosy = Math.cos(ry), siny = - Math.sin(ry);
var cosz = Math.cos(rz), sinz = - Math.sin(rz);
var m = new CSSMatrix();
m.m11 = m.a = cosy * cosz;
m.m12 = m.b = -cosy * sinz;
m.m13 = siny;
m.m21 = m.c = sinx * siny * cosz + cosx * sinz;
m.m22 = m.d = cosx * cosz - sinx * siny * sinz;
m.m23 = - sinx * cosy;
m.m31 = sinx * sinz - cosx * siny * cosz;
m.m32 = sinx * cosz + cosx * siny * sinz;
m.m33 = cosx * cosy;
return m;
};
当使用 360 度旋转(在任何轴上)组成矩阵时,CSSMatrix.rotate()
方法正在创建一个旋转矩阵,对于每个角度值,我们得到 angle * Math.PI / 180
然后其他正弦/余弦运算,但是矩阵结果不同于常规 rotateX(360deg)
的计算变换。
在这里查看我的小提琴,其中相同的代码 doesn't work properly with 360deg angle and working properly 角度不同于 360 度。
请问我该如何解决?
这里的问题是 CSSMatrix
polyfill 代码支持的精度。它最多支持 6 位小数并将任何较小的值(正或负)截断为 0,即任何小于 0.000001 的值都将转换为 0。
在你的 fiddle 中,如果你只是应用 rotateX(360deg)
转换,它会转换成这个 matrix3d:
matrix3d(1, 0, 0, 0, 0, 1, -2.44929e-16, 0, 0, 2.44929e-16, 1, 0, 0, 0, 0, 1)
polyfill 将 -2.44929e-16
和 2.44929e-16
转换为 0
从而生成此 matrix3d:
matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
提高 polyfill 代码中的小数精度可以解决此问题。将 line 35 从:
CSSMatrix.SMALL_NUMBER = 1e-6;
至
CSSMatrix.SMALL_NUMBER = 1e-20; // 20 decimal point precision
我已在 this fiddle.
中修复了该问题编辑:关于评论中有关应用沿 2 个轴旋转时生成的不同矩阵的问题:这是因为 fiddle 中使用的 compose
函数应用沿所有轴的旋转同时 - 这相当于单个 rotate3d(x, y, z)
调用。
但是通过 CSS 在 fiddle 中应用的变换分别在 X 轴和 Z 轴上旋转,这相当于应用 rotate(x, 0, 0)
,然后应用 rotate(0, 0, z)
。
这可以通过更改 fiddle 中的 compose
函数并比较 polyfill 生成的 matrix3d 与浏览器生成的 matrix3d 来验证。