<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://www.w3.org/Bugs/Public/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.4"
          urlbase="https://www.w3.org/Bugs/Public/"
          
          maintainer="sysbot+bugzilla@w3.org"
>

    <bug>
          <bug_id>23014</bug_id>
          
          <creation_ts>2013-08-19 22:00:54 +0000</creation_ts>
          <short_desc>Backface-visibility cannot be tested by only looking at m33</short_desc>
          <delta_ts>2017-01-13 18:02:44 +0000</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>1</classification_id>
          <classification>Unclassified</classification>
          <product>CSS</product>
          <component>Transforms</component>
          <version>unspecified</version>
          <rep_platform>PC</rep_platform>
          <op_sys>All</op_sys>
          <bug_status>RESOLVED</bug_status>
          <resolution>MOVED</resolution>
          
          
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords></keywords>
          <priority>P2</priority>
          <bug_severity>normal</bug_severity>
          <target_milestone>---</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter name="Shawn Singh">shawnsingh</reporter>
          <assigned_to name="Simon Fraser">smfr</assigned_to>
          <cc>ayg</cc>
    
    <cc>cmarrin</cc>
    
    <cc>dino</cc>
    
    <cc>dschulze</cc>
    
    <cc>eoconnor</cc>
    
    <cc>smfr</cc>
    
    <cc>trchen</cc>
          
          <qa_contact>public-css-bugzilla</qa_contact>

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>92296</commentid>
    <comment_count>0</comment_count>
      <attachid>1386</attachid>
    <who name="Shawn Singh">shawnsingh</who>
    <bug_when>2013-08-19 22:00:54 +0000</bug_when>
    <thetext>Created attachment 1386
Example of a transform that needs to account for perspective for correct backface-visibility.

According to the current spec, backface-visibility must be checked by testing whether the m33 element of the matrix is positive or negative. But the problem is that this only works without a perspective component.

Actually, it seems like this is already acknowledged since the spec says &quot;before accounting for perspective&quot;. However, backface-visibility will often need to be tested on matrices that have perspective in them:
  - by definition of the &quot;accumulated 3d transformation matrix&quot; the perspective will be included in that matrix
  - a user may use the matrix3d() transform function in their CSS to specify arbitrary perspective on an element, even if it is not in a 3d rendering context.

I attached an example page with a layer rotated just more than 90 degrees.  In this configuration, the layer&apos;s backface would be visible if there is an orthographic projection.  Under perspective projection, if set up correctly, the layer&apos;s front side is actually visible.

The accumulated 3d transformation matrix of that example is:

[ +1.0574 +0.0000 +2.4037 +88.5277
  +1.2310 +1.0000 +0.4341 +53.7981
  -0.4924 +0.0000 -0.1736 +98.4808
  +0.0025 +0.0000 +0.0009 +0.5076 ]

The m33 element is negative, but because of perspective, we should interpret that the front side of the layer is facing the camera.

Instead of checking m33, there are at least two ways to correctly implement backface visibility:

(1) Inspect vertices of the element being drawn for clockwise / counter-clockwise, similar to how game engines often perform backface culling

(2) Rigorously apply the transform the z normal, and check the transformed normal is still facing the camera (i.e. it&apos;s z value is positive or negative).  However, we cannot just apply the transform to the z normal by doing a basic matrix*vector operation --&gt; that is why checking m33 only is not correct.  Instead, mathematically if we want to transform a surface normal, we must do inverseTranspose(matrix) * normalVector.

Knowing that the normalVector is (0, 0, 1, 0), we don&apos;t have to compute a heavy full inverse, and the implementation can remain mostly lightweight.  You can see chrome&apos;s implementation here:
  https://code.google.com/p/chromium/codesearch#chromium/src/ui/gfx/transform.cc&amp;q=gfx::Transform::IsBackFaceVisible&amp;sq=package:chromium&amp;type=cs&amp;l=219

I have not tested how the attached example works in IE.  Firefox, Safari, and Chrome seem to get backface visibility correct on the attached example page -- which implies that no browser is checking for (m33 &lt; 0) anyway.

