Skip to content

Commit c1201ba

Browse files
committed
Define how exactly to apply perspective (w-parameter)
Fixes https://www.w3.org/Bugs/Public/show_bug.cgi?id=15605.
1 parent 39758cc commit c1201ba

3 files changed

Lines changed: 348 additions & 6 deletions

File tree

css3-transforms/ChangeLog

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
2012-05-28 ayg@aryeh.name
2+
Define how exactly to apply perspective (w-parameter)
3+
Fixes https://www.w3.org/Bugs/Public/show_bug.cgi?id=15605
4+
15
2012-05-26 dschulze@adobe.com
26
Define neutral element for addition on transforms.
37

css3-transforms/Overview.html

Lines changed: 154 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@
3939

4040
<h1>CSS Transforms</h1>
4141

42-
<h2 class="no-num no-toc" id=longstatus-date>Editor's Draft 26 May 2012</h2>
42+
<h2 class="no-num no-toc" id=longstatus-date>Editor's Draft 28 May 2012</h2>
4343

4444
<dl>
4545
<dt>This version:
4646

4747
<dd> <a
48-
href="http://www.w3.org/TR/2012/ED-css3-transforms-20120526/">http://dev.w3.org/csswg/css3-transforms/</a>
49-
<!--http://www.w3.org/TR/2012/WD-css3-transforms-20120526/-->
48+
href="http://www.w3.org/TR/2012/ED-css3-transforms-20120528/">http://dev.w3.org/csswg/css3-transforms/</a>
49+
<!--http://www.w3.org/TR/2012/WD-css3-transforms-20120528/-->
5050

5151
<dt>Latest version:
5252

@@ -199,6 +199,10 @@ <h2 class="no-num no-toc" id=contents>Table of contents</h2>
199199
<ul class=toc>
200200
<li><a href="#transform-3d-rendering"><span class=secno>6.1. </span>3D
201201
Transform Rendering</a>
202+
203+
<li><a href="#processing-of-perspective-transformed-boxes"><span
204+
class=secno>6.2. </span> Processing of Perspective-Transformed Boxes
205+
</a>
202206
</ul>
203207

204208
<li><a href="#transform-property"><span class=secno>7. </span> The
@@ -1117,7 +1121,7 @@ <h3 id=transform-3d-rendering><span class=secno>6.1. </span>3D Transform
11171121
</div>
11181122

