Bugzilla – Bug 23014

Backface-visibility cannot be tested by only looking at m33

Last modified: 2013-09-25 21:09:40 UTC

Created attachment 1386 [details] 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 "before accounting for perspective". However, backface-visibility will often need to be tested on matrices that have perspective in them: - by definition of the "accumulated 3d transformation matrix" 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's backface would be visible if there is an orthographic projection. Under perspective projection, if set up correctly, the layer'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'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 --> 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't have to compute a heavy full inverse, and the implementation can remain mostly lightweight. You can see chrome's implementation here: https://code.google.com/p/chromium/codesearch#chromium/src/ui/gfx/transform.cc&q=gfx::Transform::IsBackFaceVisible&sq=package:chromium&type=cs&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 < 0) anyway. So, would it work just to change the spec to be mathematically correct and to reflect what browsers already implement?

(In reply to Shawn Singh from comment #0) > Created attachment 1386 [details] > 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 > "before accounting for perspective". However, backface-visibility will often > need to be tested on matrices that have perspective in them: > - by definition of the "accumulated 3d transformation matrix" 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's backface would be visible if there is an > orthographic projection. Under perspective projection, if set up correctly, > the layer'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'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 --> 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't have to compute a > heavy full inverse, and the implementation can remain mostly lightweight. > You can see chrome's implementation here: > > https://code.google.com/p/chromium/codesearch#chromium/src/ui/gfx/transform. > cc&q=gfx::Transform::IsBackFaceVisible&sq=package:chromium&type=cs&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 < 0) anyway. > > So, would it work just to change the spec to be mathematically correct and > 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.