I'm trying to have the camera follow a model with a SampledPositionProperty and have all camera position and orientation modifications use the current model position as the reference frame. This is partially functional, as the reference frame can easily be set each clock tick with a lookAtTransform at the current position.
The issue I'm having is that the axis still seem to be based on the globe, where even if the orientation of the model is changed the axis are stationary based on the globe. Is there any workaround for this that I'm not seeing?
Thanks in advance,
Alfredo
Sandcastle code modified from an example that shows what I described above :
Essentially, the green polyline always points towards the north pole, the blue away from the center of the globe, and the red to the east. Ideally I'd like to have those directions change with the orientation of the plane, e.g. the red line would extend from the nose of the plane no matter the orientation with the other lines placed relative to that.
var viewer = new Cesium.Viewer('cesiumContainer', {
terrainProviderViewModels : [], //Disable terrain changing
infoBox : false, //Disable InfoBox widget
selectionIndicator : false //Disable selection indicator
});
//Enable lighting based on sun/moon positions
viewer.scene.globe.enableLighting = true;
//Use STK World Terrain
viewer.terrainProvider = new Cesium.CesiumTerrainProvider({
url : '//cesiumjs.org/stk-terrain/world',
requestWaterMask : true,
requestVertexNormals : true
});
//Enable depth testing so things behind the terrain disappear.
viewer.scene.globe.depthTestAgainstTerrain = true;
//Set the random number seed for consistent results.
Cesium.Math.setRandomNumberSeed(3);
//Set bounds of our simulation time
var start = Cesium.JulianDate.fromDate(new Date(2015, 2, 25, 16));
var stop = Cesium.JulianDate.addSeconds(start, 360, new Cesium.JulianDate());
//Make sure viewer is at the desired time.
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; //Loop at the end
viewer.clock.multiplier = 10;
//Set timeline to simulation bounds
viewer.timeline.zoomTo(start, stop);
//Generate a random circular pattern with varying heights.
function computeCirclularFlight(lon, lat, radius) {
var property = new Cesium.SampledPositionProperty();
for (var i = 0; i <= 360; i += 45) {
var radians = Cesium.Math.toRadians(i);
var time = Cesium.JulianDate.addSeconds(start, i, new Cesium.JulianDate());
var position = Cesium.Cartesian3.fromDegrees(lon + (radius * 1.5 * Math.cos(radians)), lat + (radius * Math.sin(radians)), Cesium.Math.nextRandomNumber() * 500 + 1750);
property.addSample(time, position);
//Also create a point for each sample we generate.
viewer.entities.add({
position : position,
point : {
pixelSize : 8,
color : Cesium.Color.TRANSPARENT,
outlineColor : Cesium.Color.YELLOW,
outlineWidth : 3
}
});
}
return property;
}
//Compute the entity position property.
var position = computeCirclularFlight(-112.110693, 36.0994841, 0.03);
//Actually create the entity
var entity = viewer.entities.add({
//Set the entity availability to the same interval as the simulation time.
availability : new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({
start : start,
stop : stop
})]),
//Use our computed positions
position : position,
//Automatically compute orientation based on position movement.
orientation : new Cesium.VelocityOrientationProperty(position),
//Load the Cesium plane model to represent the entity
model : {
uri : '../../SampleData/models/CesiumAir/Cesium_Air.gltf',
minimumPixelSize : 64
},
//Show the path as a pink line sampled in 1 second increments.
path : {
resolution : 1,
material : new Cesium.PolylineGlowMaterialProperty({
glowPower : 0.1,
color : Cesium.Color.YELLOW
}),
width : 10
}
});
var prim = undefined;
viewer.clock.onTick.addEventListener(function(clock) {
viewer.scene.primitives.remove(prim);
var referencePoint = position.getValue(clock.currentTime);
var transform = Cesium.Transforms.eastNorthUpToFixedFrame(referencePoint, new Cesium.Ellipsoid(500, 500, 500));
prim = viewer.scene.primitives.add(new Cesium.DebugModelMatrixPrimitive({
modelMatrix : transform,
length : 10000.0,
}));
viewer.camera.lookAtTransform(transform, viewer.camera.position.clone());
});
The lookAtTransform controls how the camera rotates around a point and does not affect the angle at which a camera is viewing the point. If you want to lock the view to a given angle, then camera.lookAt each frame is what would be used. You might also find some value in looking at the Monster Milk Truck. https://github.com/AnalyticalGraphicsInc/cesium-google-earth-examples/blob/master/demos/milktruck/milktruck.js.
var matrix3Scratch = new Cesium.Matrix3();
var positionScratch = new Cesium.Cartesian3();
var orientationScratch = new Cesium.Quaternion();
function getModelMatrix(entity, time, result) {
var position = Cesium.Property.getValueOrUndefined(entity.position, time, positionScratch);
if (!Cesium.defined(position)) {
return undefined;
}
var orientation = Cesium.Property.getValueOrUndefined(entity.orientation, time, orientationScratch);
if (!Cesium.defined(orientation)) {
result = Cesium.Transforms.eastNorthUpToFixedFrame(position, undefined, result);
} else {
result = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromQuaternion(orientation, matrix3Scratch), position, result);
}
return result;
}
function getHeading(matrix, ellipsoid) {
var position = Cesium.Matrix4.getTranslation(matrix, new Cesium.Cartesian3());
var transform = Cesium.Transforms.eastNorthUpToFixedFrame(position, ellipsoid);
Cesium.Matrix3.transpose(transform, transform);
var right = Cesium.Cartesian3.fromCartesian4(Cesium.Matrix4.getColumn(matrix, 0, new Cesium.Cartesian4()));
var direction = Cesium.Cartesian3.fromCartesian4(Cesium.Matrix4.getColumn(matrix, 1, new Cesium.Cartesian4()));
Cesium.Matrix3.multiplyByVector(transform, right, right);
Cesium.Matrix3.multiplyByVector(transform, direction, direction);
var heading = Math.atan2(right.y, right.x);
return Cesium.Math.TWO_PI - Cesium.Math.zeroToTwoPi(heading);
}
var CAM_HEIGHT = 0;
var TRAILING_DISTANCE = 100;
var PITCH = Cesium.Math.toRadians(0);
var RANGE = Cesium.Cartesian3.magnitude(new Cesium.Cartesian3(TRAILING_DISTANCE, 0.0, CAM_HEIGHT));
function cameraFollow(time, entity) {
var camera = viewer.scene.camera;
var modelMatrix = getModelMatrix(entity, time, new Cesium.Matrix4());
var position = Cesium.Matrix4.getTranslation(modelMatrix, new Cesium.Cartesian3());
var heading = Cesium.Math.zeroToTwoPi(getHeading(modelMatrix, Cesium.Ellipsoid.WGS84) + Cesium.Math.PI_OVER_TWO);
camera.lookAt(position, new Cesium.HeadingPitchRange(heading, PITCH, RANGE));
}
viewer.clock.onTick.addEventListener(function(clock) {
cameraFollow(clock.currentTime, entity);
});Essentially the function I'm trying to build is a mixture of both your posted code and mine. I'd like to have the camera act as a chase cam, like in the milk truck example, but still have the ability to manipulate the camera position like in mine. The end result would be a camera using the model as the focal point with the ability to move the camera around this point without any of the swinging or other observed changes that come with the change of the model's orientation.
What I am trying to accomplish is basically the camera movement around the model seen in my code, with the constant orientation of the reference frame seen in yours. I've been trying to work around this for a while now, and haven't made much progress. I can do one or the other, but trying to combine the two hasn't worked thus far.
Also, I just noticed that the example Sandcastle code that you posted still rotates with the orientation of the model, albeit less so than in what I've got working. What I'm looking for is essentially treating the model as the globe, where the camera's reference frame is constant, eg when crossing from one side of the pole to the other there isn't any swinging of the axis. I've got a few ideas and I'll continue to brainstorm a bit over the weekend, and I'll update this thread if I get anything working. Thanks again for your input.
That is pretty much what I've been trying to work from, just looking through the trackedEntity behavior and trying to modify it to fit my needs. The same issue is still present, though. The base coordinate frame still persists, so the "up" direction for the entity is still based on the "up" direction of the globe. This means that any time the entity crosses the poles, for example, there is a swinging sort of camera motion without any programmatic or input based camera change. For example, if you position the camera trailing the model, when it crosses one of the Earth's poles the camera will be repositioned ahead of the model. Here is a link to a Gyazo showing this.
http://gyazo.com/acfca5e2bd8031ea078aeb3c9e9974e2
--
You received this message because you are subscribed to the Google Groups "cesium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cesium-dev+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.