If you want to move camera on the orthogonal coordinate system, you can simply add camera position with a vector. Here is one way to do it:
camera.position = Cesium.Cartesian3.add(camera.position, new Cesium.Cartesian3(0, 0, moveRate), camera.position);
I modified the “right” flag in the example you posted in the sandcastle example below. You may scroll down to the very bottom of the code snippet to see where I changed. I did not bother to find the exact vector for “right”, but you can definetly use whatever 3D vector you want to replace the
new Cesium.Cartesian3(0, 0, moveRate)
And you will be able to see that pressing d
always moves the camera to the same direction (in the example the direction would be (0, 0, 1)), regardless the facing of the camera.
Now, if I understand the title correctly, you also want to keep the camera looking at an entity while moving on arbitrary directions. This is a bit more work; as far as I know, there is no simple build-in method. The build-in lookAt take a center and an offset vector, and does not really allow you to move the camera with arbitrary postion directly at the same time; but you may use the following function as I did:
// Author: Omar
function lookAt(camera, point) {
let direction = Cesium.Cartesian3.subtract(
point,
camera.position,
new Cesium.Cartesian3()
);
direction = Cesium.Cartesian3.normalize(direction, direction);
camera.direction = direction;
// get an "approximate" up vector, which in this case we want to be something like the geodetic surface normal.
const approxUp = Cesium.Cartesian3.normalize(
camera.position,
new Cesium.Cartesian3()
);
// cross viewdir with approxUp to get a right normal
let right = Cesium.Cartesian3.cross(
direction,
approxUp,
new Cesium.Cartesian3()
);
Cesium.Cartesian3.normalize(right, right);
camera.right = right;
// cross right with view dir to get an orthonormal up
const up = Cesium.Cartesian3.cross(
right,
direction,
new Cesium.Cartesian3()
);
camera.up = up;
}
I am not the original author of the code above; the original author is @omar, and you can find the original discussion here.
The code is very simple and straight forward if you have some basic graphic knowledge; one thing you might need to consider is that if your camera direction is very close to parallel to the “approxUp” vector (namely when the entity, the camera and the earth are on the same line), which I expect to be a rare situation and should simply be taken care by halting the function. Another thing is that since you are already moving on orthogonal directions, you probably do not care about the earth postion at all. In which case you may need to replace the “approxUp” vector with some fixed “universalUp” vector. I did not actually try this though. With thses being taken care of, you should hopefully get something similar to the lookAt()
function of three.js
.
If you do not have a point from the entity you want to focus, here is a solution. You can first get its bounding sphere with following code:
let b = new Cesium.BoundingSphere()
viewer.dataSourceDisplay.getBoundingSphere(entity, false, b)
Notice this getBoundingSphere
function is not well documented since it was initially a private function; it may not write the bounding sphere to the object you passed in right away, and neither does it return a promise. I’ve suffered through this and you may look at this.
Now you have the bounding sphere, the center point is just b.center
, passing this center point (or whatever Cartesian3 point you want to focus on) and your camera to your version of lookAt()
function should set the camera to look at the desired point. All you need to do is just call this function every time after the camera is moved to a new position.
However, with the method above, if the step size for translation is relatively large, you would see a lot of glitch when the camera is turning. If you want a smooth turning, you might want to take a look at eventListeners that trigger on every frame, for example, Cesium.Clock.onTick
event.