Scene.globe.pick delivers undefined

Hi,

is there a trick - for the usage of scene.globe.pick . I want to determine the intersection with the terrain, but scene.globe.pick delivers in most cases undefined - see Sandcastle.

Disclaimer: I’m not deeply familiar with CesiumJS or picking, but will try to give some hints, involving a rough guess about what you are trying to achieve:

You apparently want to compute the intersection of the rays with a theoretical ground level. The important point here is: You don’t want to compute an “actual” intersection with geometry (otherwise you’d have to use a Terrain Provider somewhere).

It this is true, then the main issues are:

  1. The rays are horizontal, at z=0, so … they’ll hardly intersect anything. This can easily be fixed by letting the rays start at a z-value that is greater than 0, and letting them end at a z-value that is smaller than 0.

  2. The intersection checks are performed “too early”, when the relevant part of the globe is not yet rendered. This can be fixed by not using globe.pick, but computing the intersection point analytically.

Specifically: The globe.pick function computes the intersection with something that has been rendered. But calling the function directly in the sandcastle will cause this to happen when the globe is not rendered yet.

But instead of using globe.pick, you can compute the intersection of the ray with the WGS84 ellipsoid that approximates the surface of the earth (and for which the theoretical, approximated ground level is at z=0).

An updated sandcastle - the changes marked with UPDATED:

var viewer = new Cesium.Viewer("cesiumContainer");

// München
// UPDATED: Start the ray at height "200", which is "above the ground"
var starting_point = Cesium.Cartesian3.fromDegrees(	11.54985, 48.13041, 200);

// Bavaria
// UPDATED: End the ray at height "-100", which is "below the ground"
var end = Cesium.Cartesian3.fromDegrees(11.54582, 48.13072, -100);

viewer.camera.flyTo({
    destination : starting_point,
    complete: analysisVisible
});


var lat = 48.13041;
for (var i=0; i<100; i++)
{
  lat = lat + 0.00001;
  // UPDATED: Start the ray at height "200", which is "above the ground"
  starting_point = Cesium.Cartesian3.fromDegrees(11.54985, lat, 200);
  analysisVisible();
}


// * View analysis
function analysisVisible() {

// * Calculate the direction of the ray
  let direction = Cesium.Cartesian3.normalize(
    Cesium.Cartesian3.subtract(
             end,
             starting_point,
      new Cesium.Cartesian3()
    ),
    new Cesium.Cartesian3()
  );
  // Establish a ray
  let ray = new Cesium.Ray(starting_point, direction);
  
  //let result = viewer.scene.globe.pick(ray, viewer.scene); // calculate intersection points
  
  // UPDATED: Compute the intersection of the ray with
  // the surface of the WGS84 ellipsoid that approximates
  // the shape of the earth
  let intersectionInterval = Cesium.IntersectionTests.rayEllipsoid(ray, Cesium.Ellipsoid.WGS84);
  if (Cesium.defined(intersectionInterval)) {
    console.log("Result - ok");
    
    // Compute the intersection point from the interval
    var t = intersectionInterval.start > 0.0 ? intersectionInterval.start : intersectionInterval.stop;
    var result = Cesium.Ray.getPoint(ray, t, new Cesium.Cartesian3());
    
    drawLine(result,  starting_point, Cesium.Color.GREEN); // visual
    drawLine(result,  end, Cesium.Color.RED); // is not visible
  } else {
    console.log("Result - undefined");
    drawLine(starting_point,  end, Cesium.Color.YELLOW); // UPDATED: indicate error
  }
}

// * draw line
function drawLine(starting_point,  end, color) {
  viewer.entities.add({
    polyline: {
      positions: [starting_point,  end],
      width: 5,
      material: color,
      depthFailMaterial: color,
      //clampToGround: true // UPDATED: I found that confusing :-)
    }
  });
}

It should show the expected rays, starting above da Theräsienwiesn, and ending under da Bavaria:

1 Like

Hi,

@Marco13 thank you for the explanation.

I also found out, that I have to check if the terrain is loaded, if I wat to use the terrain.

Regards

Rüdiger

Indeed, if you actually want to compute intersections with the terrain, then things may become more tricky. The globe.pick function can then only be used when the respective part of the terrain is actually visible on the screen.

(One can argue that this is implied by the word “picking”, which suggests that this is related to some user interaction on the screen, with the rendered model. There are also mechanisms for performing similar checks for the geometry when it is not rendered, but I’d have to look into the details here, and at some point, these details (i.e. the most sensible solution) might depend on your exact goals…)

1 Like