Rotating clipping plane around itself

Hello everyone,

I’m trying to rotate a clipping plane, from the clipping plane editor (SDK object).
I end up with this function, called each time my variable “orient” changes (it is binded to a slider, representing orientation in degrees 0-360), which reconstruct clippingPlanes and editor :

Function
function updateRotation(orient) {

    var angleRadians = Cesium.Math.toRadians(orient);

    var dist = tileset.clippingPlanes.get(0).distance;

    var rotatedPlane = new Cesium.Plane(new Cesium.Cartesian3(Math.cos(angleRadians), Math.sin(angleRadians), 0.0), dist);
    
    //get the translation in local frame between the rotated plane and the origin
    var translate = new Cesium.Cartesian3(Math.cos(angleRadians)*dist, Math.sin(angleRadians)*dist, 0.0);

    clippingPlanes = new Cesium.ClippingPlaneCollection({
        planes : [Cesium.ClippingPlane.fromPlane(rotatedPlane)],
        edgeWidth : 1.0
    });

    if (Cesium.defined(clippingPlanesEditor)) {
        clippingPlanesEditor.destroy();
        clippingPlanesEditor = undefined;
    }

    tileset.clippingPlanes = clippingPlanes;

    clippingPlanesEditor = new Cesium.ClippingPlanesEditor({
        scene : viewer.scene,
        clippingPlanes : clippingPlanes,
        movePlanesToOrigin : false,
        //origin : ?,
        maximumSizeInMeters : new Cesium.Cartesian2(500, 500),
        pixelSize : new Cesium.Cartesian2(150, 150)
    });
    clippingPlanesEditor.activate();
}

With this function my plane is rotating over the tileset center when its distance is not zero.

For it to rotate around itself I figured out that I need to rotate the editor’s origin around the plane (not the tileset.center otherwise my tileset would also rotate).
Or maybe something more efficient, translate the editor’s origin to the plane (the inverse of moving the plane to its origin) and setting the plane’s distance to zero (so that it would rotate over the new origin, “itself”)

Maybe there is a simpler way to achieve this effect, working with the clipping plane editor from the SDK.
I tried a lot of different approaches, like getting the translation vector between the previous plane and the new plane (rotated), then applying that translation to the new plane so that it would “stay in place”.
Or getting the translation from the origin to the plane (normal*distance).
Or playing with clippingPlanes.modelMatrix.

I tried to use Cesium.Transforms.eastNorthUpToFixedFrame to get a 4x4 transform matrix at the tileset’s center or editor’s origin, but I don’t really know what to do with it then.

Here is the complete sandcastle code (SDK required) :

Javascript
/////////////////////
////////INIT/////////
/////////////////////

var viewer = new Cesium.Viewer('cesiumContainer', {
    scene3DOnly : true,
    terrainProvider : Cesium.createWorldTerrain()
});
var globe = viewer.scene.globe;
globe.depthTestAgainstTerrain = true;

var viewModel = {
    orientation: 0
};

Cesium.knockout.track(viewModel);

var toolbar = document.getElementById('toolbar');
Cesium.knockout.applyBindings(viewModel, toolbar);

var clippingPlanes;
var clippingPlanesEditor;
var tileset;

clippingPlanes = new Cesium.ClippingPlaneCollection({
    planes : [
        new Cesium.ClippingPlane(new Cesium.Cartesian3(1, 0, 0), 0),
    ],
    unionClippingRegions : true,
    edgeWidth : 1.0
});

tileset = new Cesium.Cesium3DTileset({
    url : Cesium.IonResource.fromAssetId(40866),
    clippingPlanes : clippingPlanes
});

tileset.readyPromise.then(function(tileset) {
    viewer.scene.primitives.add(tileset);
    viewer.zoomTo(tileset);
});


clippingPlanesEditor = new Cesium.ClippingPlanesEditor({
    scene : viewer.scene,
    clippingPlanes : tileset.clippingPlanes,
    movePlanesToOrigin : true,
    maximumSizeInMeters : new Cesium.Cartesian2(500, 500),
    pixelSize : new Cesium.Cartesian2(150, 150)
});
clippingPlanesEditor.activate();

/////////////////////
//////END INIT///////
/////////////////////


function updateRotation(orient) {

    var m4 = Cesium.Transforms.eastNorthUpToFixedFrame(clippingPlanesEditor._origin);// or tilest.boundingSphere.center ? but what for ?

    var angleRadians = Cesium.Math.toRadians(orient);

    var dist = tileset.clippingPlanes.get(0).distance;
    
    //create a new plane, with rotation from the slider
    var rotatedPlane = new Cesium.Plane(new Cesium.Cartesian3(Math.cos(angleRadians), Math.sin(angleRadians), 0.0), dist);

    //the point in local frame where the editor's origin would be moved to
    var rotatedPlaneOrigin = new Cesium.Cartesian3(Math.cos(angleRadians)*dist, Math.sin(angleRadians)*dist, 0.0);

    //var newEditorOrigin = Cesium.Matrix4.multiplyByPoint(m4, rotatedPlaneOrigin);//incorrect it seems

    clippingPlanes = new Cesium.ClippingPlaneCollection({
        planes : [Cesium.ClippingPlane.fromPlane(rotatedPlane)],
        unionClippingRegions : true,
        edgeWidth : 1.0
    });

    if (Cesium.defined(clippingPlanesEditor)) {
        clippingPlanesEditor.destroy();
        clippingPlanesEditor = undefined;
    }

    tileset.clippingPlanes = clippingPlanes;

    clippingPlanesEditor = new Cesium.ClippingPlanesEditor({
        scene : viewer.scene,
        clippingPlanes : clippingPlanes,
        movePlanesToOrigin : false,//need to be true when the origin is translated
        //origin : ?,
        maximumSizeInMeters : new Cesium.Cartesian2(500, 500),
        pixelSize : new Cesium.Cartesian2(150, 150)
    });
    clippingPlanesEditor.activate();
}

Cesium.knockout.getObservable(viewModel, 'orientation').subscribe(function(orientation) {
    orientation = Number(orientation);
    if (isNaN(orientation)) {
        return;
    }
    updateRotation(orientation);
});
HTML and CSS
<style>
    @import url(../templates/bucket.css);
</style>
<div id="cesiumContainer" class="fullSize"></div>
<div id="loadingOverlay"><h1>Loading...</h1></div>
<div id="toolbar">
    <div>Orientation</div>
    <input type="range" min="-180.0" max="180.0" step="1" data-bind="value: orientation, valueUpdate: 'input'">
    <input type="text" size="5" data-bind="value: orientation">
</div>

Any help or thought is welcomed !

cesium version : latest
browser : chrome

Hey Benoit, welcome to the new forum!

The easiest way to rotate the clipping plane around itself is to change its origin. You can do this by modifying its model matrix. I put together a Sandcastle here showing this. You can click the buttons at the top to toggle between rotating around the origin of the 3D Tileset, or rotating around an offset from that origin.

Let me know if that helps! We have been considering changing how clipping planes are defined to be more of a global setting, so you can define it in world coordinates and not have to worry about relative offsets. The GitHub issue for this is here: https://github.com/CesiumGS/cesium/issues/8554.

Hello Omar !

Thank you for your answer, that did help.
I almost get what I want, which is rotating a clipping plane around itself and still being able to move it along its normal (playing with the plane’s distance).

Each time the rotation changes, I test if the plane has been moved along its normal. If so, I set an offest to the clipping plane collection, and reset the plane distance, wich gives me the effect I want on the clipping plane.

My only issue is that I’d like to use the clipping plane editor to move the plane along its normal, which a very handy object, visually pleasing and easy to use.
However, the visual plane reset itself at tileset’s center each time the clipping plane’s distance is set to zero.
The wanted behaviour would be that the visual plane from the editor stays at the plane’s origin (translated by the collection matrix).

Here is a sandcastle to show the effect, using a slider to modify plane’s distance : Sandcastle (cesium.js)

And here is another sandcastle with the clipping plane editor used to modify plane’s distance (need to uncomment editors objects and functions) : Sandcastle (cesium.js + cesium SDK)

I figured out that I can move the editor’s origin, so I need to move it at the clipping plane collection’s center, which is at tileset.center and transformed by a 4*4 matrix.

However this matrix is in local frame. How can I get this center in the fixed frame ?
I hope I am clear enough.

Regarding the cesium issue you pointed out, I think that it is a good idea to have clipping planes wihich are always defined in global coordinates and without ownership.
One of our use case is to clip several objects with a single plane, and this would help (also remonving clipping plane owneship to a model).

Thank you for your time !