three.js: GLTFLoader: Texture alpha should be ignored on opaque materials

In GLTFLoader we can load standard materials using StandardMaterial . However, the alpha channel of its texture doesn’t be handled properly, when renderer’s alpha is activated.

In OPAQUE or MASK material, alpha channels of texture should be negated: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#alpha-coverage

Change the material’s blend mode to ZERO-ONE (in GLTFLoader) might solve this problem?

This is how it should be (rendered in Unity):

image

Here’s how it looks like in Three.js GLTFLoader:

default

This is the source code: https://github.com/FMS-Cat/cube-gradient-alpha

Environment:

  • Three.js version: r99
  • Browser: Confirmed in Chrome, Firefox, Edge
  • OSes: Windows. Has not tested in other env
  • Hardware: Probably no requirements

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 33 (8 by maintainers)

Most upvoted comments

Better late than never™ #22424

So if a user wanted to create a cool background using custom blending, the user would assign the material to the background queue. (In particular, the user would not be forced to place his custom-blended material into the transparent queue, where the material can never be rendered “first”.)

maybe we’re on the same page enough to discuss fixes rather than terms.

Let’s assume we are. 😃

AdditiveBlending works regardless of the render order as long as the depth buffer is not causing fragments to be discarded.

I don’t understand, sorry. I see the commutative part when operations are the same, but the following are clearly different:

  • ( 0 × 5 ) + 2
  • 0 × ( 5 + 2 )

THREE.TransparentQueue // Anything alpha-blended goes here

Ok, if we consider additive blending a type of alpha blending, which should be put into a transparent queue if there is one, then maybe we’re on the same page enough to discuss fixes rather than terms. 😅

I find the render queue concept helpful, yes.

I am taking .transparent to mean, “not opaque.” Occluded fragments affect the final result, and from that perspective I do not consider the objects in your example above to be opaque. The fact that depthWrite must be disabled, alone, is indicative.

Definitely supporting this argumentation 👍

I vote the reimplement #18631 and revert #14171 for R115. I actually doubt somebody will complain if the mechanics from #14171 are removed.

I am taking .transparent to mean, “not opaque.” Occluded fragments affect the final result, and from that perspective I do not consider the objects in your example above to be opaque. The fact that depthWrite must be disabled, alone, is indicative.

That’s certainly not the only meaning a user might reasonably associate with the word transparent: light passing through a glass-like material is probably a very common association, and certainly the example above has nothing to do with glass-like transparency.

However, I think the effects of the .transparent setting — sorting differently and (if we can manage it) defaulting to .depthWrite=false have more to do with the “not opaque” meaning than with physical transparency.

I do feel that .alphaMode would provide a much clearer conceptual model for all of that, and flexibility for features that don’t fit as well into this model. For example, “alpha hash” mode is arguably opaque, and should be sorted like opaque objects, but can certainly be used to mimic cheap physical transparency. Whether it’s worth a breaking change, I’m not sure.

Continuing the discussion from https://github.com/mrdoob/three.js/pull/18631 here:

We don’t know of cases where users need to use .transparent=false and .blending=AdditiveBlending both, but they certainly could, and we don’t want to silently break those applications. I believe the most pragmatic fix would be to resubmit the previous changes in r115, with the addition of a warning when both of the options above are set:

THREE.WebGLRenderer: Setting .transparent=true is required when using non-opaque .blending modes.

Rationale in https://github.com/mrdoob/three.js/pull/18631#discussion_r385506836. If that change goes through and does not cause any complaints, then perhaps https://github.com/mrdoob/three.js/pull/14171 should be reverted too.

There is a more complex suggestion also in that thread, of replacing .transparent with an .alphaMode-like property. I think that idea shows some promise but I’m not necessarily volunteering to do all that in r115. 😇

and the fragment is blended using normal alpha blending.

If transparent=true, that’s a desired threejs behavior. If transparent=false, I think writing alpha to gl_FragColor is a side effect in threejs that we could change safely. glTF models never specify both alpha blending and alpha clip/test.

still sounds workaroundy but what mrdoob said

I think we could solve this by setting texture.format = THREE.RGBFormat in GLTFLoader, when the material specifies a blendMode=OPAQUE. If the texture is used by other materials with different blend modes, that would mean cloning it — and at least one duplicate GPU upload. Probably better than a new shader permutation, though?

You mean, we should treat the alpha as a “fourth component of the output” even if it’s fully “OPAQUE”? That sounds pretty weird for me… I thought “rendered output is fully opaque” means output alpha is always 1.0 .

In your sample source repository, which of the two models are you talking about?

cube-gradient-alpha.glb , has an alpha channel on its material.pbrMetallicRoughness.baseColorTexture but its material.alphaMode is OPAQUE . (Yes I’m talking about weird case)

Bleh I might have picked wrong words, negated -> ignored (I have a disability to my English)