Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for concave /convex clipping planes + holes in CesiumJS #8751

Closed
Samulus opened this issue Apr 13, 2020 · 66 comments · Fixed by #11750
Closed

Add support for concave /convex clipping planes + holes in CesiumJS #8751

Samulus opened this issue Apr 13, 2020 · 66 comments · Fixed by #11750

Comments

@Samulus
Copy link
Contributor

Samulus commented Apr 13, 2020

The user should be able to define a 2D clipping polygon with zero or more holes.

We should support:

  • Multiple clipping planes
  • Multiple holes in each clipping plane
  • Overlapping holes

We should disallow:

  • Self-intersecting polygons / holes
  • Holes that extend beyond the region of their parent clipping plane.
@OmarShehata
Copy link
Contributor

@NotEmptyWKL
Copy link

I also need support for concave polygon

@OmarShehata
Copy link
Contributor

@NotEmptyWKL can you describe your use case?

@NotEmptyWKL
Copy link

@NotEmptyWKL您可以描述您的用例吗?
After supporting concave polygon clipping, I can cut the earth into the scope of a country without showing the whole earth

@hpinkos
Copy link
Contributor

hpinkos commented Dec 23, 2020

Another request for multiple disjoint clipping polygons came from https://community.cesium.com/t/multiple-clippingplanes/11809

@zhwy
Copy link

zhwy commented Feb 6, 2021

I urgently need multiple clipping on the globe!. Here is a simple effect I achieved.
image

These files are modified: GlobeSurfaceShaderSet.js, GlobeSurfaceTileProvieder.js, Globe.js, GlobeVS.glsl.
New files are created: MultiClippingPlaneCollection.js, getMultiClippingFunction.js.

You can now clip multiple polygons on the globe by passing an instance of MultiClippingPlaneCollection which manages a list of ClippingPlaneCollection to the multiClippingPlanes property new added to the globe.

For example:

    var clippingPlanecollection1 = new Cesium.ClippingPlaneCollection({
      planes: [
        new Cesium.ClippingPlane(new Cesium.Cartesian3(1.0, 0.0, 0.0), 0.0),
        new Cesium.ClippingPlane(
          new Cesium.Cartesian3(-1.0, 0.0, 0.0),
          -500.0
        ),
        new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 1.0, 0.0), -15.0),
        new Cesium.ClippingPlane(
          new Cesium.Cartesian3(0.0, -1.0, 0.0),
          -15.0
        ),
      ],
    });
    var clippingPlanecollection2 = new Cesium.ClippingPlaneCollection({
      planes: [
        new Cesium.ClippingPlane(new Cesium.Cartesian3(1.0, 0.0, 0.0), 1000),
        new Cesium.ClippingPlane(
          new Cesium.Cartesian3(-1.0, 0.0, 0.0),
          -2000.0
        ),
        new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 1.0, 0.0), -15.0),
        new Cesium.ClippingPlane(
          new Cesium.Cartesian3(0.0, -1.0, 0.0),
          -15.0
        ),
      ],
    });

    globe.multiClippingPlanes = new Cesium.MultiClippingPlaneCollection({
      collections: [clippingPlanecollection1, clippingPlanecollection2],
      modelMatrix: entity.computeModelMatrix(Cesium.JulianDate.now()),
      edgeWidth: 1,
      edgeColor: Cesium.Color.WHITE,
    });

The key point is to rewrite the orginal getClippingFunction.js to getMultiClippingFunction.js to make the fragment shader able to handle multiple clipping plane collections. The shader also needs to know the length of every collection so it can get the correct clipping plane.

This is only a temporary solution on multi-clipping on terrain, more problems to be solved:

  1. Different styles and model matrix on each ClippingPlaneCollection are not supportive. They're set on the ClippingPlaneCollection and are the same for each collection.
  2. It dosen't support concave polygon directly. But you could try decomposing the polygon into convex polygons.
    The star below is actually two triangles.
    image
  3. It only works on the globe terrain with every ClippingPlaneCollection's unionClippingRegions set to false. I didn't rewrite the union function.
  4. Clipping on 3dtiles and models is out of scope, but I think the concept is similar.
  5. Having too many clipping collections or too many clipping planes in one collection will cause performance issues.
  6. There might be bugs. : P

