Already discussed a bit about it on #13889
Currently, we are letting depthWrite: true
for every material that is being loaded from GLTFLoader, even when the material is alphaTest: BLEND
.
And glTF spec does not specify how we must set our depth write, even in non-normative sections, since the use of glTF is not restricted to the traditional realtime rasterizer.
It just says that we should try to make it look proper in as many situations as possible.
See: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0/#alpha-coverage
I think we should follow other "majority" implementations for this situation. (uhhh is this good idea?)
Note that it's pretty easy to change the behavior, just adding a line to GLTFLoader would work I think.
Currently, we are letting depthWrite: true for every material that is being loaded from GLTFLoader.
I think we came to the conclusion that https://github.com/mrdoob/three.js/issues/13889 was a modeling issue. Can you give other examples of models that require depthWrite: true
? My impression is that without it, we handle transparency correctly roughly as often as babylonjs, although either may succeed and fail in different situations.
And glTF spec does not specify how we must set our depth write, even in non-normative sections, since the use of glTF is not restricted to the traditional realtime rasterizer.
glTF files are meant to be renderable by realtime rasterizers, but even with that, I'm not sure whether it's true that a majority of implementations set depthWrite: false
for models with the "BLEND" alpha mode.
I'm OK with considering a change here, but (1) I don't know whether depthWrite: false
is the right change, as opposed to (for example) a different sorting algorithm, and (2) if there is a change I don't think it should be in GLTFLoader alone. The glTF format does not specify depthWrite for alpha transparency because we don't think there's a single correct/consensus answer. GLTFLoader uses three.js defaults to be consistent with user expectations, so if we change anything here, it should probably be the three.js defaults – there's nothing particularly different about alpha transparency in glTF vs FBX, the same limitations apply.
Yes that is pretty expected and reasonable answer, thank you @donmccurdy -san!
I think I need more examples of actual model and implementations.
Our current implementation that let end developers to decide whether or not use depth write for any materials (using .depthWrite
) is more flexible, but make it consistent over the entire Three.js as BabylonJS does also sounds good, I can't judge about it, we need more opinion imo.
We've essentially run into this issue and I think we may have a very specific example. We have a semi transparent material under a mostly transparent material and it displays fairly well in babylon, but in three.js we have two scenarios:
Here's the glb of the model we're testing (we can provide the original Blend file if anyone wants it).
HumanEye-V2(concept).zip
For us it would be preferable if the display was like babylon by default - as the babylon version is very close to what we're looking for and it seems to have a high[er] compatibility with the Blender (2.81) glTF exporter. For others this may of course not be the case, but I feel like with so much effort being put into the Blender exporter by members of the Khronos Group(♥) it may be a better reference.?
If there's anything we can do to help with this issue please let me know.
@Kagetsuki the problem visible in your third image comes from setting depthWrite=false
on _all_ materials. If you set the option only on the transparent materials, you'll get a reasonable result.
@FMS-Cat Okay, I think I agree at this point. Let's set depthWrite=false
for transparent materials in GLTFLoader. Opened https://github.com/mrdoob/three.js/pull/18235.
@donmccurdy That is correct. Thanks for the clarification and thanks for your continued work!
Thanks for the examples and discussion, @FMS-Cat and @Kagetsuki!
Thank you @donmccurdy .
Ohhhh I didn't notice to this! Thank you ❤️
FTW, this change broke stuff. So while it may have worked for the example above it is not clear it's the correct thing to do?
I didn't search that hard but some scenes that broke (testing here)
https://sketchfab.com/models/a1d315908e9f45e5a3bc618bdfd2e7ee
https://sketchfab.com/3d-models/fantasy-sea-keep-daa54937ce844ed390101fa9318843ba ?
https://sketchfab.com/3d-models/sweet-tree-b8e30834ed2e4fd3a12fa24075bbc914
https://sketchfab.com/3d-models/tree-f0b457a918c046a0b9508ba86afe899b
https://sketchfab.com/3d-models/pink-rock-garden-f2f4ddd3657542c8a9fd86dcd7a1699c
I don't know how many others might break. It's really hard to find scenes that I have permission to download that have any kind of transparency at all to test with.
@greggman Any chance you can share screenshots?
Checking the first three examples, they are all cases where the material has enabled transparency for objects with 100% opacity. Unfortunately that seems to be pretty common on Sketchfab; I'd be curious if we can ask them to fix that in their generated glTF models.
Maybe you have different experience. In games I've rarely worked on a project that used depthWrite = false except for particles effects. It's extremely common to enable gl.BLEND for things like leaves and grass and use an alpha test discard and the depth test has to be on for it work. I'm sure there are a ton more scenes that will break where in three.js terms it needs to be (depthWrite = true, transparency = true, alphaTest = > 0) but unfortunately most of the scenes that would show this are not downloadable from sketchfab
I think all of these models would be better served by transparent = false
than transparent = true
. Artists can't just enable .transparent=true
on an entire opaque model, that will cause other kinds of problems, including overdraw at least.
The glTF format gives three alpha options:
a) alphaMode=BLEND: disable alpha test, enable alpha blend
b) alphaMode=MASK: enable alpha test, disable alpha blend
c) alphaMode=OPAQUE: disable alpha test, disable alpha blend
glTF does not specify when depthWrite should be enabled/disabled, but (with this change) we apply it only to the BLEND case by default. If these models were using the mask mode, which I think they should be, then depthWrite would not be disabled.
All that said, yes, I realize that transparency sometimes requires depthWrite=true, and in other cases requires depthWrite=false. Whichever default we choose, some things will be broken. https://github.com/mrdoob/three.js/pull/18235 lists other cases that were _fixed_ by the change. I think those cases are more compelling: some of those models were designed as well as they could be, and were still broken, whereas these ones generated by Sketchfab are unfortunately not using particularly good material settings.
I realize things will break either way. In my experience I expect the new way to break things far more often than visa-versa just given that I've all the games I've worked and having never turned off depth testing except for particles. But, I guess we'd have to find more scenes find out if the there is an advantage to defaulting to one way or the other. It's possible it's 50/50. It's also possible it's 90/10 one way or the other.
For comparison (details in https://github.com/mrdoob/three.js/pull/18235) this behavior appears to be recommended by Unity's docs, and enabled by default in Unreal Engine and BabylonJS. Probably there's more of a grey area for models that need both alpha test and alpha blend, but these models don't enable alpha test. 😕
Most helpful comment
@Kagetsuki the problem visible in your third image comes from setting
depthWrite=false
on _all_ materials. If you set the option only on the transparent materials, you'll get a reasonable result.@FMS-Cat Okay, I think I agree at this point. Let's set
depthWrite=false
for transparent materials in GLTFLoader. Opened https://github.com/mrdoob/three.js/pull/18235.