I'm trying to create the effect of a FPS (first person shooter) game view, where WASD are used to move forward/back/felt/right, and mouse controls where the camera is looking.
I played with the "Camera Tutorial", however that's not the entire effect I'm looking for. Two things I can't figure out:
1. I need the camera to always be a constant height, and not move upwards if the viewer is looking upwards. The current way the Camera Tutorial is set up is forward/back directions moves in the direction of the heading and pitch direction. I only want the camera to move in the heading direction, and ignore the pitch component.
Is that possible?
2. The camera (user) will be walking/exploring through a 3d object (gltf/b3dm) environment, and I need the camera to follow the contour of the 3d object.
How does one set the camera height to always be a certain distance from the mesh beneath it?
Are there any existing examples I can look at to find a resolutions to my questions?
The moveForward will move a camera in the direction it’s facing. If you just want to translate the camera’s position along a given direction, you can use move instead. You can read the camera’s heading/pitch/roll and use what you need to compute this direction.
For the camera height, this might be a bit tricky, because it sounds like the camera will be inside the 3D model. Does the model have a ceiling where you’re trying to sample the height?
Thank you for the suggestions Omar.
Using "move" solved my problem.
As for my second point, currently the camera is not inside the model (there's no ceiling), but I'll be working with models with a ceiling very soon.
The functionality in the "pick ray" from Gabby's post is exactly what I'm looking for.
Will the "pick ray" approach work when the object is inside the 3d model?
Exploring the inside of a 3D model like that in Cesium sounds really cool, what kind of application is this for? I’d definitely love to see it once it comes together!
This should take the pitch out of camera forward. It’s converted from my own code which uses my math library so I tried to use the equivalent Cesium math functions in this conversion. Let me know if this works, this conversion is untested. If it doesn’t work I’ll try debugging it to get a working version.
EDIT: this code replaced by another approach in follow up posts.
var GD_transform = Cesium.Transforms.eastNorthUpToFixedFrame(viewer.scene.camera.position, viewer.scene.globe.ellipsoid, new Cesium.Matrix4());
var GD_rotmat=new Matrix3();
Cesium.Matrix4.getMatrix3(GD_transform,GD_rotmat);
var camDir=new Cesium.Cartesian3();
Cesium.Matrix3.multiplyByVector(GD_rotmat, viewer.scene.camera.direction, camDir);
camDir.z=0;Cesium.Cartesian3.normalize(camdir,camdir);
Cesium.Matrix3.multiplyByScale(GD_rotmat, camDir, camDir);
CamDir should now face the same azimuth as the camera, but will not have the same pitch as the camera, rather be level with the horizon.
Regarding moving along sloped terrain: Instead of moving parallel with the slope, you could move level, then bump the camera up or down to follow the slope. Getting the direction along a sloped surface in any azimuth direction would be tricky to do, though I might be able to do it given the normal of the tile, just project the direction vector onto the tile. EDIT: ya, with just a dot,scale,subtract.
Bah, that method is overkill, transforming components that don’t need transforming. A better way would be:
-Get ‘up vector’ directly from GD_transform.
-Dot the up vector with camera.direction and save that to tempScale.
-Scale the up vector with tempScale and save that to tempVect.
-Then just subtract tempVect from from camera.position.
EDIT: this code is faulty, check updated code in a followup post
var GD_transform = Cesium.Transforms.eastNorthUpToFixedFrame(viewer.scene.camera.position, viewer.scene.globe.ellipsoid, new Cesium.Matrix4());
var up = new Cesium.Cartesian3(GD_transform[8],GD_transform[9],GD_transform[10]);
tempScale = Cesium.Cartesian3.dot(up,viewer.scene.camera.direction);
tempVect = Cesium.Cartesian3.multiplyByScalar(up,tempScale);
viewer.scene.camera.direction = Cesium.Cartesian3.subtract(viewer.scene.camera.direction,tempVect );
Same thing can be done with a normal to a surface that is not flat, just substitute up with the normal.
Thank you, I will try it.
But strange that such a simple use case (same feature as when you drag mouse from top to bottom) need complicated code, why cesium team didn’t implement a ‘moveForward(pitch)’ api .
I forgot to mention that you shouldn’t change camera.direction without also changing camera.up and camera.right to keep them all orthogonal with each other. That last line should be something like:
var moveDir = Cesium.Cartesian3.subtract(viewer.scene.camera.direction,tempVect );
Then move in the direction of moveDir, then this will also not mess up your pitch view of the camera.
I forgot that Cesium’s multiply by scalar needs a third parameter for result. Try this:
var GD_transform = Cesium.Transforms.eastNorthUpToFixedFrame(viewer.scene.camera.position, viewer.scene.globe.ellipsoid, new Cesium.Matrix4());
var up = new Cesium.Cartesian3(GD_transform[8],GD_transform[9],GD_transform[10]);
tempScale = Cesium.Cartesian3.dot(up,viewer.scene.camera.direction);
tempVect = Cesium.Cartesian3.multiplyByScalar(up,tempScale,new Cesium.Cartesian3());
moveDir = Cesium.Cartesian3.subtract(viewer.scene.camera.direction,tempVect,new Cesium.Cartesian3() );
You’re welcome, anytime! Glad it worked. If the camera were to roll you could also use this code to factor out the vertical component of camera.right as well for lateral movement. If you can find the normal of the surface you’re walking on just replace up with that normal vector in this code to walk along the slope.