问题
I asked previously about the proper function for perspective (to compute and compose a matrix), now I'm facing an older problem and I wasn't expecting this to be so much of an issue still.
Basically 360deg / 720deg is just zero and I don't know how to hack the following function to fix that.
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;
};
When using 360deg rotations (on any axis) to compose a matrix, the CSSMatrix.rotate()
method is creating a rotation matrix and for each angle value we get angle * Math.PI / 180
then other sinus / cosinus operations, but the matrix result is different from a computed transform of a regular rotateX(360deg)
.
See my fiddles here where same code doesn't work properly with 360deg angle and working properly with angles different from 360deg.
How can I fix that please?
回答1:
The issue here is the precision supported by the CSSMatrix
polyfill's code. It supports upto 6 decimals and truncates any lesser value (positive or negative) to 0 i.e. anything less than 0.000001 will be converted to 0.
In your fiddle, if you just apply the rotateX(360deg)
transform, it converts to this matrix3d:
matrix3d(1, 0, 0, 0, 0, 1, -2.44929e-16, 0, 0, 2.44929e-16, 1, 0, 0, 0, 0, 1)
The polyfill converts -2.44929e-16
and 2.44929e-16
to 0
thereby generating this matrix3d:
matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
Increasing the decimal precision in the polyfill's code fixes this issue. Change line 35 from:
CSSMatrix.SMALL_NUMBER = 1e-6;
to
CSSMatrix.SMALL_NUMBER = 1e-20; // 20 decimal point precision
I've fixed that in this fiddle.
Edit: Regarding the question in the comment about different matrices being generated when applying rotate along 2 axes: This is because the compose
function used in the fiddle applies rotation along all axes at the same time - which would be equivalent to a single rotate3d(x, y, z)
call.
But the transforms applied via CSS in the fiddle rotate on the X and Z axes separately which would be equivalent to applying rotate(x, 0, 0)
followed by rotate(0, 0, z)
.
This can be verified by changing the compose
function in the fiddle and comparing the matrix3d generated by the polyfill vs the one generated by the browser.
来源:https://stackoverflow.com/questions/35892678/javascript-issue-with-360deg-rotations-and-matrix-composition