You just embed a SubScene within a 3D scene, or a SubScene3D within a 2D scene, 
etc. So you can easily nest one rendering mode within the other -- where 
"easily" means, that each SubScene / SubScene3D has the semantics of "draw into 
a texture and composite into the parent scene".

Richard

On Jul 18, 2013, at 2:20 PM, Daniel Zwolenski <zon...@gmail.com> wrote:

> Does it need to be a separate class, can it not just be a setting on scene 
> like setRenderMode(3d)? Just thinking you may want a base 3d view for example 
> but then show 2d screens at times for settings, etc, so you could switch it 
> on and off. 
> 
> I assume there's no way to do it pane by pane, so the docked components of a 
> BorderPane are 2d optimized but the center is 3d? Or is that what SubScene3d 
> is for (not real clear how this would be used)?
> 
> 
> 
> On 19/07/2013, at 6:58 AM, Richard Bair <richard.b...@oracle.com> wrote:
> 
>> While working on RT-5534, we found a large number of odd cases when mixing 
>> 2D and 3D. Some of these we talked about previously, some either we hadn't 
>> or, at least, they hadn't occurred to me. With 8 we are defining a lot of 
>> new API for 3D, and we need to make sure that we've very clearly defined how 
>> 2D and 3D nodes interact with each other, or developers will run into 
>> problems frequently and fire off angry emails about it :-)
>> 
>> Fundamentally, 2D and 3D rendering are completely different. There are 
>> differences in how opacity is understood and applied. 2D graphics frequently 
>> use clips, whereas 3D does not (other than clipping the view frustum or 
>> other such environmental clipping). 2D uses things like filter effects (drop 
>> shadow, etc) that is based on pixel bashing, whereas 3D uses light sources, 
>> shaders, or other such techniques to cast shadows, implement fog, dynamic 
>> lighting, etc. In short, 2D is fundamentally about drawing pixels and 
>> blending using the Painters Algorithm, whereas 3D is about geometry and 
>> shaders and (usually) a depth buffer. Of course 2D is almost always defined 
>> as 0,0 in the top left, positive x to the right and positive y down, whereas 
>> 3D is almost always 0,0 in the center, positive x to the right and positive 
>> y up. But that's just a transform away, so I don't consider that a 
>> *fundamental* difference.
>> 
>> There are many ways in which these differences manifest themselves when 
>> mixing content between the two graphics.
>> 
>> http://fxexperience.com/?attachment_id=2853
>> 
>> This picture shows 4 circles and a rectangle. They are setup such that all 5 
>> shapes are in the same group [c1, c2, r, c3, c4]. However depthBuffer is 
>> turned on (as well as perspective camera) so that I can use Z to position 
>> the shapes instead of using the painter's algorithm. You will notice that 
>> the first two circles (green and magenta) have a "dirty edge", whereas the 
>> last two circles (blue and orange) look beautiful. Note that even though 
>> there is a depth buffer involved, we're still issuing these shapes to the 
>> card in a specific order.
>> 
>> For those not familiar with the depth buffer, the way it works is very 
>> simple. When you draw something, in addition to recording the RGBA values 
>> for each pixel, you also write to an array (one element per pixel) with a 
>> value for every non-transparent pixel that was touched. In this way, if you 
>> draw something on top, and then draw something beneath it, the graphics card 
>> can check the depth buffer to determine whether it should skip a pixel. So 
>> in the image, we draw green for the green circle, and then later draw the 
>> black for the rectangle, and because some pixels were already drawn to by 
>> the green circle, the card knows not to overwrite those with the black pixel 
>> in the background rectangle.
>> 
>> The depth buffer is just a technique used to ensure that content rendered 
>> respects Z for the order in which things appear composited in the final 
>> frame. (You can individually cause nodes to ignore this requirement by 
>> setting depthTest to false for a specific node or branch of the scene graph, 
>> in which case they won't check with the depth buffer prior to drawing their 
>> pixels, they'll just overwrite anything that was drawn previously, even if 
>> it has a Z value that would put it behind the thing it is drawing over!).
>> 
>> For the sake of this discussion "3D World" means "depth buffer enabled" and 
>> assumes perspective camera is enabled, and 2D means "2.5D capable" by which 
>> I mean perspective camera but no depth buffer.
>> 
>> So:
>> 
>>   1) Draw the first green circle. This is done by rendering the circle into 
>> an image with nice anti-aliasing, and then rotating that image
>>            and blend with anything already in the frame buffer
>>   2) Draw the magenta circle. Same as with green -- draw into an image with 
>> nice AA and rotate and blend
>>   3) Draw the rectangle. Because the depth buffer is turned on, for each 
>> pixel of the green & magenta circles, we *don't* render
>>        any black. Because the AA edge has been touched with some 
>> transparency, it was written to the depth buffer, and we will not
>>        draw any black there. Hence the dirty fringe! No blending!
>>   4) Draw the blue circle into an image with nice AA, rotate, and blend. AA 
>> edges are blended nicely with black background!
>>   5) Draw the orange circle into an image with nice AA, rotate, and blend. 
>> AA edges are blended nicely with black background!
>> 
>> Transparency in 3D is a problem, and on ES2 it is particularly difficult to 
>> solve. As such, it is usually up to the application to sort their scene 
>> graph nodes in such a way as to end up with something sensible. The 
>> difficulty in this case is that when you use any 2D node and mix it in with 
>> 3D nodes (or even other 2D nodes but with the depth buffer turned on) then 
>> you end up in a situation where the nice AA ends up being a liability rather 
>> than an asset -- unless you have manually sorted all your nodes in such a 
>> way as to avoid the transparency problems.
>> 
>> There are other problems. Suppose you create a scene where you have 3 
>> Rectangles, with Z values:
>> 
>> r1.setTranslateZ(10);
>> r2.setTranslateZ(20);
>> r3.setTranslateZ(30);
>> 
>> g1 = [r2, r3]
>> g2 = [g1, r1]
>> 
>> If you have the depth buffer turned on, then you would expect that r1 is 
>> drawn on top of r2, which is drawn on top of r3, regardless of the presence 
>> of groups, because the order in which things are rendered is independent of 
>> the order in which they appear, since we're using a depth buffer, so the Z 
>> values are the only thing that really dictates the order in which things 
>> appear.
>> 
>> Now, something weird is going to happen if I either apply an effect, clip, 
>> blendMode, or turn node caching on to g1. Because all 4 of these properties 
>> are 2D properties that by their nature result in "flattening". That is, they 
>> take the scene graph they've been given and render to an intermediate image, 
>> and are then composited into the rest of the scene. In this case, since g1 
>> has no Z translation, what you would get is the combination of r2 and r3 
>> drawn on top of r1! We've flattened r2 and r3 into an image which is then 
>> rendered at Z=0, which is above r1 with z=10.
>> 
>> This behavior, although surprising, is consistent and correct. But it sure 
>> is surprising for those, who like me, are traditional 2D developers coming 
>> to the 3D world!
>> 
>> Then there is the new support for scene anti-aliasing (presently using 
>> multi-sampling, referred to as MSAA . In our 2D rendering, we always 
>> anti-alias all shapes using a special set of shaders and grayscale masks 
>> generated in software. This is a common technique and produces objectively 
>> the best AA money can buy, often with the least overhead (the cost is in 
>> generating and uploading the masks, which for most things we've optimized 
>> the heck out of, though for paths you still will run into the worst case 
>> scenarios). MSAA on the other hand, applies an algorithm against the entire 
>> scene in order to produce "automatic" AA on everything (there are many ways 
>> to do scene anti-aliasing. One way you can think of would be to draw to a 
>> buffer 4x or 8x as large as necessary, and then scale it down using bilinear 
>> scaling to 1x and put that on the screen, letting the image scaling 
>> algorithm do the work).
>> 
>> https://wiki.mozilla.org/images/4/48/Msaa_comparison.png
>> 
>> Here you can see the smoothed edges of the monster. However MSAA does take 
>> extra cycles and on resource constrained devices you may not want to do this 
>> at all. In addition, it gives you worse AA than you would get with our mask 
>> / shader approach for 2D shapes.
>> 
>> Also, opacity. In 2D rendering contexts, using opacity means "render to an 
>> image and apply the alpha blend to the entire image". This also inherently 
>> means flattening. In 3D contexts, if you put an alpha on a Group, it should 
>> mean "multiply this alpha with the alpha of each of my children 
>> individually". This would always give the wrong result in 2D, but generally 
>> the right one in 3D. And certainly better than flattening a group, which is 
>> pretty much always a problem.
>> 
>> So in summary, if you use 2D APIs in a 3D world (effect, clip, blendMode, 
>> node caching) then you get surprising results. If you use a 2D shape in a 3D 
>> world then the nice AA of 2D shapes may end up good or bad depending on the 
>> render order relative to depth. And depending on whether you use a parallel 
>> or perspective camera, using 3D shapes in a 2D world may end up quite 
>> surprising as well.
>> 
>> So what do I propose to do about this? Well, we can leave it be and just 
>> document the heck out of it. Or we can try to tease apart the scene graph 
>> into Node, Node3D, and NodeBase. Right now we're doing the former, and I've 
>> tried the latter and it makes a mess in many places. We can talk about those 
>> alternatives if you like, but to shorten (ahem) this message, I'm going to 
>> just say it doesn't work (at least, it doesn't work well and may not work at 
>> all) and leave it at that.
>> 
>> Instead I propose that we keep the integrated scene graph as we have it, but 
>> that we introduce two new classes, Scene3D and SubScene3D. These would be 
>> configured specially in two ways. First, they would default to depthTest 
>> enabled, scene antialiasing enabled, and perspective camera. Meanwhile, 
>> Scene and SubScene would be configured for 2.5D by default, such that 
>> depthTest is disabled, scene AA is disabled, and perspective camera is set. 
>> In this way, if you rotate a 2.5D shape, you get perspective as you would 
>> expect, but none of the other 3D behaviors. Scene3D and SubScene3D could 
>> also have y-up and 0,0 in the center.
>> 
>> Second, we will interpret the meaning of opacity differently depending on 
>> whether you are in a Scene / SubScene, or a Scene3D / SubScene3D. Over time 
>> we will also implement different semantics for rendering in both worlds. For 
>> example, if you put a 2D rectangle in a Scene3D / SubScene3D, we would use a 
>> quad to represent the rectangle and would not AA it at all, allowing the 
>> scene3D's anti-aliasing property to define how to handle this. Likewise, a 
>> complex path could either be tessellated or we could still use the mask + 
>> shader approach to filling it, but that we would do so with no AA (so the 
>> mask is black or white, not grayscale).
>> 
>> If you use effects, clips, or blendModes we're going to flatten in the 3D 
>> world as well. But since these are not common things to do in 3D, I find 
>> that quite acceptable. Meanwhile in 3D we'll simply ignore the cache 
>> property (since it is just a hint).
>> 
>> So the idea is that we can have different pipelines optimized for 2D or 3D 
>> rendering, and we will key-off which kind to use based on Scene / Scene3D, 
>> or SubScene / SubScene3D. Shapes will look different depending on which 
>> world they're rendered in, but that follows. All shapes (2D and 3D) will 
>> render by the same rules in the 3D realm.
>> 
>> Thoughts?
>> 
>> Richard
>> 
>> 

Reply via email to