-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Description
Description:
- A-Frame Version: 1.4.2
- Platform / Device: All
- Reproducible Code Snippet or URL: None
I've been doing a deep dive into A-Frame / Three.js sortObjects, prompted by some difficulties I had getting a "hider material" to work for a Mixed Reality scene I was working on.
A-Frame sortObjects is described here as follows:
Sorting is used to attempt to properly render objects that have some degree of transparency. Due to various limitations, proper transparency often requires some amount of careful setup. By default, objects are not sorted, and the order of elements in the DOM determines order of rendering. Re-ordering DOM elements provides one way of forcing a consistent behavior, whereas use of renderer="sortObjects: true" may cause unwanted changes as the camera moves.
However this description fails to mention some important details about how the THREE.js sortObjects option actually works.
When sortObjects
is enabled, sorting of objets happens according to the following logic (see code here)
- 1st factor is any
renderOrder
value set on any Group the Object3D is a member of. - 2nd factor is any
renderOrder
value set on the Object3D itself - 3rd factor is the id of the Object3D's material (this is done for performance reasons - see this checkin)
- 4th factor (only if ordering can't be decided by any of the above) is z-distance of the object from the camera (the object's center, of course, which may or may not be useful - e.g it's very much not useful for a sky...)
The A-Frame sortObjects option + docs were added under #3424, following discussion under #666.
#666 includes various reports of the render order changing as the camera moves around the scene (e.g. this) - which explains the warning about sortOrder that was added to the docs.
However this is only true for objects that use the same material. For obects using different materials, sort order is determined by material id. That's been true since THREE.js r69.
So in fact, enabling sortObjects enables a bunch of different things, not just the z-distance sort mentioned in the docs:
- The ability to control sort order directly using Object3D.renderOrder
- A performance optimization to render objects in material order (comments in the THREE.js checkin suggest this could be pretty significant)
- z-distance from camera
Ideally, it would be great to be able to control enabling / disabling of each of these individually. THREE.js doesn't offer a native way to do that, but it does allow specification of a custom sort function, which could be used to do a pre-render sort that can be configurable using properties on the renderer
component.
In terms of default settings, I agree with the discussion in #666 that says that stable ordering is preferable. But of the above, both 1 & 2 are stable - only 3 results in position-based instability.
So I'd propose that by default:
- Object3D
renderOrder
settings should be considered - Material sorting (which may boost performance) should be enabled
- z-distance from camera should be disabled.
And then there should be options to:
- enable z-distance sorting (existing function, which we can retain)
- disable material sorting (particularly useful for the case where z-distance sorting should take priority)
- and maybe an option to disable sorting completely - helps ensure back compatibility, and may be useful in cases where the sorting itself causes a performance hit.
I'm happy to do a PR on this, but keen to gather input first on what others might want / need here.
For my original use case (a "hider material") I need to ensure this is rendered before all other objects. There are several ways to achieve this, but the simplest is probably to use a renderOrder
of -1 on the object. I can do that with current A-Frame, as long as I enable renderer="sortObjects:true". That does have the side effect of also enabling z-distance sorting for same-material objects, which I don't actually need, but doesn't seem like it will cause too many problems...