Hope this feautre will come out soon!


There are some mistakes in the MultiClippingPlaneCollection.js file. Please replace it with the new file below. Thanks to @andrevall.


I reuploaded files after I updated Cesium to 1.92.
files.zip


I put the exmaple in the sandcaslte https://zhwy.github.io/cesium/Apps/Sandcastle/index.html?src=Terrain%20Multiple%20Clipping%20Planes.html.

@andrevall
Copy link

Hello @zhwy,

thank you for your reply! I applied the changes you mentioned to the MultiClippingPlaneCollection.js file and it worked perfectly 😀.

I really hope that @cesiumgs-admin will merge this feature in a future release: clipping multiple holes in the terrain is a feature that a lot of people would benefit from.

Thank you again!

Andrea

@zhwy
Copy link

zhwy commented May 25, 2021

You are welcome, Andrea. @andrevall

@abcdweiok
Copy link

I urgently need multiple clipping on the globe!. Here is a simple effect I achieved.
image

These files are modified: GlobeSurfaceShaderSet.js, GlobeSurfaceTileProvieder.js, Globe.js, GlobeVS.glsl.
New files are created: MultiClippingPlaneCollection.js, getMultiClippingFunction.js.
files.zip

You can now clip multiple polygons on the globe by passing an instance of MultiClippingPlaneCollection which manages a list of ClippingPlaneCollection to the multiClippingPlanes property new added to the globe.

For example:

    var clippingPlanecollection1 = new Cesium.ClippingPlaneCollection({
      planes: [
        new Cesium.ClippingPlane(new Cesium.Cartesian3(1.0, 0.0, 0.0), 0.0),
        new Cesium.ClippingPlane(
          new Cesium.Cartesian3(-1.0, 0.0, 0.0),
          -500.0
        ),
        new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 1.0, 0.0), -15.0),
        new Cesium.ClippingPlane(
          new Cesium.Cartesian3(0.0, -1.0, 0.0),
          -15.0
        ),
      ],
    });
    var clippingPlanecollection2 = new Cesium.ClippingPlaneCollection({
      planes: [
        new Cesium.ClippingPlane(new Cesium.Cartesian3(1.0, 0.0, 0.0), 1000),
        new Cesium.ClippingPlane(
          new Cesium.Cartesian3(-1.0, 0.0, 0.0),
          -2000.0
        ),
        new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 1.0, 0.0), -15.0),
        new Cesium.ClippingPlane(
          new Cesium.Cartesian3(0.0, -1.0, 0.0),
          -15.0
        ),
      ],
    });

    globe.multiClippingPlanes = new Cesium.MultiClippingPlaneCollection({
      collections: [clippingPlanecollection1, clippingPlanecollection2],
      modelMatrix: entity.computeModelMatrix(Cesium.JulianDate.now()),
      edgeWidth: 1,
      edgeColor: Cesium.Color.WHITE,
    });

The key point is to rewrite the orginal getClippingFunction.js to getMultiClippingFunction.js to make the fragment shader able to handle multiple clipping plane collections. The shader also needs to know the length of every collection so it can get the correct clipping plane.

This is only a temporary solution on multi-clipping on terrain, more problems to be solved:

  1. Different styles and model matrix on each ClippingPlaneCollection are not supportive. They're set on the ClippingPlaneCollection and are the same for each collection.
  2. It dosen't support concave polygon directly. But you could try decomposing the polygon into convex polygons.
    The star below is actually two triangles.
    image
  3. It only works on the globe terrain with every ClippingPlaneCollection's unionClippingRegions set to false. I didn't rewrite the union function.
  4. Clipping on 3dtiles and models is out of scope, but I think the concept is similar.
  5. There might be bugs. : P

Hope this feautre will come out soon!

There are some mistakes in the MultiClippingPlaneCollection.js file. Please replace it with the new file below. Thanks to @andrevall.
MultiClippingPlaneCollection.zip

excuse me, how to works on the 3dtiles?

@zhwy
Copy link

zhwy commented Sep 1, 2021

@abcdweiok Sorry, I'm not working on it now, might take some time to figure this out.

@qjh999
Copy link

qjh999 commented Sep 1, 2021

@Samulus Hi, When will this capability be supported?

@andrevall
Copy link

andrevall commented Sep 9, 2021

Hi @zhwy,

again thank you so much for this amazing extension to CesiumJS! I would like to notify two bugs that I experience with the multiClippingPlaneCollection:

  1. The first bug happens on iOS devices such as iPhones, iPads etc... I have attached below a video of the bug. Basically, when zooming out, the imagery and terrain disappears completely, but reappears when zooming in. On Android and Windows PC this bug doesn't happen. This is the link I used for demonstration, which is based on Cesium 1.83

multiplanes_ios_min

  1. The second problem is that starting from Cesium 1.84 and after (including the latest 1.85 release), the multiClippingPlanes feature crashes Cesium. The latest working version of Cesium that I was able to use with multiClippingPlanes was release version 1.83. For example, on this demo you can see what happens when I compile with Cesium 1.85

I tried fixing these problems, but my webGL and JS knowledge is too limited for this complex stuff 😌

@zhwy
Copy link

zhwy commented Sep 12, 2021

Hi @andrevall,

Thank you for notifying!

The first problem seems to be a bug of Cesium. I found the same problem of the original terrain clipping example on iphone.
https://sandcastle.cesium.com/?src=Terrain%20Clipping%20Planes.html
I have no idea about how to fix it 😮, maybe we can open a new issue.

About the second problem, the copyFrom interface of Texture class has been modified from 1.84, a 'source' parameter is now required. Two places in MultiClippingPlaneCollection.js need correcting:

      this._dataTexture.copyFrom({
        source: {
          width: widthTotal,
          height: height,
          arrayBufferView: arrayBuffer,
        },
      });

      this._lengthTexture.copyFrom({
        source: {
          width: collections.length,
          height: 1,
          arrayBufferView: lengthArrayBuffer,
        },
      });

Here's the new file:
MultiClippingPlaneCollection.zip

@raulvigueras
Copy link

raulvigueras commented Oct 7, 2021

Hi @zhwy,

Following these lines, I reaffirm the importance of this extension. In my case, I am looking for a way to fit the holes in the tunnels of an underground infrastructure and without a doubt it would be great to have this active capacity.
Thanks.
imagen

At the moment I can only apply a transparency when I approach the mouth of the tunnel.
imagen

@zhwy
Copy link

zhwy commented Oct 19, 2021

Hi @raulvigueras,

Sorry for my replying late. You may try to use the MultiClippingPlaneCollection to clip the holes of tunnels.

clipping

Yet the effect is not very good, it's hard to fit the tunnel holes very well.

@raulvigueras
Copy link

Thanks @zhwy.
I've replaced the GlobeSurfaceTileProvider.js, GlobeSurfaceShaderSet.js, GlobeFS.glsl y Globe.js files, and copied the new MultiClippingPlaneCollection.js and getMultiClippingFunction.js files to their location in ./Source/Scene but I can't create the holes. In the brownser console I get the message 'Uncaught TypeError: Cesium.MultiClippingPlaneCollection is not a constructor'. I have tried with version 1.86 and 1.89. Am I doing something wrong? or am I missing something?

@zhwy
Copy link

zhwy commented Jan 27, 2022

Thanks @zhwy. I've replaced the GlobeSurfaceTileProvider.js, GlobeSurfaceShaderSet.js, GlobeFS.glsl y Globe.js files, and copied the new MultiClippingPlaneCollection.js and getMultiClippingFunction.js files to their location in ./Source/Scene but I can't create the holes. In the brownser console I get the message 'Uncaught TypeError: Cesium.MultiClippingPlaneCollection is not a constructor'. I have tried with version 1.86 and 1.89. Am I doing something wrong? or am I missing something?

Hi @raulvigueras , did you run the compile command like 'npm run build' in the cesium root directory?

After doing this a new Cesium.js will be created in the 'Source' directory and you can import it as a module to use Cesium.MultiClippingPlaneCollection in your test page with 'import * as Cesium from "path/to/Source/Cesium.js"'.
You may need to add 'window.CESIUM_BASE_URL = "path/to/Source"' to avoid the Unable to determine Cesium base URL automatically error.

If you want to make a release version, run the command 'npm run minifyRelease' in the root directory and this will create a 'Build/Cesium' directory which contains the Cesium.js. Put the entire 'Build/Cesium' directory on a server, now you can use it with <script src="path/to/Cesium.js"> .

@chenwwsdo
Copy link

I added six clipping surfaces to the project, which caused my page to get stuck

@chenwwsdo
Copy link

Another problem is that if I add clipping surfaces at the beginning and then I clear them, I need to add them twice if I want to add them again

@zhwy
Copy link

zhwy commented Apr 1, 2022

Hi, @chenwwsdo
Can you show some code snippets?

@saosokin
Copy link

saosokin commented Apr 6, 2022

image

@zhwy
Copy link

zhwy commented Apr 8, 2022

image

Please show me some code snippets or upload data for me to run tests.

@lvfeijian
Copy link

I'm sorry but MultiClippingPlaneCollection only works on the globe for now.

Okay, I would like to know if future updates will consider adding 3dTIles' multiple cropping API

@ggetz
Copy link
Contributor

ggetz commented May 1, 2023

Requested on the forum https://community.cesium.com/t/tileset-multiple-clippingplanes-irregular-clippingplane-shape/23666

@saadatali48
Copy link

image
I am getting this error, anybody know the fix to it?

@Immersiv-1
Copy link

I urgently need multiple clipping on the globe!. Here is a simple effect I achieved. image

These files are modified: GlobeSurfaceShaderSet.js, GlobeSurfaceTileProvieder.js, Globe.js, GlobeVS.glsl. New files are created: MultiClippingPlaneCollection.js, getMultiClippingFunction.js.

You can now clip multiple polygons on the globe by passing an instance of MultiClippingPlaneCollection which manages a list of ClippingPlaneCollection to the multiClippingPlanes property new added to the globe.

For example:

var clippingPlanecollection1 = new Cesium.ClippingPlaneCollection({
  planes: [
    new Cesium.ClippingPlane(new Cesium.Cartesian3(1.0, 0.0, 0.0), 0.0),
    new Cesium.ClippingPlane(
      new Cesium.Cartesian3(-1.0, 0.0, 0.0),
      -500.0
    ),
    new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 1.0, 0.0), -15.0),
    new Cesium.ClippingPlane(
      new Cesium.Cartesian3(0.0, -1.0, 0.0),
      -15.0
    ),
  ],
});
var clippingPlanecollection2 = new Cesium.ClippingPlaneCollection({
  planes: [
    new Cesium.ClippingPlane(new Cesium.Cartesian3(1.0, 0.0, 0.0), 1000),
    new Cesium.ClippingPlane(
      new Cesium.Cartesian3(-1.0, 0.0, 0.0),
      -2000.0
    ),
    new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 1.0, 0.0), -15.0),
    new Cesium.ClippingPlane(
      new Cesium.Cartesian3(0.0, -1.0, 0.0),
      -15.0
    ),
  ],
});
globe.multiClippingPlanes = new Cesium.MultiClippingPlaneCollection({
  collections: [clippingPlanecollection1, clippingPlanecollection2],
  modelMatrix: entity.computeModelMatrix(Cesium.JulianDate.now()),
  edgeWidth: 1,
  edgeColor: Cesium.Color.WHITE,
});

The key point is to rewrite the orginal getClippingFunction.js to getMultiClippingFunction.js to make the fragment shader able to handle multiple clipping plane collections. The shader also needs to know the length of every collection so it can get the correct clipping plane.

This is only a temporary solution on multi-clipping on terrain, more problems to be solved:

  1. Different styles and model matrix on each ClippingPlaneCollection are not supportive. They're set on the ClippingPlaneCollection and are the same for each collection.
  1. It dosen't support concave polygon directly. But you could try decomposing the polygon into convex polygons.

The star below is actually two triangles.

image

  1. It only works on the globe terrain with every ClippingPlaneCollection's unionClippingRegions set to false. I didn't rewrite the union function.
  1. Clipping on 3dtiles and models is out of scope, but I think the concept is similar.
  1. Having too many clipping collections or too many clipping planes in one collection will cause performance issues.
  1. There might be bugs. : P

Hope this feautre will come out soon!

There are some mistakes in the MultiClippingPlaneCollection.js file. Please replace it with the new file below. Thanks to @andrevall.

I reuploaded files after I updated Cesium to 1.92. files.zip

Hello! Is it possible to update the feature to the latest? 1.106 or 1.107? Thanks!

@zhwy
Copy link

zhwy commented Aug 15, 2023

Update for Cesium 1.108. files.zip
@Immersiv-1 @saadatali48

@saadatali48
Copy link

@zhwy any update on multiclipping for 3D Tileset?

@Iron-john
Copy link

针对铯 1.108 的更新。文件.zip

Hi, I tried in Cesium1.108, no error shows,but results are not displayed on earth.o(╥﹏╥)o

@Immersiv-1
Copy link

Immersiv-1 commented Sep 14, 2023 via email

@zhwy
Copy link

zhwy commented Sep 14, 2023

@Iron-john @Immersiv-1

I checked my codes and found that only the modelMatrix set on the MultiClippingCollection participates in the calculation, so the modelMatrix of each ClippingCollection has no effect. Better to calculate the clipping collections in the cartesian absolute coordinate system.

Here is an example:

const viewer = new Cesium.Viewer("cesiumContainer");
viewer.camera.setView({
  destination: new Cesium.Cartesian3(1e7, 0, 0),
});

viewer.scene.debugShowFramesPerSecond = true;

const { globe } = viewer.scene;
globe.depthTestAgainstTerrain = true;

const multiCollections = new Cesium.MultiClippingPlaneCollection({
  collections: [
    generateClippingPlanesCollection([
      Cesium.Cartesian3.fromDegrees(-10, -5),
      Cesium.Cartesian3.fromDegrees(10, -5),
      Cesium.Cartesian3.fromDegrees(0, 10),
    ]),
    generateClippingPlanesCollection([
      Cesium.Cartesian3.fromDegrees(-10, 5),
      Cesium.Cartesian3.fromDegrees(0, -10),
      Cesium.Cartesian3.fromDegrees(10, 5),
    ]),
  ],
  modelMatrix: Cesium.Matrix4.IDENTITY,
  edgeWidth: 5,
  edgeColor: Cesium.Color.WHITE,
});
globe.multiClippingPlanes = multiCollections;

const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
let positions = [];

