function getPickRayPerspective(camera, windowPosition, result) {
  const canvas = camera._scene.canvas;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;

  const tanPhi = Math.tan(camera.frustum.fovy * 0.5);
  const tanTheta = camera.frustum.aspectRatio * tanPhi;
  const near = camera.frustum.near;

  const x = (2.0 / width) * windowPosition.x - 1.0;
  const y = (2.0 / height) * (height - windowPosition.y) - 1.0;

  const position = camera.positionWC;
  Cartesian3.clone(position, result.origin);

  const nearCenter = Cartesian3.multiplyByScalar(
    camera.directionWC,
    near,
    pickPerspCenter,
  );
  Cartesian3.add(position, nearCenter, nearCenter);
  const xDir = Cartesian3.multiplyByScalar(
    camera.rightWC,
    x * near * tanTheta,
    pickPerspXDir,
  );
  const yDir = Cartesian3.multiplyByScalar(
    camera.upWC,
    y * near * tanPhi,
    pickPerspYDir,
  );
  const direction = Cartesian3.add(nearCenter, xDir, result.direction);
  Cartesian3.add(direction, yDir, direction);
  Cartesian3.subtract(direction, position, direction);
  Cartesian3.normalize(direction, direction);

  return result;
}
Pick an ellipsoid or map.

@param {Cartesian2} windowPosition The x and y coordinates of a pixel.
@param {Ellipsoid} [ellipsoid=Ellipsoid.default] The ellipsoid to pick.
@param {Cartesian3} [result] The object onto which to store the result.
@returns {Cartesian3 | undefined} If the ellipsoid or map was picked,
returns the point on the surface of the ellipsoid or map in world
coordinates. If the ellipsoid or map was not picked, returns undefined.

@example
const canvas = viewer.scene.canvas;
const center = new Cesium.Cartesian2(canvas.clientWidth / 2.0, canvas.clientHeight / 2.0);
const ellipsoid = viewer.scene.ellipsoid;
const result = viewer.camera.pickEllipsoid(center, ellipsoid);