Tezra
Tezra

Reputation: 8833

How to check if a Cesium Entity is visible / occluded

Given an Entity, I'm trying to figure out if at a particular moment/frame, if one of the entities is viewable on the screen.

The closest I could find was Entity.isVisible, but it seems to just tally the explicit show properties. It returns true even if...

I also can't find any functions to convert the entity position to viewport coordinates to test if it is at least within the camera view cone.

I had one idea to measure the distance between the entity and the camera kinda like this Cesium.Cartesian3.distance(this.viewer.selectedEntity.position.getValue(Cesium.JulianDate.now()), this.viewer.camera.position); But obviously the acceptable distance needs to be based on the camera height, FOV and if the camera is even looking in that direction. I haven't yet been able to get the math to work for this solution.

How can I tell if an Entity is currently visible to the user?

Upvotes: 3

Views: 1643

Answers (2)

Mikael Mantis
Mikael Mantis

Reputation: 1

Using BoundingSphere and in the frustum culling works for 2D visualizations however will return Cesium.Intersect.INSIDE for entities that are on the other side of the globe.

A more accurate method would be to use the Occluder class. Not sure why but similar questions across forums and documentation fail to mention this class. Here is a working example given a viewer and a Cartesian3 position:

    isPositionInView(position: Cartesian3) {
        const globeBoundingSphere = new BoundingSphere(
            Cartesian3.ZERO,
            this.viewer.scene.globe.ellipsoid.minimumRadius
        );
        const occluder = new Occluder(
            this.globeBoundingSphere,
            this.viewer.camera.position
        );

        return occluder.isPointVisible(position);
    }

Note: I use ellipsoid.minimumRadius here to account for entities that are on the globe's surface.

Upvotes: 0

Ugnius Malūkas
Ugnius Malūkas

Reputation: 2827

One of the ways is to use BoundingSphere in the frustum culling. Then check if the bounding sphere of the entity is visible in the culling volume.

const viewer = new Cesium.Viewer('cesiumContainer');
const camera = viewer.camera;

const position = Cesium.Cartesian3.fromDegrees(23.9036, 54.8985);

const frustum = camera.frustum;
const cullingVolume = frustum.computeCullingVolume(
  camera.position,
  camera.direction,
  camera.up
);

const someEntity = viewer.entities.add({
    name: 'Some Point',
    position: position,
    point: {
        pixelSize: 14,
        color: Cesium.Color.GREEN
    }
});

// Bounding sphere of the entity.
let boundingSphere = new Cesium.BoundingSphere();
viewer.dataSourceDisplay.getBoundingSphere(someEntity, false, boundingSphere);

// Check if the entity is visible in the screen.
const intersection = cullingVolume.computeVisibility(boundingSphere);

console.log(intersection);
//  1: Cesium.Intersect.INSIDE
//  0: Cesium.Intersect.INTERSECTING
// -1: Cesium.Intersect.OUTSIDE

I have also made a Cesium Sandcastle example.

Upvotes: 4

Related Questions