How to render a specific 3D Tiles layer always on top of everything

Hello,
I’m working with CesiumJS and loading multiple datasets as 3D Tiles from Cesium ion.

One of my tilesets contains underground utilities (pipes, infrastructure, etc.) located below terrain level. When viewing the scene from above, the terrain tileset (for example, Google Photorealistic 3D Tiles terrain) completely occludes these utilities.

I know that historically there were a lot of requests to properly hide underground elements but, I’d like to implement exactly the opposite - visualization mode where these underground utilities remain visible even when under the terrain. Let’s call it a “wall-hack” mode, ideally with some kind of outline (silhouette, inverted hull, or similar).


Desired Behavior

When enabled:
The underground utilities tileset should always remain visible
Terrain should still render normally underneath
Only the utilities layer should ignore terrain occlusion

Conceptually, this could behave like:
Rendering the utilities layer in a separate render pass
Disabling depth testing against terrain only for that tileset
Drawing the layer as an overlay on top of the terrain


Things I’ve Tried

Globe translucency:

viewer.scene.globe.translucency.enabled = true;
viewer.scene.globe.translucency.frontFaceAlpha = 0.1;
viewer.scene.globe.translucency.frontFaceAlphaByDistance =
    new Cesium.NearFarScalar(50.0, 0.0, 100.0, 1.0);
  • Works for the globe, but does not affect terrain from 3D Tiles datasets

disableDepthTestDistance:

  • Works for billboards and labels, but not for meshes inside tilesets

Clipping planes:

  • Can hide terrain, but also clip everything else, not suitable

depthTestAgainstTerrain:

  • works for primitives only

Recreating geometry as a Primitive:
Use a custom appearance with renderState.depthTest = false
Outline as inverse hull, also with depthTest = false
Works, but becomes painful for larger, complex tilesets with thousands of objects. Also depthTest here is disabled per element (instancing multiple objects) they randomly overlap each other - exactly what depthTest does but I need something more like a depthTest for the whole layer, rather than per instance


Ideal Solution

I’d like something that allows me to:

  • Render one tileset/entity always on top

  • Keep normal depth testing inside that tileset (so pipes/objects occlude each other properly)

  • Keep terrain rendering normally underneath

  • Bonus: support outline or silhouette for the “on-top” mode


Question

Is there a supported way, or a clever hack, in CesiumJS to:

  • Render a single tileset/entity on top of everything,

  • While keeping proper depth testing inside the tileset itself?

Any tips, hacks, or API tricks for outlines/inverse hulls that also work in bigger, more dynamic scenes would be super appreciated.

Hi @marlucz, welcome to the community!

Have you tried invert classification? You can see how it works by selecting the “invert classification” option in the Classification sandcastle, and sliding the “invert color alpha” down to zero.

To clarify what is happening in that screenshot: the trees are part of a 3D Tiles surface that covers most of the screen. With the invert color alpha at zero, you are seeing through the tileset to the globe surface below. (The painted parking spaces in the background are part of the globe surface, not the tileset.)

Let me know if that doesn’t work for your use case.

I think if you want to still see the 3D Tiles surface, translucency is your best bet. Otherwise you could simply use a ClippingPlaneCollection to cut out the 3D Tiles above the utilities.

I’m not aware of a way to turn off depth testing for one tileset.

Thank you for your reply!
Yeah, classification looks quite ok but I can’t play with that and it does not give real ‘wall-hack’ as it’s still overlapped by i.e terrain when terrain is not transparent. For now the only hack that I found that follows cesium render flow is either custom shader that changes diffuse of the element and takes it out of the depth test, but this way element needs to be a solid color, or use custom geometries with the depthTest disabled through renderState

Hey @marlucz ,

With some tinkering I think I was able to achieve the desired affect however performance is limited.

This is achieved by rendering two separate viewers, a base viewer with all my tiles and globe, and an overlay viewer to render what needs to be on top. As this solution is running two cesium viewers at once, there is a bit of a performance hit, but maybe there is some room to iterate on performance here.

Here is a sand castle (With my ion token and asset ids removed, so add yours in). You’ll notice I also used Cesium.PostProcessStageLibrary.createSilhouetteStage to add a highlight/outline to the tiles to make it a bit easier to see.

I can’t say I recommend this approach because of performance, and there may be another better approach out there, but this technically does achieve what you want

Yeah, performance is definitely a concern here :sweat_smile: In my case I’m dealing with thousands of underground elements, so this approach probably won’t scale well enough. Still, thanks for the effort and the suggestions :slight_smile: if I run out of other options I might give it a try.

For now I’m trying to keep things as lightweight as possible: using primitives wherever I can, disabling depthTest in the renderState, and doing outlines with an inverted hull. It has some flaws, it does not work well enough.. but it works.

I also tried implementing the same idea in Three.js with 3d-tiles-renderer. There it was easier to experiment because I could manually call clearDepth() inside the frame loop and render specific things in a controlled order. But in this case I’m loosing all the good stuff that comes with Cesium… From what I understand, Cesium doesn’t really expose similar control over render targets or render order, unless I’m missing something?