W3C home > Mailing lists > Public > www-style@w3.org > March 2015

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

From: Rik Cabanier <cabanier@gmail.com>
Date: Thu, 5 Mar 2015 22:26:57 -0800
Message-ID: <CAGN7qDC-a+QEH-B3zQ_OqHRBaGcR6f9k8jMyo0tY5aoBmrHQHQ@mail.gmail.com>
To: Shane Stephens <shans@google.com>
Cc: "Tab Atkins Jr." <jackalmage@gmail.com>, www-style list <www-style@w3.org>
On Thu, Mar 5, 2015 at 1:48 PM, Shane Stephens <shans@google.com> wrote:

> Dredging this up from the depths (original comment below for context):
>
> Nearly 2 years ago, we were considering whether to change the behavior of
> transform matrix interpolation to always take the shortest path for the
> rotation component.
>
> (Remember: if we can interpolate transform components, we do. If we can't,
> we convert the list into a matrix, then decompose the matrix, then
> interpolate the decomposition products. One of those is a rotation
> quaternion).
>
> The current state of the world is this:
>
> * Firefox, IE and the specification agree that interpolations should
> directly SLERP the quaternions that come out of decomposition.
>
> * Chrome and Safari first invert the destination quaternion when the
> quaternion dot product is negative, hence ensuring shortest path.
>
> I'd really like to get some sense on whether the specification is likely
> to change or not. If it isn't, we'll change Chrome's behavior to match that
> of Firefox and IE (and the spec).
>

We changed the spec so it is matching what Safari implemented since people
like its behavior best.
We created patches for Blink and Firefox to match but they didn't get out
of the review process.

I'm in the process of refreshing the Firefox patch.


> I don't really think it matters one way or the other - we're talking about
> a side-effect of an already broken animation scenario (if you want a
> particular transform interpolation effect then you should ensure that the
> transform components match). But I would like to move towards consistency :)
>
> Cheers,
>     -Shane
>
> On Tue, May 7, 2013 at 8:49 AM 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.  ^_^
>>
>> ~TJ
>>
>>
Received on Friday, 6 March 2015 06:27:44 UTC

This archive was generated by hypermail 2.3.1 : Monday, 2 May 2016 14:39:30 UTC