CesiumGS / cesium

An open-source JavaScript library for world-class 3D globes and maps :earth_americas:
https://cesium.com/cesiumjs/
Apache License 2.0
12.64k stars 3.43k forks source link

There is a possibility of throw an error in a frame when continuously modifying the clipping planes and picking #11410

Open PolanZ opened 1 year ago

PolanZ commented 1 year ago

Hi, I found the clippingPlanes changed, There may be a possibility of encountering an error in a frame when the picking.

I created a sample, please see Sandcastle Example

throw error when the mouse pick the 3dtiles.

Recently, I discovered that the texture on the clipping plane was missing during debugging. This occurred because it was executed during the "Cesium3DTileset.prototype.prePassesUpdate" phase, and it may not have been executed when picking.

related #8824

ggetz commented 1 year ago

Hi @PolanZ,

I'm a bit confused why this is an issue.

I noticed you're using setInterval and re-assigning the clipping planes every millisecond. The issue goes away if you use setTimeout to only set the clipping planes once.

I'm not sure if this is anything different than https://github.com/CesiumGS/cesium/issues/8824?

PolanZ commented 1 year ago

@ggetz Because, If I need to perform both drawing and picking simultaneously, it requires constant updates of new clipping planes. This can lead to errors in certain frames.

use setInterval , It can quickly highlight the problem.

saadatali48 commented 1 year ago

Hi @PolanZ, Any luck with finding any work around for this bug? I am facing the same issue

3DGISKing commented 9 months ago

I also found this you can reproduce with this Sandcastle

ggetz commented 7 months ago

Also reported in https://github.com/CesiumGS/cesium/issues/11779

lilleyse commented 7 months ago

It seems like what's happening is the clipping collection is being created between the render pass and the pick pass, which is a problem because the clipping plane is normally initialized in the render pass (which callsprePassesUpdate). The browser must be resolving setInterval before the move event.

A workaround is to use view.scene.preUpdate instead of setInterval to ensure the correct execution order. Here's a sandcastle example.

// test loop refresh clipping planes
viewer.scene.preUpdate.addEventListener(function () {
  tileset.clippingPlanes = new Cesium.ClippingPlaneCollection({
    planes: [
      new Cesium.ClippingPlane(
        new Cesium.Cartesian3(0.0, 0.0, -1.0),
        0.0
      ),
    ],
  });
});
PolanZ commented 3 months ago

@lilleyse Hi, you can take a look at this example sandcastle,

let you zoom to refresh the 3DTiles and then switch the clipping planes, there will be throw an error.