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.