Issues with opacity and 3D Tiles
What happened?
In our application we have an opacity-slider that can be used to see what's below the terrain. It will affect the globe and some 3D Tiles-tilesets added to the scene. For 3D Tiles-tilesets it looks like the only way to change opacity is with setStyle, modifying the alpha-value similar to this:
tileset.style = new Cesium.Cesium3DTileStyle({
color: {
"conditions": [[ "true", `rgba(255, 255, 255, ${opacity})` ]]
}
});
This works fine for basically all tilesets, but we've noticed that if a tileset contain glTF-models with alphaMode MASK, the models disappears completely when the alpha-value goes below the alphaCutOff-value.
For example, if the alphaCutOff is set to 0.5, it looks like this with opacity 0.50:
Changing the opacity to 0.49 causes it to disappear:
I've created a tileset with random alphaCutOffs, which shows the problem even more:
What we expect to happen is that the tileset should be visible all they way down to 0 where it will become fully transparent. I assume that the color-value in setStyle is applied to the material of the model, which is why it's affected by its alphaMode.
In the provided Sandcastle-example I also included a tileset with alphaMode BLEND, which for some reason is transparent even at opacity 1 (this seems to be the same problem reported in https://github.com/CesiumGS/cesium/issues/12909):
It's not urgent to figure this out, but it would be interesting to know if we're doing something wrong or if this is a bug or intended behavior.
Reproduction steps
- Add a 3D Tiles-tileset that has glTF-models with alphaMode MASK.
- Change opacity using setStyle.
- The model disappears when the alpha-value is lower than the value for alphaCutOff.
Sandcastle example
https://sandcastle.cesium.com/#c=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
Environment
Browser: Google Chrome 142.0.7444.134 CesiumJS Version: 1.135.0 Operating System: Fedora Linux 42
Hi @mborjesson-bentley, can you clarify what the issue is here? From my understanding, what you describe is the expected behavior for the glTF alphaCutoff property.
If you want to view these models with a lower opacity, then they will need a lower value for alphaCutoff. Or they could use a different alphaMode.
That was also my first thought, and I considered to point to https://github.com/KhronosGroup/glTF-Sample-Assets/tree/main/Models/AlphaBlendModeTest showing this visually. But I assume that the expectation was that it should be possible to set the opacity independently of the blend mode.
I think that there is no straightforward, "runtime" solution for that - the behavior of properly combining the blend mode and the cutoff is "baked" pretty deeply into the rendering process. The first workaround would then be to just set the alpha mode to BLEND, but...
In the provided Sandcastle-example I also included a tileset with alphaMode BLEND, which for some reason is transparent even at opacity 1
... there seems to be some matryoshka of issues.
Probably unrelated, but ... somewhat important:
I wanted to look at some of the GLBs in isolation, and downloaded some from the "Blend" tileset (for example, 69dd6dfb-f925-42bc-a22e-3c963f62c05d.glb ). The glTFs are invalid, due to a wrong accessor byte offset.
They are rendered by common glTF viewers, but none of them renders them correctly. The effect is... hard to describe - it looks like some winding order issue, but I'm a bit stumped what might cause this:
Additionally, the glTFs contain some large translation in the root note...
"translation" : [
3102908.846534217,
1010081.6407450675,
5461808.939364055
]
Yes, that's the geo-placement. But that should preferably not be stored in the glTF. (Somewhat related to https://github.com/CesiumGS/3d-tiles/issues/803 ). Here's how BabylonJS is rendering that:
(Note that "wiggling" - in addition to whatever the ... is happening with the texture there...)
So... the glTFs say
"generator" : "A3XtoGltf 1.0",
That tool seems to have some issues.
Thanks for your feedback!
@jjhembd Sorry, I should have clarified that the 3D Tiles-tilesets could be provided by our users. So, if they add their own tilesets with alphaMode in our application and then uses the opacity-slider they could be confused to why it's not working properly. So, as @javagl mentioned we'd like the opacity-slider to be independent from the alphaMode the models have.
However, the issues with alphaMode is something we've so far only noticed on tilesets we've created ourselves. So there could be an issue with how we create our glTFs.
@javagl I agree that the issues you found are probably unrelated, but I'll try to fix them and we'll see if that affects the blending.
However, not storing the geo-placement in the translation of the root node, I haven't checked the link you provided but isn't that how it's supposed to be according to the 3D Tiles 1.1-reference card?
The root node translation is the only (reasonable) way to store something like the RTC_CENTER translation (i.e. the "geolocation") within glTF. So when you have a B3DM file with RTC_CENTER, and want to convert this into a glTF, then this translation can only be stored as a node translation.
(This is also done in the automatic B3DM-to-glTF migration of the 3d-tiles-tools. As you can see in the BabylonJS example, some renderers may still struggle with that. One could play the 'blame game' and say that the renderer should be fixed, but I'll skip some further considerations here for now...)
In contrast to that, when a tool is supposed to produce a geolocated tileset, then it's preferable to store the geolocation as the tile.transform (and ideally, only of the root tile). This allows the glTF to be in its canonical form: At the origin, in its standard (y-up) orientation. The glTF itself then becomes some sort of a building block (pun somewhat intended...) that can trivially be placed at different positions on the globe, without modifying the glTF itself. (Again, skipping some details that already are discussed in the linked issue about "geolocation").
Now, all that is unrelated to the opacity issue.
There could be workarounds for that, varying wildly in "how hacky they are" and "how likely they would work". One of the "less hacky" approaches could be a custom shader. Maybe it's possible to define a custom shader that largely does the default rendering, and only consist of a small special treatment for the opacity/masking. But that's a wild guess for now.
A quick shot of using
function updateStyle() {
console.log("using " + opacity);
const customShader = new Cesium.CustomShader({
translucencyMode: Cesium.CustomShaderTranslucencyMode.TRANSLUCENT,
fragmentShaderText: `
void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material)
{
material.alpha = float(${opacity});
}
`,
});
tileset.customShader = customShader;
}
did not resolve it, and there doesn't seem to be a way to override the discard that happens depending on the alphaCutoff. (Maybe a resolution of https://github.com/CesiumGS/cesium/issues/12909 could help here, but that remains to be sorted out...)
My initial impression is that we should prioritize #12909 first. That issue points to something wrong (or at least unusual) with the way we are handling certain blend functions. Until the blend function is fixed, workarounds or fixes for this issue will be difficult to test.