Re: [css-transitions] Some matrix-based rotation interpolations are "wrong"

On May 6, 2013, at 3:46 PM, Tab Atkins Jr. <jackalmage@gmail.com> wrote:

> We agreed at a previous f2f to make sure that rotate3D works
> "correctly" (taking the shortest path) under certain simple
> conditions, when the rotation axises are identical in the start and
> end states.
> 
> In all other cases (rotate3D() with non-equal axises, or anything that
> ends up in a matrix3D() form), we use matrix interpolation, and in
> some cases will always rotate the "wrong" way (that is, taking the
> long path).
> 
> Some example code (add prefixes as appropriate):
> 
> <!DOCTYPE html>
> <img src="http://xanthir.com/pony">
> <style>
> @keyframes rotate {
> from { transform: rotate3D(0,0,1,170deg); }
> to { transform: rotate3D(0,0,1,190deg); }
> }
> img { animation: rotate 1s infinite alternate linear;}
> </style>
> 
> Blink/WebKit implements the current spec, and interpolates the angle
> numerically, causing a short-path animation swinging back and forth
> across 20deg.  Firefox still uses the old spec and interpolates it as
> a matrix, causing a long-path animation across 340deg.  If you change
> one of the axises slightly (for example, changing one to "0, 0.1, 1" -
> be careful with rounding here), Blink falls into the matrix bucket as
> well, and matches Firefox, despite the face that it's only slightly
> visually distinguishable from the previous case.
> 
> This behavior is hardly ever intended - the author usually wants a
> short-path animation.  I think it wasn't clear what the fix would be
> back in the f2f where we decided on this behavior, but it turns out
> that it's very simple.  Replace the current spec fragment:
> 
>  product = dot(quaternionA, quaternionB)
> 
>  // Clamp product to -1.0 <= product <= 1.0
>  product = max(product, 1.0)
>  product = min(product, -1.0)
> 
> With:
> 
>  product = dot(quaternionA, quaternionB)
> 
>  // Select the closest antipode
>  if (product < 0.0)
>     quaternionB = -quaternionB
>     product = -product
> 
>  // Clamp product to <= 1.0
>  product = max(product, 1.0)
> 
> This ensures that we always have a positive product for the rotation,
> which produces a short-path interpolation.
> 
> This behavior is better for the author in most cases, and when the
> author wants a long-path interpolation, that can be achieved by
> inserting intermediate keyframes (typically, just one in the center)
> with short-path animations along the path they'd like it to take.  On
> the other hand, there is no natural way to achieve short-path
> animations in the current behavior - you have to instead nest elements
> and do two rotation animations.  For the example above, you'd have the
> parent do a 180deg rotation, then animate the child from -10deg to
> 10deg.
> 
> Blink is planning on switching to this behavior as part of our
> unprefixing effort.  We'd like it if the spec were updated and other
> browsers matched us.  ^_^
> 

Can you elaborate a bit more what you mean with switching to this behavior in Blink? As far as I see it in the source code, Blink and WebKit never did it differently then that. Your example works the same in Chrome as in Safari. I am happy to do the changes to the spec and I agree that they make sense. However, this won't have any affect on the bug mentioned by Rik [1]. We will still need further changes. The editors of Transforms are still trying to figure out what happens in Safari for that.

Greetings,
Dirk

[1] https://bugs.webkit.org/show_bug.cgi?id=112824

> ~TJ
> 

Received on Tuesday, 7 May 2013 00:25:00 UTC