Skip to content
This repository has been archived by the owner on Feb 6, 2022. It is now read-only.

Rotation #14

Open
Arnavion opened this issue Feb 11, 2014 · 7 comments
Open

Rotation #14

Arnavion opened this issue Feb 11, 2014 · 7 comments
Assignees

Comments

@Arnavion
Copy link
Owner

  • Partial implementation in this branch - diff
  • Rotation is always applied in the order Y-X-Z
  • Rotations apply from the point where they're defined till the end of the line or till they're redefined. However, a redefined rotation is always measured from the zero of the screen. For example, the line M{\fry60}N{\fry60}O will cause O to be rotated a total of 60 degrees, not 120.
  • When individual angles of rotation are thus overridden, the other angles remain unmodified. For example, in the line M{\frz45\fry60}N{\fry0}O, M will be rotated by 0-0-0, N will be rotated by 60-0-45 and O by 0-0-45
  • However, this cannot be rendered as completely separate rotations. In the previous example, the N will be slightly into the screen due to the 60 degrees Y-angle, and the O will be also into the screen (but parallel to the X-Y plane). Effectively the O will be in a plane closer to the viewer than the M, and so will appear larger.

All these facts combined mean that rotations must nest. The line M{\frz45\fry60}N{\fry0}O{\frx90\frz30}P must be rendered as follows:

<span id="1">M<span id="2">N<span id="3">O<span id="4">P</span></span></span></span>

with the following transforms on each:

#1: .transform = "";
#2: .transform = "rotateY(60deg) rotateX(0deg) rotateZ(-45deg)";
#3: .transform = "rotateZ(45deg) rotateX(-0deg) rotateY(-60deg) " + // undo existing rotation to reset back to 0
                 "rotateY(0deg) rotateX(0deg) rotateZ(-45deg)"; // apply new rotation
#4: .transform = "rotateZ(45deg) rotateX(-0deg) rotateY(-0deg) " + // undo existing rotation to reset back to 0
                 "rotateY(0deg) rotateX(90deg) rotateZ(-30deg)"; // apply new rotation

The only thing that should start a top-level span with no reversed rotation applied first is a \N


Unfortunately browsers implement rotation in a retarded manner. All rotations are done from scratch, i.e., if the parent element is rotated, the child element's rotation is not applied on top of the parent's rotation. Instead, it's applied as if the way the child is visible right now is the 0-0-0 state. Thus there is no way to undo a parent's rotation on a child and apply a new rotation.

<style type="text/css">div { display: inline-block; }</style>
<div><div>ABCD</div></div>
<div style="-webkit-transform: rotateY(60deg); transform: rotateY(60deg);"><div>ABCD</div></div>
<div style="-webkit-transform: rotateY(60deg); transform: rotateY(60deg);"><div style="-webkit-transform: rotateY(-60deg); transform: rotateY(-60deg);">ABCD</div></div>

Notice how the third div doesn't look like the first. The child doesn't have the parent's 60deg rotation reversed, instead it has a -60deg rotation applied to its appearance due to the parent rotation (second div).

Another example: http://jsfiddle.net/ag5dQ/4/ Notice how .child_b1 is the same size as .child_b, but .child_b2 isn't.

@Arnavion Arnavion self-assigned this Nov 27, 2014
@Denoder
Copy link

Denoder commented Jan 26, 2015

What about this? - http://jsfiddle.net/ag5dQ/6/ create a second rotation for it to align.

@Arnavion
Copy link
Owner Author

@ChristianMcQuilkin

The inner blue in the third diagram is supposed to look exactly like the inner blue in the first and second diagrams. The inner rectangle is meant to cancel the rotation of its parent. The parent has -60deg and the child has +60deg - in libass / VSFilter this would result in the child looking exactly as if the child had no net rotation, just like the blue rectangle in the first two diagrams. But this cannot be done in the browser CSS model.

You just made the child have 0 rotation (-60 + +60), so it's still rotated with its parent like the green rectangle.

@Denoder
Copy link

Denoder commented Jan 26, 2015

AHHHHH now I see... cant believe i missed that, I'll take a look at that and get back to you with something.

@Denoder
Copy link

Denoder commented Jan 26, 2015

@Arnavion

but for the last element you are using RotateY not Rotate like the other elements. The only way that would wro kis to make child_b2 not have any rotation for Y

@Arnavion
Copy link
Owner Author

Let me explain what my jsfiddle is meant to show.

The first diagram has two rectangles, a yellow and a blue. No rotation is applied to either of them.

The second diagram applies a +60deg Z-rotation to the yellow rectangle. This has the effect of rotating the yellow rectangle and its child the blue rectangle both by +60deg from the observer's standpoint. Next, a -60deg Z-rotation is applied on the blue rectangle. This makes it return to the original position, and from the observer's standpoint, this results in 0 net rotation for the blue rectangle.

The third diagram does the same but with Y-rotations. Here however, the blue rectangle does not return to the 0 net rotation state. This is because of how browsers apply transforms. When the browser tries to apply the rotation on the blue rectangle, it does not take into account that the blue rectangle is already rotated by +60deg around the Y-axis because of its parent. Instead, it treats its current state (which is +60deg rotated from the observer's standpoint) as the starting point, and rotates this state by -60deg. The result is the blue rectangle gets doubly squished instead of having its first squished-ness be unsquished.

That's the purpose of the third green rectangle. It represents the starting point of the transform applied to the blue rectangle.

This is not only for Y-rotations - it happens for the Z-rotations in the second diagram as well (and of course for X-rotations also). However since Z-rotations don't modify the dimensions (no squishing), the net result is identical to the first diagram.

@Denoder
Copy link

Denoder commented Jan 27, 2015

hmm then i dont see anything i can do about that there >_> - Without rotating back to the origin the only thing i was able to do was have it scale by 2 using ScaleX

http://jsfiddle.net/ag5dQ/7/

@Arnavion
Copy link
Owner Author

Correct. The point is that a simple transform like rotateY is insufficient for child rotations. One would have to write a transform matrix that take parent rotations into account - such a matrix would include both skew/rotation and potentially translational components and is harder to calculate.

In other words, the transform becomes a function of both the angles in the tags, and the current position of the text span being transformed. This is difficult in libjass as it doesn't concern itself with the positioning of text spans (it leaves that to the browser).

Arnavion pushed a commit that referenced this issue Apr 29, 2016
… dialogue, by applying the rotation transform on the sub div instead of the individual spans.

The implementation is still broken for the general case of multiple rotations (see #14), but one rotation is the much more common case.

Fixes #75
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants