Controls to rotate a point cloud?

I’m rendering a 3D point cloud. I’m only interested in the 3D model itself, there isn’t any geolocation data attached.

I’ve made a simple scene but the mouse rotation controls are unintuitive IMO. Id like to either:
1 - Make clicking and dragging the mouse rotate the model (as Potree does).
2 - Expose a widget that users can click on to rotate the scene.

Can either of these be done?

Im confused by the docs, many link to a sandcastle page but these but I get an error trying to load them eg Cesium Sandcastle
Error, first part of bucket-requirejs.html must match first part of bucket.html exactly.

Here is my code:

async function init() {
  // Grant CesiumJS access to your ion assets
  Cesium.Ion.defaultAccessToken = YOUR_ACCESS_TOKEN_HERE;

  const viewer = new Cesium.Viewer("cesiumContainer", {
    skyBox: false,
    globe: false,
    baseLayerPicker: false,
    navigationHelpButton: true, // Shows navigation instructions
    navigationInstructionsInitiallyVisible: false, // Shows help overlay on start
    sceneModePicker: false, // Allows switching between 3D/2D modes
    navigationWidget: true, // Add navigation widget
  });

  // Enable screen space camera controller
  viewer.scene.screenSpaceCameraController.enableRotate = true; // Enable rotation
  viewer.scene.screenSpaceCameraController.enableTilt = true; // Enable tilting
  viewer.scene.screenSpaceCameraController.enableTranslate = true; // Enable panning
  viewer.scene.screenSpaceCameraController.enableZoom = true; // Enable zoom

  viewer.scene.backgroundColor = Cesium.Color.WHITE;


  try {
    const tileset = await Cesium.Cesium3DTileset.fromIonAssetId(
      YOUR_ASSET_ID_HERE,
      {
        //This tileset doesn't have a location, so we're using a modelMatrix to place it at 0, 0 instead of drawing at the center of the earth
        modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(
          Cesium.Cartesian3.fromDegrees(0, 0)
        ),
      }
    );
    viewer.scene.primitives.add(tileset);
    await viewer.zoomTo(tileset);

    // Apply the default style if it exists
    const extras = tileset.asset.extras;
    if (
      Cesium.defined(extras) &&
      Cesium.defined(extras.ion) &&
      Cesium.defined(extras.ion.defaultStyle)
    ) {
      tileset.style = new Cesium.Cesium3DTileStyle(extras.ion.defaultStyle);
    }

    // Add this to change point cloud color (if needed)
    tileset.style = new Cesium.Cesium3DTileStyle({
      color: 'color("blue")', // You can use any CSS color name or RGB/RGBA values
    });
  } catch (error) {
    console.log(error);
  }
}
init();

First, a short aside about that message

Error, first part of bucket-requirejs.html must match first part of bucket.html exactly.

I have seen this error occasionally, but I think that this only happened during local development. If you see this with the actual online version at Cesium Sandcastle , then that’s unusual. A related thread contains different suggestions for how to solve this, like clearing cache and cookies. If this thread does not help, this may have to be investigated further.


About the controls:

The “default controls” may appear to be “unintuitive” when there is no geolocation involved. The standard interactions in CesiumJS are pretty much tailored for an intuitive navigation on the globe (which is unbelievably challenging). Beyond that, there are always many degrees of freedom for user interactions.

(Anecdotal: When dragging the mouse to rotate, then there may be two expectations: CAD people expect the model to rotate. People who are more into computer games or VR expect the camera to rotate…)

However, when the goal is to examine a model that is centered in the view, without any geo-context, then you’re most likely looking for the functionality of setting the reference frame of the camera. This can be done with Camera#lookAtTransform.

The following is a Sandcaste … (and hopefully this bucket.html issue can be resolved) … is extracted from yours, and that loads an existing point cloud tileset. And it uses the following snippet to center the view at the loaded tileset:

    const transform = Cesium.Matrix4.fromTranslation(
      tileset.boundingSphere.center, new Cesium.Matrix4());
    viewer.camera.lookAtTransform(
      transform,
      new Cesium.Cartesian3(50.0, 50.0, 50.0),
    );
    viewer.camera.constrainedAxis = Cesium.Cartesian3.UNIT_Z;

This snippet uses the tileset.boundingSphere.center of the tileset as the reference frame center point. You can also manually set that point - for example, when you want to center the camera at the origin, then this could just be new Cesium.Cartesian3(0,0,0).

(Note: In the sandcastle, the model seems to be oddly rotated. This is because it already does have a geolocation. But the functionality of setting the reference frame should work for the model even when it is at the origin)

The sandcastle issue was just caching :man_facepalming:

Thanks for such a detailed response. The code works and explanation makes perfect sense.

@Marco13 your code changes work but it’s difficult to rotate the object effectively. Im my case its a long thin object which could be the reason?

It’s hard for me to describe why exactly it’s hard. I recorded a video first using Potree (which works nicely) and then Cesium (with your code changes), I’m not sure if that will indicate what I mean?:

Some guesses are involved here, just based on the video:

At the beginning of the CesiumJS part, you are

  • First zooming out - you can change the parameter of new Cesium.Cartesian3(50.0, 50.0, 50.0) that is used in the Sandcastle, with larger values (like 200 or so) to start further away
  • Then (the important part) you seem to be dragging up, and then horizontally

When you are dragging up until it hits the “limit”, then subsequent rotations may appear counterintiuitive. Again, there are many degrees of freedom - even the fact that there is such a “limit” or that constrainedAxis may be something that the user does not want or expect. You can try setting
viewer.camera.constrainedAxis = undefined;
(instead of Cesium.Cartesian3.UNIT_Z). This way, the behavior resembles that of a “trackball”, where you can freely rotate, and the interaction (roughly speaking) always refers to the current orientation.

1 Like