Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-transforms] Inconsistencies in 2D and 3D matrix decomposition #3713

Open
kevers-google opened this issue Mar 6, 2019 · 3 comments
Open

Comments

@kevers-google
Copy link
Contributor

2D spec: https://drafts.csswg.org/css-transforms/#decomposing-a-2d-matrix
3D spec: https://drafts.csswg.org/css-transforms-2/#decomposing-a-3d-matrix

A minor tweak to a transformation matrix that alters the transform from 2D to 3D, or vice versa, should not radically alter the interpolation path.

In the 2D case, the decomposed matrix has a total of 9 parameters: 2 translate, 2 scale, an angle and a 2x2 matrix that corresponds to the skew. This feels over-specified as the skew should be expressible with at most 2 parameters.

Here is an alternative, which is more consistent with the 3D matrix decomposition:

Input:  
    matrix      ; a 4x4 matrix
Output: 
    translation ; a 2 component vector
    scale       ; a 2 component vector
    skew        ; X skew
    angle       ; rotation
Returns false if the matrix cannot be decomposed, true if it can

m11 = matrix[0][0]
m12 = matrix[0][1]
m21 = matrix[1][0]
m22 = matrix[1][1]

determinant = m11 * m22 - m12 * m21;
if (determinant == 0)
    return false;

translate[0] = matrix[3][0]
translate[1] = matrix[3][1]

scale[0] = 1;
scale[1] = 1;
if (determinant < 0)
    // If the determinant is negative, we need to flip either the x or y scale.
    // Flipping both is equivalent to rotating by 180 degrees.
    if (m11 < m22)
        scale[0] = -1
    else
        scale[1] = -1

scale[0] *= sqrt(m11 * m11 + m12 * m12)
m11 /= scale[0]
m12 /= scale[0]

scaledShear = m11 * m21 + m12 * m22
m21 -= m11 * scaledShear
m22 -= m12 * scaledShear

scale[1] *= sqrt(m21 * m21 + m22 * m22)
m21 /= scale[1]
m22 /= scale[1]
skew = scaledShear / scale[1]
angle = atan2(m12, m11)

The inconsistency in handling negative determinants is files as #3712.

The 3D counterpart to this 2D decomposition is:

decomp3d.scale = [decomp2d.scale[0], decomp2d.scale[1], 1]
decomp3d.translate = [decomp2d.translate[0], decomp2d.translate[1], 0]
decomp3d.skew = [decomp2d.skew, 0, 0]
decomp3d.perspective = [0, 0, 0, 1]
decomp3d.quaternion = [0, 0, sin(decomp2d.angle/2), cos(decomp2d.angle/2)]

Having this simple mapping facilitates blending a 2D and 3D transformation matrix.

@birtles birtles added css-transforms-1 Current Work css-transforms-2 and removed css-transforms-1 Current Work labels Mar 6, 2019
@birtles
Copy link
Contributor

birtles commented Mar 6, 2019

I'm pretty sure this is a dupe of #3230.

@birtles
Copy link
Contributor

birtles commented May 24, 2019

I've been working through this trying to fix inconsistencies in Gecko but I'm having trouble understanding how this produces consistent results for 2D/3D for input such as matrix(1, 0, 0, -1, 0, 0).

As far as I can tell, the 3D decomposition would yield a quaternion of 0, 1, 0, 0 and debugging Gecko and Chrome I see they both give that.

However, using the algorithm above we have:

decomp3d.quaternion = [0, 0, sin(decomp2d.angle/2), cos(decomp2d.angle/2)]

Which is clearly never going to give 0, 1, 0, 0.

Instead, applying the above logic in Gecko I get 0, 0, 0, 1.

@kevers-google Is there something I'm missing here?

@kevers-google
Copy link
Contributor Author

The 2D algorithm flips one scale factor if the determinant is negative whereas the specced 3D algorithm flips all scale factors. Both have the impact of making the matrix determinant positive -- though in the 3D case, this will lead to rotations in addition to the scaling as well as create a throbbing effect. If in the 3D algorithm a single axis was selected for scale inversion to address the negative determinant in a consistent manner to the 2D algorithm, the 2D and 3D results should align.

@birtles birtles added the css-transforms-1 Current Work label Sep 17, 2019
mattwoodrow added a commit to mattwoodrow/WebKit that referenced this issue Aug 30, 2023
…lgorithm and fails css/css-transforms/animation/transform-interpolation-005.html.

https://bugs.webkit.org/show_bug.cgi?id=235806
<rdar://88488559>

Reviewed by NOBODY (OOPS!).

The updated algorithm has been proposed in an issue for years, and taken up both both other engines and WPTs.
We should use it, and hopefully get the changes added to the actual spec.

w3c/csswg-drafts#3713

* LayoutTests/imported/w3c/web-platform-tests/css/css-transforms/animation/transform-interpolation-005-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-transforms/animation/transform-skew-composition-expected.txt:
* Source/WebCore/animation/KeyframeEffect.cpp:
(WebCore::KeyframeEffect::computeTransformedExtentViaTransformList const):
(WebCore::KeyframeEffect::computeTransformedExtentViaMatrix const):
* Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp:
(WebCore::decompose2):
(WebCore::interpolateQuaternion):
(WebCore::TransformationMatrix::blend2):
(WebCore::TransformationMatrix::decompose2 const):
(WebCore::TransformationMatrix::recompose2):
* Source/WebCore/platform/graphics/transforms/TransformationMatrix.h:
(WebCore::TransformationMatrix::Decomposed2Type::operator== const):
(WebCore::TransformationMatrix::Decomposed2Type::hasRotation):
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants