Model Silhouette is wrong when silhouette alpha is not 1
What happened?
Reported on the forum: https://community.cesium.com/t/behavior-of-entity-model-silhouette-color-options-with-alpha/37082
It seems this may have started happening in version 1.121
https://github.com/user-attachments/assets/d2df426e-ec4e-4637-98e3-4e0ef25d2a9c
It looks like something about the model is not getting translated correctly when it's rotated while processing the silhouette color. Could this be related to https://github.com/CesiumGS/cesium/issues/11067?
Reproduction steps
- Load the 3D Models Coloring sandcastle
- Set the model color to white to avoid confusing the colors
- Change the Silhouette alpha to anything lower than 1
Sandcastle example
No response
Environment
Browser: Chrome CesiumJS Version: 1.124 Operating System: Linux
Given the post processing depth buffer ties, perhaps https://github.com/CesiumGS/cesium/issues/7705 is related?
Hello. I am the original author of this issue's community post. I would like to share a few discoveries I've made since posting.
1. Disabling MSAA temporarily resolves this issue. Sandcastle
2. When MSAA is enabled, it appears that two silhouette rendering commands are executed in different render passes (OPAQUE and TRANSLUCENT).
Pass 1: Silhouette Model Command [ModelDrawCommand.js]
function deriveSilhouetteModelCommand(command, model) {
const stencilReference = model._silhouetteId % 255;
const silhouetteModelCommand = DrawCommand.shallowClone(command);
const renderState = clone(command.renderState, true);
renderState.stencilTest = {
enabled: true,
frontFunction: WebGLConstants.ALWAYS,
reference: stencilReference,
...
};
// ...
}
Pass 2: Silhouette Color Command [ModelDrawCommand.js]
function deriveSilhouetteColorCommand(command, model) {
const stencilReference = model._silhouetteId % 255;
const silhouetteColorCommand = DrawCommand.shallowClone(command);
const renderState = clone(command.renderState, true);
const silhouetteTranslucent =
command.pass === Pass.TRANSLUCENT || model.silhouetteColor.alpha < 1.0;
if (silhouetteTranslucent) {
silhouetteColorCommand.pass = Pass.TRANSLUCENT;
renderState.depthMask = false;
renderState.blending = BlendingState.ALPHA_BLEND;
}
renderState.stencilTest = {
enabled: true,
frontFunction: WebGLConstants.NOTEQUAL,
reference: stencilReference,
...
};
}
3. Issue guessing
When alpha = 1.0 (Working Correctly):
silhouetteModelCommand.pass=Pass.OPAQUEsilhouetteColorCommand.pass=Pass.OPAQUE(no reassignment)- Both commands execute in the same pass
- Stencil buffer state is consistent within the pass
- Silhouette renders correctly
When alpha < 1.0 (Broken):
-
silhouetteModelCommand.pass=Pass.OPAQUE- Writes stencil to MSAA multisampled renderbuffer
- Stencil reference (e.g., 5) written where model is visible
-
silhouetteColorCommand.pass=Pass.TRANSLUCENT- Reads from MSAA stencil buffer
- Tests
stencil != 5(NOTEQUAL) - In MSAA environment with commands in different passes, stencil state is not properly preserved
- Stencil appears to be 0 or corrupted
- NOTEQUAL test passes everywhere (0 != 5 is true)
- Result: Silhouette renders over entire model, not just outline
I considered save texture (maybe blitStencil() do that?) after the OPAQUE pass to share it with the TRANSLUCENT pass, but I'm still unfamiliar with Graphics, so i haven't tested yet.
The video from the first post here looks different from what I've seen. But the screenshot in the linked forum post looks more like what I reported in https://github.com/CesiumGS/cesium/issues/13074 , so this is now closed as a duplicate, assuming that it will be resolved with whatever change will fix this one as well.