A way to orient and place Frustum outline

In another thread someone asked how to orient (and place) Frustum outlines. I believe I got a fully working sandcastle example here:

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

const onComplete = () => {
  return () => {
    viewer.scene.globe.depthTestAgainstTerrain = true;
    viewer.scene.debugShowFrustumPlanes = true;

    setTimeout(
      function() {
        viewer.camera.zoomOut(10);
        doit();
      }, 50);
  };
};

//set us up
var heading = 90;
var pitch = -45;
var roll = -22;
const lon = 90;
const lat = 0;
const height = 66.5;
const origin = Cesium.Cartesian3.fromDegrees(lon, lat, height);
const zeroPt = new Cesium.Cartesian3(0,0,0);

// orientation for flyTo
const orientationCamera = {
  heading: Cesium.Math.toRadians(heading),
  pitch: Cesium.Math.toRadians(pitch),
  roll: Cesium.Math.toRadians(roll),
};

//flyTo
viewer.camera.flyTo({
  destination: origin,
  orientation: orientationCamera,
  complete: onComplete(),
});

function doit()
{
  if(1) //method I wrote
  {
    //deg to rad
    heading*=Math.PI/180;pitch*=Math.PI/180;roll*=Math.PI/180;

    //declare shortcuts
    var til=pitch+(Math.PI/2);roll*=-1;
    var ch = Math.cos(heading);var sh = Math.sin(heading);
    var ct = Math.cos(til);var st = Math.sin(til);
    var cr = Math.cos(roll);var sr = Math.sin(roll);

    //calc rot mat in terms of local ENU frame
    var myrig=new Cesium.Cartesian3(ch*cr+sh*ct*sr,sh*cr*-1+ch*ct*sr,st*sr);
    var mydir=new Cesium.Cartesian3(sh*st,ch*st,ct*-1);
    var myup=new Cesium.Cartesian3(sh*ct*cr+ch*sr*-1,ch*ct*cr+sh*sr,st*cr);

    //transform rot mat to world coordinates
    var GD_transform = Cesium.Transforms.eastNorthUpToFixedFrame(origin, viewer.scene.globe.ellipsoid, new Cesium.Matrix4());//rot-tran
    var GD_rotmat = Cesium.Matrix4.getMatrix3(GD_transform, new Cesium.Matrix3());
    Cesium.Matrix3.multiplyByVector(GD_rotmat, myrig, myrig);
    Cesium.Matrix3.multiplyByVector(GD_rotmat, mydir, mydir);
    Cesium.Matrix3.multiplyByVector(GD_rotmat, myup, myup);
    var rot = [myrig.x,myrig.y,myrig.z,mydir.x,mydir.y,mydir.z,myup.x,myup.y,myup.z];
  }
  else //using built in function (not working properly)
  {
    const rotation4 = new Cesium.HeadingPitchRoll.fromDegrees(heading, pitch, roll);
    const mat = Cesium.Transforms.headingPitchRollToFixedFrame(origin, rotation4);
    var rot = new Cesium.Matrix3();
    Cesium.Matrix4.getMatrix3(mat,rot);
  }

  //create frustum
  let frustum4 = new Cesium.PerspectiveFrustum();
  frustum4.fov = Cesium.Math.PI_OVER_TWO;
  frustum4.aspectRatio = 4 / 3;
  frustum4.near = 1.0;
  frustum4.far = 30.0;
  const frustumGeometry4 = new Cesium.FrustumOutlineGeometry({
    frustum: frustum4,
    origin: zeroPt,
    orientation: {x:0,y:0,z:0,w:1}, //same as HPR 0,0,0
  });
  const frustumOutlineGeometryInstance4 = new Cesium.GeometryInstance({
    geometry: frustumGeometry4,
  //modelMatrix :[1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1], //identity
  modelMatrix :[1,0,0,0, 0,0,-1,0, 0,1,0,0, 0,0,0,1], //twist 90deg around x
      attributes: {
        color: Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(0.0, 1.0, 0.0, 1.0))
      },
  });
  myprim = viewer.scene.primitives.add(
    new Cesium.Primitive({
      geometryInstances: frustumOutlineGeometryInstance4,
      appearance: new Cesium.PerInstanceColorAppearance({
        closed: true,
        flat: true,
      }),
    }),
  );

//place and orient primitive
    myprim.modelMatrix=
    [rot[0],rot[1],rot[2],0, rot[3],rot[4],rot[5],0, rot[6],rot[7],rot[8],0,
    origin.x,origin.y,origin.z,1];
}

I made the frustum creation as generic as possible, such as
orientation: {x:0,y:0,z:0,w:1}
origin: zeroPt

For geometry instance instead of the identity matrix I used one that rotates the face forward (it is created facing up.) Placement and orientation is only done once it is made into a primitive.

I used my own HPR to rot matrix calculations I wrote way back when I made 6DOF Google Earth. GE didn’t give the user access to Cartesian coordinates (only lat/lon/height & HPR) so for 6DOF movements I had to convert HPR->rot mat->HPR every frame.

3 Likes

I have an if/else statement, on the else portion I’ve tried using the
Cesium.Transforms.headingPitchRollToFixedFrame
function instead, but could not get it to work. I wonder which is the case:
-I have a mis-conception of what it’s supposed to do.
-I’m not using it properly.
-It’s not working properly.

1 Like