在cesium中实现键盘监听控制飞机的heading pitch roll
主要参考例子:
https://sandcastle.cesium.com/index.html?src=HeadingPitchRoll.html
上述例子中的第一人称视角处理有纰漏,改进后的效果和实现的代码如下:
let canvas = viewer.canvas;
canvas.setAttribute("tabindex", "0"); // needed to put focus on the canvas
canvas.addEventListener("click", function () {
canvas.focus();
});
canvas.focus();
let scene = viewer.scene;
let pathPosition = new SampledPositionProperty();
this.planePath = viewer.entities.add({
id: "keyboardDemoPlanePath",
position: pathPosition,
// name: "path",
path: {
show: true,
leadTime: 0,
trailTime: 60,
width: 10,
resolution: 1,
material: new PolylineGlowMaterialProperty({
glowPower: 0.3,
taperPower: 0.3,
color: Color.PALEGOLDENROD
})
}
});
let camera = viewer.camera;
let controller = scene.screenSpaceCameraController;
let r = 0;
let center = new Cartesian3();
let hpRoll = new HeadingPitchRoll();
let hpRange = new HeadingPitchRange();
let speed = 1;
let deltaRadians = _Math.toRadians(3.0);
let position = Cartesian3.fromDegrees(
114.4152843,
30.512368,
5000.0
);
let speedVector = new Cartesian3();
let fixedFrameTransform = Transforms.localFrameToFixedFrameGenerator(
"north",
"west"
);
let planePrimitive = scene.primitives.add(
Model.fromGltf({
url: `${
webSetting.assetsUrl}/map/su30.gltf`,
// url: `${webSetting.assetsUrl}/map/apaqi_x-90_y180.glb`,
modelMatrix: Transforms.headingPitchRollToFixedFrame(
position,
hpRoll,
Ellipsoid.WGS84,
fixedFrameTransform
),
minimumPixelSize: 256
})
);
this.plane = planePrimitive;
planePrimitive.readyPromise.then(function (model) {
// Play and loop all animations at half-speed
model.activeAnimations.addAll({
multiplier: 0.5,
loop: ModelAnimationLoop.REPEAT
});
// Zoom to model
r = 2.0 * Math.max(model.boundingSphere.radius, camera.frustum.near);
controller.minimumZoomDistance = r * 0.5;
Matrix4.multiplyByPoint(
model.modelMatrix,
model.boundingSphere.center,
center
);
let heading = _Math.toRadians(230.0);
let pitch = _Math.toRadians(-20.0);
hpRange.heading = heading;
hpRange.pitch = pitch;
hpRange.range = r * 50.0;
camera.lookAt(center, hpRange);
});
this.keyBoardListener = function (e) {
switch (e.keyCode) {
case 40:
if (e.shiftKey) {
// speed down
speed -= 10;
speed = Math.max(speed, 1);
} else {
// pitch down
hpRoll.pitch -= deltaRadians;
if (hpRoll.pitch < -_Math.TWO_PI) {
hpRoll.pitch += _Math.TWO_PI;
}
}
break;
case 38:
if (e.shiftKey) {
// speed up
speed += 10;
speed = Math.min(speed, 1000);
} else {
// pitch up
hpRoll.pitch += deltaRadians;
if (hpRoll.pitch > _Math.TWO_PI) {
hpRoll.pitch -= _Math.TWO_PI;
}
}
break;
case 39:
if (e.shiftKey) {
// roll right
hpRoll.roll += deltaRadians;
if (hpRoll.roll > _Math.TWO_PI) {
hpRoll.roll -= _Math.TWO_PI;
}
} else {
// turn right
hpRoll.heading += deltaRadians;
if (hpRoll.heading > _Math.TWO_PI) {
hpRoll.heading -= _Math.TWO_PI;
}
}
break;
case 37:
if (e.shiftKey) {
// roll left until
hpRoll.roll -= deltaRadians;
if (hpRoll.roll < 0.0) {
hpRoll.roll += _Math.TWO_PI;
}
} else {
// turn left
hpRoll.heading -= deltaRadians;
if (hpRoll.heading < 0.0) {
hpRoll.heading += _Math.TWO_PI;
}
}
break;
default:
break;
}
};
document.addEventListener("keydown", this.keyBoardListener);
let headingSpan = document.getElementById("heading");
let pitchSpan = document.getElementById("pitch");
let rollSpan = document.getElementById("roll");
let speedSpan = document.getElementById("speed");
let fromBehind = document.getElementById("fromBehind");
this.preUpateSpeedViewFunc = (scene, time) => {
speedVector = Cartesian3.multiplyByScalar(
Cartesian3.UNIT_X,
speed / 10,
speedVector
);
// let lastPosition = position.clone();
position = Matrix4.multiplyByPoint(
planePrimitive.modelMatrix,
speedVector,
position
);
this.center = position;
// pathPosition.addSample(JulianDate.now(), position);
pathPosition.addSample(time, position);
// console.log("adding: t->p: ", JulianDate.now().toString(), " -> ",position.toString());
Transforms.headingPitchRollToFixedFrame(
position,
hpRoll,
Ellipsoid.WGS84,
fixedFrameTransform,
planePrimitive.modelMatrix
);
// view at fisrt player
if (this.fpsFlag) {
// Zoom to model
Matrix4.multiplyByPoint(
planePrimitive.modelMatrix,
planePrimitive.boundingSphere.center,
center
);
hpRange.heading = hpRoll.heading;
hpRange.pitch = hpRoll.pitch;
hpRange.range = camera.frustum.near * 0.05;
// mainly using this to set the camera position relatively to the plane
camera.lookAt(center, hpRange);
camera.moveForward(8.2);
camera.moveLeft(2.65);
camera.moveUp(0.7);
// console.log("cur camera hpr is: ",camera.heading, " ", camera.pitch, " ", camera.roll,
// "hpRoll's hpr is ", hpRoll.heading, " ", hpRoll.pitch, " ", hpRoll.roll, " ");
// set the hpr according to the hpr of the plane
camera.setView({
orientation: {
heading : hpRoll.heading, // east, default value is 0.0 (north)
pitch : hpRoll.pitch, // default value (looking down)
roll : hpRoll.roll // default value
}
});
}
};
viewer.scene.preUpdate.addEventListener(this.preUpateSpeedViewFunc, this);
this.preUpateHPRFunc = (scene, time) => {
this.headingShow = _Math.toDegrees(hpRoll.heading).toFixed(2);
this.pitchShow = _Math.toDegrees(hpRoll.pitch).toFixed(2);
this.rollShow = _Math.toDegrees(hpRoll.roll).toFixed(2);
this.speedShow = speed.toFixed(2);
let tmp = Cartographic.fromCartesian(this.center, Ellipsoid.WGS84);
this.planeLon = tmp.longitude.toFixed(2);
this.planeLat = tmp.latitude.toFixed(2);
this.planeHei = tmp.height.toFixed(2);
};
viewer.scene.preRender.addEventListener(this.preUpateHPRFunc, this);
});
}