So, would it work just to change the spec to be mathematically correct and to reflect what browsers already implement?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>93831</commentid>
    <comment_count>1</comment_count>
    <who name="Dirk Schulze">dschulze</who>
    <bug_when>2013-09-25 21:09:40 +0000</bug_when>
    <thetext>(In reply to Shawn Singh from comment #0)
&gt; Created attachment 1386 [details]
&gt; Example of a transform that needs to account for perspective for correct
&gt; backface-visibility.
&gt; 
&gt; According to the current spec, backface-visibility must be checked by
&gt; testing whether the m33 element of the matrix is positive or negative. But
&gt; the problem is that this only works without a perspective component.
&gt; 
&gt; Actually, it seems like this is already acknowledged since the spec says
&gt; &quot;before accounting for perspective&quot;. However, backface-visibility will often
&gt; need to be tested on matrices that have perspective in them:
&gt;   - by definition of the &quot;accumulated 3d transformation matrix&quot; the
&gt; perspective will be included in that matrix
&gt;   - a user may use the matrix3d() transform function in their CSS to specify
&gt; arbitrary perspective on an element, even if it is not in a 3d rendering
&gt; context.
&gt; 
&gt; I attached an example page with a layer rotated just more than 90 degrees. 
&gt; In this configuration, the layer&apos;s backface would be visible if there is an
&gt; orthographic projection.  Under perspective projection, if set up correctly,
&gt; the layer&apos;s front side is actually visible.
&gt; 
&gt; The accumulated 3d transformation matrix of that example is:
&gt; 
&gt; [ +1.0574 +0.0000 +2.4037 +88.5277
&gt;   +1.2310 +1.0000 +0.4341 +53.7981
&gt;   -0.4924 +0.0000 -0.1736 +98.4808
&gt;   +0.0025 +0.0000 +0.0009 +0.5076 ]
&gt; 
&gt; The m33 element is negative, but because of perspective, we should interpret
&gt; that the front side of the layer is facing the camera.
&gt; 
&gt; Instead of checking m33, there are at least two ways to correctly implement
&gt; backface visibility:
&gt; 
&gt; (1) Inspect vertices of the element being drawn for clockwise /
&gt; counter-clockwise, similar to how game engines often perform backface culling
&gt; 
&gt; (2) Rigorously apply the transform the z normal, and check the transformed
&gt; normal is still facing the camera (i.e. it&apos;s z value is positive or
&gt; negative).  However, we cannot just apply the transform to the z normal by
&gt; doing a basic matrix*vector operation --&gt; that is why checking m33 only is
&gt; not correct.  Instead, mathematically if we want to transform a surface
&gt; normal, we must do inverseTranspose(matrix) * normalVector.
&gt; 
&gt; Knowing that the normalVector is (0, 0, 1, 0), we don&apos;t have to compute a
&gt; heavy full inverse, and the implementation can remain mostly lightweight. 
&gt; You can see chrome&apos;s implementation here:
&gt;  
&gt; https://code.google.com/p/chromium/codesearch#chromium/src/ui/gfx/transform.
&gt; cc&amp;q=gfx::Transform::IsBackFaceVisible&amp;sq=package:chromium&amp;type=cs&amp;l=219
&gt; 
&gt; I have not tested how the attached example works in IE.  Firefox, Safari,
&gt; and Chrome seem to get backface visibility correct on the attached example
&gt; page -- which implies that no browser is checking for (m33 &lt; 0) anyway.
&gt; 
&gt; So, would it work just to change the spec to be mathematically correct and
&gt; to reflect what browsers already implement?

We already seek requests from browser vendors for that. Thank you very much for your input. I agree that we need to take the perspective into account. Looking at m33 is not enough. I still need to check the math. Do you have a source for the suggested method other than a source file in Chrome? I suggest posting this conclusion on the mailing list so that hopefully more people will read this.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>119164</commentid>
    <comment_count>2</comment_count>
    <who name="Tien-Ren Chen">trchen</who>
    <bug_when>2015-03-31 23:58:10 +0000</bug_when>
    <thetext>Replying to Shawn&apos;s comment. The proposal (1) of using winding direction won&apos;t work because we won&apos;t be able to distinguish rotateY(180deg) and scaleX(-1) that way. Both will change the winding direction, but rotateY(180deg) should be considered the plane being rotated to the back face while scaleX(-1) should be considered the contents on the plane being mirrored.

However I found there is an alternative to proposal (2) when I studied some perspective bug in Chromium. Here is my abandoned CL: https://codereview.chromium.org/1047463002/

For a short summary,
Proposal (2) calculates det|M33| * det|M| &lt; 0
My proposal calculates det|M33| * det|M34| &gt; 0

Both formulas behave the same on regular matrices that does xyz transform first and applying a positive perspective at last. The difference stands where they handle negative perspective. i.e. The farther in z, the bigger the object seems. The proposal (2) prefers xyz space, where my formula prefers xyw space.

That is, for perspective(-1px), proposal (2) says front, my proposal says back.

Note that my formula runs 3x faster with finite perspective, and 2x faster with infinite perspective. Due to avoiding to calculate 4x4 determinant.

I think the spec should be clear about how to handle the case where the forth row of the matrix can&apos;t be generated by simple positive perspective. (Negative perspective is one problem. We can also have w depending on other rows.)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>128381</commentid>
    <comment_count>3</comment_count>
    <who name="Simon Fraser">smfr</who>
    <bug_when>2017-01-13 18:02:44 +0000</bug_when>
    <thetext>https://github.com/w3c/csswg-drafts/issues/917</thetext>
  </long_desc>
      
          <attachment
              isobsolete="0"
              ispatch="0"
              isprivate="0"
          >
            <attachid>1386</attachid>
            <date>2013-08-19 22:00:54 +0000</date>
            <delta_ts>2013-08-19 22:00:54 +0000</delta_ts>
            <desc>Example of a transform that needs to account for perspective for correct backface-visibility.</desc>
            <filename>backface-visibility-correctness.html</filename>
            <type>text/html</type>
            <size>1039</size>
            <attacher name="Shawn Singh">shawnsingh</attacher>
            
              <data encoding="base64">PCFET0NUWVBFIGh0bWw+Cgo8IS0tCiAgIFJlZHVjZWQgdGVzdCBjYXNlIGRlbW9uc3RyYXRpbmcg
YSBjb25maWd1cmF0aW9uIHdoZXJlCiAgIGEgbGF5ZXIncyBsb2NhbCB0cmFuc2Zvcm0gd291bGQg
YmUgY29uc2lkZXJlZCBiYWNrIGZhY2luZywKICAgYnV0IGlmIHRoZXJlIGlzIHBlcnNwZWN0aXZl
IGFwcGxpZWQsIHRoZSBsYXllciB3b3VsZAogICBhY3R1YWxseSBiZSBmcm9udC1mYWNpbmcuIFRo
ZSByZXN1bHRpbmcgbWF0cml4IHdpdGgKICAgcGVyc3BlY3RpdmUgaGFzIGEgbmVnYXRpdmUgZWxl
bWVudCBpbiB0aGUgM3JkIHJvdywgM3JkIGNvbHVtbSwKICAgc28gaXQgaXMgaW5jb3JyZWN0IHRv
IHRlc3QgYmFja2ZhY2UgdmlzaWJpbGl0eSB1c2luZyBvbmx5CiAgIHRoYXQgZWxlbWVudC4KLS0+
Cgo8aGVhZD4KPHN0eWxlPgogIC5wZXJzcGVjdGl2ZUNvbnRhaW5lciB7CiAgICAtd2Via2l0LXRy
YW5zZm9ybS1zdHlsZTogcHJlc2VydmUtM2Q7CiAgICAtd2Via2l0LXBlcnNwZWN0aXZlOiAyMDBw
eDsKICAgIHRyYW5zZm9ybS1zdHlsZTogcHJlc2VydmUtM2Q7CiAgICBwZXJzcGVjdGl2ZTogMjAw
cHg7CiAgICBwb3NpdGlvbjogYWJzb2x1dGU7CiAgICB0b3A6IDE1MHB4OwogICAgbGVmdDogMTUw
cHg7CiAgfQoKICAucm90YXRlZEVsZW1lbnQgewogICAgLXdlYmtpdC1iYWNrZmFjZS12aXNpYmls
aXR5OiBoaWRkZW47CiAgICAtd2Via2l0LXRyYW5zZm9ybTogVHJhbnNsYXRlWCgtMTAwcHgpIFJv
dGF0ZVkoMTAwZGVnKTsKICAgIGJhY2tmYWNlLXZpc2liaWxpdHk6IGhpZGRlbjsKICAgIHRyYW5z
Zm9ybTogVHJhbnNsYXRlWCgtMTAwcHgpIFJvdGF0ZVkoMTAwZGVnKTsKICAgIHdpZHRoOiAyMDBw
eDsKICAgIGhlaWdodDogMjAwcHg7CiAgICBiYWNrZ3JvdW5kLWNvbG9yOiBsaW1lOwogIH0KPC9z
dHlsZT4KPC9oZWFkPgo8Ym9keT4KICA8ZGl2IGNsYXNzPSJwZXJzcGVjdGl2ZUNvbnRhaW5lciI+
CiAgICA8ZGl2IGNsYXNzPSJyb3RhdGVkRWxlbWVudCI+IEhFTExPIFdPUkxEIDwvZGl2PgogIDwv
ZGl2Pgo8L2JvZHk+Cg==
</data>

          </attachment>
      

    </bug>

</bugzilla>