Disable Depth Test For Polylines and Polygons

1. A concise explanation of the problem you're experiencing.

Hi! I'm looking for an equivalent to disableDepthTestDistance in https://cesiumjs.org/Cesium/Build/Documentation/PointGraphics.html for polylines and polygons. Even if the solution is less than elegant for the time being, I'll take it. Here are the current restrictions I'm working under:
-All polylines and polygons must display on top of the globe and other entities.
-Feature picking needs to still operate on these polylines and polygons.

3. Context. Why do you need to do this? We might know a better way to accomplish your goal.

Polylines and polygons are being used to draw geometry on a mesh entity. Unfortunately, that means they render partially clipped through the mesh in many places. Hovering the lines above the surface of the mesh slightly alleviates the issue in lucky scenarios (the right zoom level for the hover offset), but isn't really a sufficient solution. The desirable behavior is to always draw the illustrations to the screen on top of all other content.

Is there a way I can modify the underlying primitives to draw them on top? An official solution through the API would be great, but I realize this may be an unconventional need and I don't expect it to be a high priority for you.

To clarify: Polylines and polygons are currently added as entities in addition to the mesh.

If your polylines and polygons are clamped to ground, you could use the zIndex property to make sure the ones you need to be on top are always on top, like in this example:

That would be the straightforward approach. Otherwise, you might have to create a custom appearance and use the primitive API (See https://cesiumjs.org/tutorials/Geometry-and-Appearances/ ). RenderState is a private property on Appearance but it would allow you to control the depthTest:

https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Source/Renderer/RenderState.js#L98

You might also need to add the primitives in the right order so whatever is added last is drawn on top.

If you do end up getting this working, it would definitely be useful to post your solution here or contribute it to Cesium! I hope this helps.

1 Like

Thank you so much Omar! Modifying the RenderState was exactly what I was looking for. Unfortunately, converting all of my code to managing primitives was going to be a fairly extensive task. Instead, I came up with a way to monkey patch my desired behavior into Primitive and PolylineCollection so I could keep my work on the entity level. These won't be universal solutions, but given my specific scenario they did the trick.

// Modify polylines so that their depth test is always disabled.
var oldPolylineUpdate = Cesium.PolylineCollection.prototype.update;
Cesium.PolylineCollection.prototype.update = function(frameState) {
  var oldMorphTime = frameState.morphTime;
  frameState.morphTime = 0.0;
  oldPolylineUpdate.call(this, frameState);
  frameState.morphTime = oldMorphTime;
};

// Modify polygons (and all other primitive objects) so that their depth test is always disabled.
var oldPrimitiveUpdate = Cesium.Primitive.prototype.update;
Cesium.Primitive.prototype.update = function (frameState) {
this.appearance._renderState.depthTest.enabled = false;
  oldPrimitiveUpdate.call(this, frameState);
};

Not very pretty, but effective at least. I'm not particularly happy with the PolylineCollection trick, but I couldn't find a better way to access and modify the render states in PolylineCollection.js before createCommandLists is called. As far as I'm aware, the update call does not otherwise need access to morphTime and I haven't seen any ill effects.

3 Likes

Thanks for posting your solution! We might revisit in the future whether it makes sense to expose depth test property on polylines and polygons. I’m glad this workaround is sufficient for now.

Great solution, thanks for sharing. Our use case would really benefit if Cesium were to enable the depth test property on polylines. What would be incredible would be the ability to modify the appearance of polylines and billboards when viewed through terrain (change shade, change colour, etc)

I just stumbled on this issue which I think is relevant:

  1. Turns out there’s an easier way to monkeypatch the solution above (see hailengc’s code here https://github.com/AnalyticalGraphicsInc/cesium/issues/5333#issuecomment-413185541 )

  2. There’s actually a depthFailMaterial that would allow you to do exactly that, control how it looks when viewed through terrain.

Try it out Josh and let me know if it does what you expect it to do.

Hi Omar,

Unfortunately we are using dynamic polylines which depthFailMaterial does not support. I can see an open issue on GitHub #5333 so fingers crossed this gets implemented soon!

I actually do not understand hailengc monkeypatch solution and cannot get it to work…

Thank you for your suggestion

Cheers,

Josh

I just bumped the issue to let them know people are still asking for it.

I think if you can get the original monkeypatch in this thread working, it’s just as well of a workaround for now.

Is there away to disable the depth test to individual models? The solutions provided above only appear to be valid for non-model primitives.

Here is the solution (hack) I came up with, use at your own risk :slight_smile:

//disable depthTest for entities annoted with a depthTest property
var oldModelUpdate = Cesium.Model.prototype.update;
Cesium.Model.prototype.update = function (frameState) {
    oldModelUpdate.call(this, frameState); //call base implementation

    //this.id is the entity
    //check for depthTest property
    //if not found, or equal to true, exit
    const depthTest = this.id?.properties?._depthTest?._value;
    if (depthTest != false)
        return;

    //get the renderStates
    const renderStates = this._rendererResources?.renderStates;

    //disable depth test
    if (renderStates != null) {
        for (const property in renderStates) {
            renderStates[property].depthTest.enabled = false;
        };
    }
}

Here is another solution.

Sandcastle

const { Model, Transforms, Pass } = Cesium;

const viewer = new Cesium.Viewer("cesiumContainer", {});

viewer.scene.screenSpaceCameraController.enableCollisionDetection = false;

const height = -50;

const position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height);

const model = Model.fromGltf({
    modelMatrix: Transforms.eastNorthUpToFixedFrame(position),
    url: "../SampleData/models/CesiumAir/Cesium_Air.glb",
    opaquePass: Pass.OVERLAY
});

viewer.scene.primitives.add(model);

Promise.resolve(model.readyPromise).then((model) => {
    viewer.camera.flyToBoundingSphere(model.boundingSphere);
});

Is that still the best way to go for dynamic polylines and polygons? Could i limit it to lines?