// left click to add points to a clipping planes collection
handler.setInputAction(function (movement) {
  const worldPosition = viewer.scene.pickPosition(movement.position);
  if (Cesium.defined(worldPosition)) {
    positions.push(worldPosition);
  }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

// right click to end a clipping planes collection
handler.setInputAction(function (movement) {
  const worldPosition = viewer.scene.pickPosition(movement.position);
  if (Cesium.defined(worldPosition)) {
    positions.push(worldPosition);
    if (positions.length > 2) {
      const collection = generateClippingPlanesCollection(positions);
      multiCollections.add(collection);
      positions = [];
    }
  }
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);

function generateClippingPlanesCollection(points) {
  const pointsLength = points.length;
  const clippingPlanes = [];
  for (let i = 0; i < pointsLength; ++i) {
    const nextIndex = (i + 1) % pointsLength;
    let midpoint = Cesium.Cartesian3.add(
      points[i],
      points[nextIndex],
      new Cesium.Cartesian3()
    );
    midpoint = Cesium.Cartesian3.multiplyByScalar(
      midpoint,
      0.5,
      midpoint
    );

    const up = Cesium.Cartesian3.normalize(
      midpoint,
      new Cesium.Cartesian3()
    );
    let right = Cesium.Cartesian3.subtract(
      points[nextIndex],
      midpoint,
      new Cesium.Cartesian3()
    );
    right = Cesium.Cartesian3.normalize(right, right);

    let normal = Cesium.Cartesian3.cross(
      right,
      up,
      new Cesium.Cartesian3()
    );
    normal = Cesium.Cartesian3.normalize(normal, normal);

    // Compute distance by pretending the plane is at the origin
    const originCenteredPlane = new Cesium.Plane(normal, 0.0);
    const distance = Cesium.Plane.getPointDistance(
      originCenteredPlane,
      midpoint
    );

    clippingPlanes.push(new Cesium.ClippingPlane(normal, distance));
  }

  return new Cesium.ClippingPlaneCollection({
    planes: clippingPlanes,
    modelMatrix: Cesium.Matrix4.IDENTITY,
  });
}

@Immersiv-1
Copy link

Immersiv-1 commented Sep 14, 2023 via email

@Immersiv-1
Copy link

Immersiv-1 commented Sep 14, 2023 via email

@Immersiv-1
Copy link

Immersiv-1 commented Sep 14, 2023 via email

@Immersiv-1
Copy link

Immersiv-1 commented Sep 21, 2023 via email

@zhwy
Copy link

zhwy commented Sep 23, 2023

Too many points in the collection will raise the performace problem. You could try generating points dynamically referring to the comments above. @Immersiv-1

Hello @kk1625846601 , can you upload a screenshot or a gif ? I don't understand "there is a layer of ground above, and I can't see the pipeline below from above the ground". Do you mean the ground is still visible after being clipped?

Hello, I have re studied the whole process and found that the problem lies in the method of generating pits. In the camera change event, the cutting plane can be dynamically updated. There are no problems with your multiclippingplanes.Thanks very much.

@Immersiv-1
Copy link

Immersiv-1 commented Sep 23, 2023 via email

@Immersiv-1
Copy link

Immersiv-1 commented Sep 27, 2023 via email

@zhwy
Copy link

zhwy commented Sep 28, 2023

Hi, @Immersiv-1 MultiClippingCollection is not Cesium's official feature, it's my temporary solution. I am sorry you encountered problems with it. Your developer offered a good suggestion but I don't have time to solve this optimization problem right now. I suggest you look for other alternatives.

@Immersiv-1
Copy link

Immersiv-1 commented Sep 28, 2023 via email

@saadatali48

This comment was marked as resolved.

@saadatali48

This comment was marked as resolved.

@saadatali48
Copy link

saadatali48 commented Feb 19, 2024

Hi @Immersiv-1 , @zhwy & everyone

I want to have a single part of the globe and hide rest of it. As there is no option to use union clipping region, how we can use multiclipping in this case?
Solution that I have implemented works with normal globe.clippingPlanes but when I try with globe.multiclippingPlanes It doesnt work, because unionregion is not implemented for multiclipping. Can anyone have a solution for this please?

Here is sandcastle link to current implementation.

image

@lvfeijian
Copy link

I'm sorry but MultiClippingPlaneCollection only works on the globe for now.

Regarding the cropping function of 3dTIles, is there any way to achieve multiple cropping? Currently, ClippingPlanes can only achieve single cropping

@lvfeijian
Copy link

I'm sorry but MultiClippingPlaneCollection only works on the globe for now.

I see a lot of feedback from people who want cesium to support multiple cropping on 3dTiles

@farmerlfz
Copy link

cesium 1.117 Supports multiple polygon cropping
viewer.scene.globe.clippingPolygons = new Cesium.ClippingPolygonCollection({
polygons: polygons
});
1

@lvfeijian
Copy link

lvfeijian commented May 15, 2024 via email

@zhang765399515
Copy link

Is version 1.97 supported?

@lvfeijian
Copy link

lvfeijian commented May 17, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Notable backlog items
Development

Successfully merging a pull request may close this issue.