- From: Nexii Malthus <nexiim@gmail.com>
- Date: Mon, 19 Sep 2016 14:56:37 +0000
- To: Rik Cabanier <cabanier@gmail.com>, "/#!/JoePea" <trusktr@gmail.com>
- Cc: "Tab Atkins Jr." <jackalmage@gmail.com>, trchen@chromium.org, Chris Harrelson <chrishtr@google.com>, Simon Fraser <simon.fraser@apple.com>, "public-fx@w3.org" <public-fx@w3.org>
- Message-ID: <CALbUtNYBmD6G4U7QLnnnweZgMXK-MTkAmKvE-j5EO5Gu4_HzJg@mail.gmail.com>
Rik, What is the exact effect you are trying to achieve? If I break the rule of markup changes I can achieve this, which is to wrap it into a sub-scene to target the composited render-to-texture layer: https://jsfiddle.net/acp4vk5u/ Thus, the wheels are properly occluded etc. Or is there a demo of more sophisticated 3D scene graph and how it interacts with other 3D surfaces that are problematic? -- My own proposal would be to have preserve-3d manipulate sub-scene perspective layers to be in the same coordinate system, as I would expect it to be behave as a web developer. (E.g. no need to layer with extra div, but proper implementation of the Impostor technique as I mentioned before) Additional feature could be being able to enable depth-testing against the impostors depth scene. Regards, Martin Pitt On Mon, 19 Sep 2016 at 09:34 Rik Cabanier <cabanier@gmail.com> wrote: > On Mon, Sep 19, 2016 at 1:51 AM, /#!/JoePea <trusktr@gmail.com> wrote: > >> Hey all, >> >> Sorry if my previous replies were rash, but I've collected myself and >> prepared the following response which can hopefully paint a picture of the >> problem as well as propose a solution. >> >> Let's step outside of the web box for a second, and just imagine: we have >> a 3D engine, and with that engine we have game characters or objects that >> are made of arbitrary number of descendant children (subtrees) in an >> overall scene graph. Imagine these objects are in a game where things fade >> in and out of view and therefore involve transparency. >> >> I believe we all want the API for doing this to be as easy as possible. >> And, since this is the case, then it makes sense that applying opacity less >> than one to the root node of an object in a scene graph will make the whole >> object transparent without flattening it. >> >> Take for example, this basic car I just made: >> >> https://jsfiddle.net/trusktr/ymonmo70/1 >> > === Challenge === >> >> Here's a challenge for you all: make the whole car transparent without >> modifying the markup (it is important not to modify the markup because that >> is what CSS is about). But, if you want to modify the markup, I am open to >> seeing that solution as well (and I already know the non-nested solution >> will work, but will be tedious to migrate to). Keep in mind, this is very >> very easy with "legacy" behavior, and we can make the whole car transparent >> by simply adding the following CSS into the CSS text box: >> >> ```css >> .car { >> opacity: 0.5; >> } >> ``` >> >> >> which results in the following (works in Safari 9 and Firefox 47, broken >> in Chrome 53): >> >> https://jsfiddle.net/trusktr/ymonmo70/2 >> > > Isn't the rendering result of the car wrong? I can see the tires that are > supposed to be occluded by the frame of the car. > > >> >> As far as I know, I don't think any of you will have a solution that is >> as simple as simply applying an opacity to the root node of the car. The >> simplest solution I can imagine is applying opacity to all the leaf nodes, >> and that will involve much more work than the addition of a single opacity >> property to a single selector or element. >> > > There is. Apply opacity on the scene. > > >> With the new behavior, it isn't so simple any more -- *the web's 3D API >> is now **more difficult to use*, which isn't what we want as API >> developers. >> >> We should aim to make 3D programming more easy, not more difficult! >> Opacity flattening makes 3D programming more difficult because the 3D >> library programmer now has to go and keep track of opacities virtually, for >> every node in the scene (DOM nodes in our case) and then has to traverse >> the scene graph (DOM tree) manually and multiply all opacities manually in >> order to finally apply actual opacities to the leaf-most items (elements) >> in the scene graph. >> >> Note, even with "legacy" behavior or the new flattening behavior, there >> is currently no way to make rendered non-leaf nodes transparent. In the >> following example, try and make *only* the red box transparent but not >> anything else (i.e. not it's children): >> >> https://jsfiddle.net/trusktr/ymonmo70/4 >> > > you can just apply transparency to the color of the red box. > > >> With the new behavior, we are limited to making only leaf-nodes of an >> existing scene transparent, and keep in mind we'd like to apply CSS *without >> modifying markup*. >> >> One of the great things about preserve-3d and nested elements is that >> transformation matrices can be cached, and don't need to be re-calculated >> all the time on the JavaScript side because the HTML engine has them cached >> in the DOM hierarchy. This prevents a TON of string manipulation in >> JavaScript due to converting numbers into strings to pass to the CSS engine >> via style tags (that will be fixed with Typed CSSOM, but we're not sure >> when that's making it into the wild). >> >> In legacy behavior, the same applies to opacity: the HTML/CSS engine >> caches values and does multiplication automatically, which makes the end >> API easier to use for 3D programming, and *more performant.* >> >> In order to solve the problem that the new opacity behavior entails, the >> best solution is (unfortunately) to abandon preserve-3d and nested DOM (*losing >> the performance benefits*), then keeping track of the transformation and >> opacity hierarchy manually, multiplying down the tree manually, and finally >> applying *all the values via number-to-string conversion in the style >> attributes, which may involve string parsing, splitting, joining, etc, >> before being actually passed to the style attribute (yikes!)*. >> >> Reverting to the non-nested approach means that we are forfeiting the >> performance advantages of the nested DOM approach just to achieve what we >> want. >> >> Note, using the non-nested approach, virtual hierarchies, and manual >> handling of the math allows us to easily make a parent in the hierarchy >> transparent but not its children (which is impossible in the nested >> approach using the `opacity` property). >> >> === Impact === >> >> One argument for the go-ahead to implement this change is that "not many >> people are impacted". >> >> I'd like to argue that 3D in the web (as far as DOM goes) is already >> fairly difficult compared to code-based APIs (i.e. imperative APIs rather >> than declarative APIs, and not just in the web), and relatively few people >> actually use CSS3D. The vast majority of websites still use only the >> decades-old 2-dimensional technology of the web, and the 3D aspects of >> HTML/CSS are relatively new and difficult to mix with the 2-dimensional >> features. It may be easy to think that many people aren't affected by this, >> but let's take into consideration the ratio of the number of people who use >> opacity in 3D scenes to the number of people who program CSS3D scenes. If >> you take these numbers into consideration, I am willing to bet that the >> number will be a lot higher than the 0.006% mentioned in the blink-dev >> thread >> <https://groups.google.com/a/chromium.org/d/msg/blink-dev/eBIp90_il1o/9q3M0ww2BgAJ> >> . >> >> Famous was making a an open-source library that depended on the legacy >> behavior, and this change breaks that library. They've gone proprietary, >> and their proprietary stuff probably still depends on the legacy behavior. >> They will now face the chore of re-writing parts of their library to >> convert from nested dom to non-nested dom if they wish for opacity to work >> the same as before. >> >> I'd like to show you how these changes impact my own library at >> http://infamous.io (which is being renamed and moved to a new domain >> soon). >> >> My library gives us both a JavaScript API (imperative) and a >> Custom-Element-based HTML API (declarative) for defining 3D scenes. When >> using the JavaScript API, it generates the same elements as when using the >> HTML API. For our purposes, I will show only the HTML API. >> >> Here is the same car example as above (or, at least similar), made with >> my custom elements: >> >> https://jsfiddle.net/trusktr/ymonmo70/5 >> >> What is great about this example is that those custom elements are *the >> elements themselves* in the final rendering (look in the element >> inspector and notice that they have `transform: matrix3d()` applied to >> them). This means we can place anything into those elements. For example, >> let's place some text onto the surfaces of the car just for fun: >> >> https://jsfiddle.net/trusktr/ymonmo70/6 >> >> Now, if we apply opacity, the whole car will be flattened in Chrome 53 >> (compare it to Safari 9) because we've applied opacity onto the `.car` >> element element: >> >> https://jsfiddle.net/trusktr/ymonmo70/7 >> >> I believe I have something really nice in the works, and plan to add >> WebGL soon, but now it is fundamentally broken: in order to fix the >> rendering, but keep my same nested markup, I will have to render new >> elements into a flat structure that sits next to my <motor-scene> elements. >> This means that for each motor-node element I will create a reciprocal >> element in the actual rendering context, while my custom elements will not >> actually be rendered (they will be display:none). In other words, although >> I'd like for my API to be nested and using preserve-3d, I will have to >> render *completely separate elements* next to my custom elements in >> order to solve the opacity problem that is on my hands now. >> >> But, there are some problems with this! Remember that we were able to >> place content like text inside the custom elements, and it worked fine >> because the custom elements are part of the actual rendered scene? >> >> Well, now that won't be the case any more. Now I have the following >> problems to deal with: >> >> 1. I have to convert my code so it renders non-nested elements next >> to my custom elements (or maybe inside a ShadowDOM root). >> 2. I will have to implement transformation caching just for DOM >> rendering, and can no longer take advantage of the HTML engine's transform >> caching. >> 3. Same for opacity caching down the scene graph, I will need to >> implement it rather than let the HTML engine handle it. >> 4. Lastly, but most problematically, I have to find a way to clone or >> copy the user's content from inside my custom elements into the new >> non-nested elements. This will have detrimental effects on the user's >> ability to target and select those elements for styling, as they will no >> longer appear in their original places. Users will need to use IDs all over >> the place when they probably shouldn't, and will likely mess up a bunch of >> times before discovering the ID workaround. This may also have an impact on >> SEO, but I haven't looked into that much yet. >> >> The first three points aren't as bad as the fourth, as I'll have to >> implement the first three points when I add WebGL anyways. But, the fourth >> point is really bad! The new behavior is an extreme pain because of point >> number four. >> >> I hope you can see how, from my perspective as a library author writing >> on top of HTML/CSS3D, this is a very unwelcoming change if opacity is to >> have any meaning in my 3D scenes. >> >> There aren't many people doing what I'm doing. There are only three >> libraries out there that are doing what I am doing (that I know of): >> >> - Three.js <http://threejs.org> - Three.js uses the non-nested >> approach, so does not face the opacity problem. People who use Three.js' >> CSS3DRenderer know what they are working with from the start, and they >> won't possibly get confused in targeting their elements for styling, >> because their elements will not be transplanted like with my library. But >> note, Three.js will not be able to update to the nested-approach due to >> this problem, and therefore won't be able to have the performance benefits >> of the nested approach. >> - Famo.us <http://deprecated.famous.org> (0.3 and below) - Like >> Three.js, uses non-nested approach, and is worry-free like Three.js. >> - Famo.us Engine <http://github.com/famous/engine> (0.5 and above) - >> Uses the nested approach, and is now broken just like my library. >> - Samsara <http://samsarajs.org> - Uses the non-nested approach, so >> no problems there. >> - Infamous <http://infamous.io> - My library, which uses the nested >> approach. Problem! >> >> In sincerity, opacity flattening is a breaking change that shouldn't have >> been implemented by any browsers without a full solution for "legacy" code >> with 3D in mind. >> >> === What We Need === >> >> What we need are possibly at least three forms of opacity: >> >> 1. 3-dimensional, like the legacy behavior where things don't get >> flattened and opacities are multiplied down the hierarchy. >> 2. Parent-only (opacity on a single element), where nothing is >> flattened, and opacity is applied only to the target element and not its >> children. Note, there is currently no way to do this in the nested >> approach, only in the non-nested approach with virtual hierarchies. In >> "legacy" behavior, we can only apply opacity to an entire subtree of a 3D >> context, not just to a parent element, so that's either all or nothing. >> 3. Flattening, which is the new behavior, though I fail to see why >> anyone applying opacity to a 3D object desires for the object to be >> suddenly flat, as that doesn't make much sense and is unintuitive, and >> means the API is more difficult to use that what we'd like. >> >> Note, with "legacy" behavior, *it is already possible to create a new 3D >> context and apply opacity to it*, so this new behavior isn't actually >> needed (from a functional perspective), because we can currently achieve >> the same behavior with the "legacy" implementation. The new behavior does >> two things: >> >> 1. it eliminates the desired 3D behavior in nested scenes that use >> preserve-3d >> 2. it adds a second method of opacifying an entire 3D scene which *we >> can already do*. >> >> Here is an example of just that using "legacy" techniques, where I simply >> add the style `motor-scene {opacity: 0.5}` to the CSS, which opacifies the >> 3D context: >> >> https://jsfiddle.net/trusktr/ymonmo70/8 >> >> We all agree that the spec (whatever it says) should be well defined so >> that it is clear what browsers should implement. I also believe that the >> legacy behavior is much more desirable for 3D programmers than is the >> flattening of objects (legacy-like behavior just needs to be clearly >> spec'd). >> >> === Possible Solution === >> >> Maybe we can improve the spec (before making breaking changes, and >> browser developers, you all roll back to "legacy" implementation ASAP) so >> that the spec can appease all three opacity styles. >> >> This could be achieved with something like a new CSS property called >> `opacity-style`, f.e. >> >> - `opacity-style: 3d` which is similar to the legacy behavior and is >> great for 3D scenes, and does not flatten anything. Opacity is multiplied >> all the way down the tree with other same-style opacities and stops at >> elements that have a different opacity-style (`flat` or `single`). >> - `opacity-style: single` which does not flatten anything and only >> applies opacity to the target element but not its children >> - `opacity-style: flat` which is like the new behavior that Chrome 53 >> just introduced, things are flattened and a new 3D context is made. I still >> fail to see how this is desirable. *Assuming we can apply an opacity >> to a 3D object to make it transparent and then having it become flat like >> paper is simply not intuitive.* >> >> The default value can be `opacity-style: single`, which I think is the >> least impacting of the three. We can then see what 3D programmers end up >> using more often (I'd like to bet that `opacity-style: flat` will be the >> least used). Or, perhaps the default for a 3D object can be `single`, and >> `flat` for non-3D objects. >> >> What are your thoughts on something like this, `opacity-style`? Because, >> as it stands, opacity in the 3D web isn't very workable now in nested >> scenes (it is much more workable with the legacy behavior). >> >> */#!/*JoePea >> >> On Thu, Sep 15, 2016 at 11:16 AM, Tab Atkins Jr. <jackalmage@gmail.com> >> wrote: >> >>> On Thu, Sep 15, 2016 at 10:02 AM, Rik Cabanier <cabanier@gmail.com> >>> wrote: >>> > On Wed, Sep 14, 2016 at 8:44 PM, /#!/JoePea <trusktr@gmail.com> wrote: >>> >> Here's an example using Famous Engine ( >>> http://github.com/famous/engine): >>> >> >>> >> First, with opacity at the default value of 1.0, the "Famous Code" >>> logo >>> >> moves back and forth and rotates: >>> >> http://jsfiddle.net/trusktr/spauv8fs/5 >>> >> >>> >> With opacity reduced, it breaks in Chrome 53: >>> >> http://jsfiddle.net/trusktr/spauv8fs/6 >>> >> >>> >> Famous Engine has the ability to mix WebGL with DOM, and this includes >>> >> opacity. This new behavior causes the DOM elements not to move in 3D >>> space >>> >> the WebGL meshes. >>> >> >>> >> First, here's a demo, with opacity at 1.0: >>> >> http://jsfiddle.net/trusktr/spauv8fs/7 >>> >> >>> >> The, with opacity at 0.7: >>> >> http://jsfiddle.net/trusktr/spauv8fs/8 >>> >> >>> >> What you are supposed to see is a DOM element and a WebGL Mesh that >>> both >>> >> seem to intersect with the pink DOM-based background (the >>> implementation is >>> >> not perfect yet...). In the second fiddle (spauv8fs/8) the "Famous >>> Code" >>> >> logo appears not to move any more while the WebGL mesh continues to >>> move. >>> >> >>> >> There is a bug in the WebGL renderer which I believe may be due to >>> changes >>> >> in WebGL, but the WebGL part of those examples is supposed to be >>> transparent >>> >> as well. >>> >> >>> >> I myself am working on a new implementation of DOM + WebGL, and it >>> allows >>> >> application of opacity. This change in Chrome 53 completely breaks >>> how that >>> >> is supposed to work. I don't have an online demo yet... >>> >> >>> >> I would say let's definitely consider undoing the changes to the spec >>> so >>> >> that flattening does not happen when applying an opacity to 3D DOM >>> elements. >>> >> The reasoning is not just to prevent breaking apps, but because the >>> new >>> >> behavior simply doesn't make sense as far as 3D goes. >>> > >>> > >>> > I don't understand how you come to that conclusion. >>> > The new behavior seems more logical since it applies the opacity to >>> element >>> > that has the property applied. The old implementation distributed the >>> value >>> > to its children which is counter to any other CSS value. >>> > Are you proposing that we also do this for filters, blending, backdrop >>> > blurring and other effects, or is opacity special in some way, >>> > >>> > As Simon stated, if you want the old behavior, just add a selector to >>> your >>> > opacity parameter so it's applied to the children. >>> >>> Yes. This is not a spec bug, it's a natural and unavoidable >>> consequence of doing a "group effect", which opacity, filters, and a >>> few other effects are. These types of effects require the group to be >>> rendered as a unit, then have the effect applied; in 3d space, this >>> has the effect of flattening them. (If you didn't flatten, then other >>> items could get between the individual pieces in 3d order, and there's >>> no consistent or sensible way to render that. This is identical to how >>> z-index is "flattened" by opacity and other group effects, so you >>> can't sandwich elements elsewhere in the page between the elements in >>> the group.) >>> >>> If you want to sandwich things, you need to push the effect further >>> down into the leaves, so it doesn't group as many things together. >>> This lets you do more re-ordering, but has a different visual effect - >>> if one item occludes another in a group, when they're made transparent >>> they still occlude; if they're made individually transparent, you'll >>> be able to see the second item behind the first. Similar differences >>> exist for other group effects - if you're doing a gaussian blur, >>> blurring two boxes as a group can look quite different than blurring >>> them individually. >>> >>> As Simon said, Chrome 52 and earlier Safari are simply buggy and not >>> "grouping" things correctly; they're instead automatically pushing the >>> opacity down further toward the leaves when 3d is involved. If you >>> want the same effect, just do so manually, as Rik recommends. >>> >>> (We had an almost identical request in the SVG Working Group a few >>> days ago. I posted >>> https://github.com/w3c/svgwg/issues/264#issuecomment-246750601 as an >>> extended explanation of what's happening.) >>> >>> ~TJ >>> >> >>
Received on Tuesday, 20 September 2016 07:18:05 UTC