11191123
<p> Using three-dimensional transforms, it's possible to transform an
1120-
element such that its reverse side is towards the viewer. 3D-tranformed
1124+
element such that its reverse side is towards the viewer. 3D-transformed
11211125
elements show the same content on both sides, so the reverse side looks
11221126
like a mirror-image of the front side (as if the element were projected
11231127
onto a sheet of glass). Normally, elements whose reverse side is towards
@@ -1129,7 +1133,152 @@ <h3 id=transform-3d-rendering><span class=secno>6.1. </span>3D Transform
11291133
class=css><code class=css>backface-visibility: hidden</code></code>
11301134
were animating, such that its front and reverse sides were alternately
11311135
visible, then it would only be visible when the front side were towards
1132-
the viewer.</p>
1136+
the viewer.
1137+
1138+
<h3 id=processing-of-perspective-transformed-boxes><span class=secno>6.2.
1139+
</span> Processing of Perspective-Transformed Boxes</h3>
1140+
1141+
<div class=issue>
1142+
<p class=desc> This is a first pass at an attempt to precisely specify how
1143+
exactly to transform elements using the provided matrices. It might not
1144+
be ideal, and implementer feedback is encouraged. See <a
1145+
href="https://www.w3.org/Bugs/Public/show_bug.cgi?id=15605">bug
1146+
15605</a>.</p>
1147+
</div>
1148+
1149+
<p> The <a href="#TermAccumulated3DTransformationMatrix">accumulated 3D
1150+
transformation matrix</a> is a 4×4 matrix, while the objects to be
1151+
transformed are two-dimensional boxes. To transform each corner
1152+
(<var>a</var>, <var>b</var>) of a box, the matrix must first be applied to
1153+
(<var>a</var>, <var>b</var>, 0, 1), which will result in a
1154+
four-dimensional point (<var>x</var>, <var>y</var>, <var>z</var>,
1155+
<var>w</var>). This is transformed back to a three-dimensional point
1156+
(<var>x</var>′, <var>y</var>′, <var>z</var>′) as follows:
1157+
1158+
<p> If <var>w</var> &gt; 0, (<var>x</var>′, <var>y</var>′,
1159+
<var>z</var>′) = (<var>x</var>/<var>w</var>, <var>y</var>/<var>w</var>,
1160+
<var>z</var>/<var>w</var>).
1161+
1162+
<p> If <var>w</var> = 0, (<var>x</var>′, <var>y</var>′,
1163+
<var>z</var>′) = (<var>x</var><var>n</var>, <var>y</var>
1164+
<var>n</var>, <var>z</var><var>n</var>). <var>n</var> is an
1165+
implementation-dependent value that should be chosen so that
1166+
<var>x</var>′ or <var>y</var>′ is much larger than the viewport size,
1167+
if possible. For example, (5px, 22px, 0px, 0) might become (5000px,
1168+
22000px, 0px), with <var>n</var> = 1000, but this value of <var>n</var>
1169+
would be too small for (0.1px, 0.05px, 0px, 0). This specification does
1170+
not define the value of <var>n</var> exactly. Conceptually,
1171+
(<var>x</var>′, <var>y</var>′, <var>z</var>′) is <a
1172+
href="http://en.wikipedia.org/wiki/Plane_at_infinity">infinitely far</a>
1173+
in the direction (<var>x</var>, <var>y</var>, <var>z</var>).
1174+
1175+
<p> If <var>w</var> &lt; 0 for all four corners of the transformed box, the
1176+
box is not rendered.
1177+
1178+
<p> If <var>w</var> &lt; 0 for one to three corners of the transformed box,
1179+
the box must be replaced by a polygon that has any parts with <var>w</var>
1180+
&lt; 0 cut out. This will in general be a polygon with three to five
1181+
vertices, of which exactly two will have <var>w</var> = 0 and the rest
1182+
<var>w</var> &gt; 0. These vertices are then transformed to
1183+
three-dimensional points using the rules just stated. Conceptually, a
1184+
point with <var>w</var> &lt; 0 is "behind" the viewer, so should not be
1185+
visible.
1186+
1187+
<div class=example>
1188+
<pre>&lt;style&gt;
1189+
.transformed {
1190+
height: 100px;
1191+
width: 100px;
1192+
background: lime;
1193+
transform: perspective(50px) translateZ(100px);
1194+
}
1195+
&lt;/style&gt;</pre>
1196+
1197+
<p> All of the box's corners have <var>z</var>-coordinates greater than
1198+
the perspective. This means that the box is behind the viewer and will
1199+
not display. Mathematically, the point (<var>x</var>, <var>y</var>) first
1200+
becomes (<var>x</var>, <var>y</var>, 0, 1), then is translated to
1201+
(<var>x</var>, <var>y</var>, 100, 1), and then applying the perspective
1202+
results in (<var>x</var>, <var>y</var>, 100, −1). The
1203+
<var>w</var>-coordinate is negative, so it does not display. An
1204+
implementation that doesn't handle the <var>w</var> &lt; 0 case
1205+
separately might incorrectly display this point as (−<var>x</var>,
1206+
<var>y</var>, −100), dividing by −1 and mirroring the box.</p>
1207+
</div>
1208+
1209+
<div class=example>
1210+
<pre>&lt;style&gt;
1211+
.transformed {
1212+
height: 100px;
1213+
width: 100px;
1214+
background: radial-gradient(yellow, blue);
1215+
transform: perspective(50px) translateZ(50px);
1216+
}
1217+
&lt;/style&gt;</pre>
1218+
1219+
<p> Here, the box is translated upward so that it sits at the same place
1220+
the viewer is looking from. This is like bringing the box closer and
1221+
closer to one's eye until it fills the entire field of vision. Since the
1222+
default transform-origin is at the center of the box, which is yellow,
1223+
the screen will be filled with yellow.</p>
1224+
1225+
<p> Mathematically, the point (<var>x</var>, <var>y</var>) first becomes
1226+
(<var>x</var>, <var>y</var>, 0, 1), then is translated to (<var>x</var>,
1227+
<var>y</var>, 50, 1), then becomes (<var>x</var>, <var>y</var>, 50, 0)
1228+
after applying perspective. Relative to the transform-origin at the
1229+
center, the upper-left corner was (−50, −50), so it becomes (−50,
1230+
−50, 50, 0). This is transformed to something very far to the upper
1231+
left, such as (−5000, −5000, 5000). Likewise the other corners are
1232+
sent very far away. The radial gradient is stretched over the whole box,
1233+
now enormous, so the part that's visible without scrolling should be the
1234+
color of the middle pixel: yellow. However, since the box is not actually
1235+
infinite, the user can still scroll to the edges to see the blue parts.</p>
1236+
<!-- TODO: Maybe we should specify that the whole thing is
1237+
yellow here somehow? Doesn't seem worth it. -->
1238+
</div>
1239+
1240+
<div class=example>
1241+
<pre>&lt;style&gt;
1242+
.transformed {
1243+
height: 50px;
1244+
width: 50px;
1245+
background: lime;
1246+
border: 25px solid blue;
1247+
transform-origin: left;
1248+
transform: perspective(50px) rotateY(-45deg);
1249+
}
1250+
&lt;/style&gt;</pre>
1251+
1252+
<p> The box will be rotated toward the viewer, with the left edge staying
1253+
fixed while the right edge swings closer. The right edge will be at about
1254+
<var>z</var> = 70.7px, which is closer than the perspective of 50px.
1255+
Therefore, the rightmost edge will vanish ("behind" the viewer), and the
1256+
visible part will stretch out infinitely far to the right.</p>
1257+
1258+
<p> Mathematically, the top right vertex of the box was originally (100,
1259+
−50), relative to the transform-origin. It is first expanded to (100,
1260+
−50, 0, 1). After applying the transform specified, this will get
1261+
mapped to about (70.71, −50, 70.71, −0.4142). This has <var>w</var> =
1262+
−0.4142 &lt; 0, so we need to slice away the part of the box with
1263+
<var>w</var> &lt; 0. This results in the new top-right vertex being (50,
1264+
−50, 50, 0). This is then mapped to some faraway point in the same
1265+
direction, such as (5000, −5000, 5000), which is up and to the right
1266+
from the transform-origin. Something similar is done to the lower right
1267+
corner, which gets mapped far down and to the right. The resulting box
1268+
stretches far past the edge of the screen.</p>
1269+
1270+
<p> Again, the rendered box is still finite, so the user can scroll to see
1271+
the whole thing if he or she chooses. However, the right part has been
1272+
chopped off. No matter how far the user scrolls, the rightmost 30px or so
1273+
of the original box will not be visible. The blue border was only 25px
1274+
wide, so it will be visible on the left, top, and bottom, but not the
1275+
right.</p>
1276+
1277+
<p> The same basic procedure would apply if one or three vertices had
1278+
<var>w</var> &lt; 0. However, in that case the result of truncating the
1279+
<var>w</var> &lt; 0 part would be a triangle or pentagon instead of a
1280+
quadrilateral.</p>
1281+
</div>
11331282
<!-- ======================================================================================================= -->
11341283

11351284
<h2 id=transform-property><span class=secno>7. </span> The ‘<a

0 commit comments

Comments
 (0)