Cesium系列(3)--全景漫游(室内漫游)第一视角跟随
Cesium的全景漫游(室内漫游)第一视角跟随
Cesium的示例中是有漫游的示例。但是角度并不是第一视角。如下图:
在对于特殊的需求中,比如室内漫游。如果不是第一视角,漫游的过程中会被室内其他物体遮挡,效果不好,也不切实际。因此需要在此基础上进行修改,以达到好的效果。
实现
在实际应用中,漫游的路线是规划好的。也就是一系列的坐标点,然后根据坐标点插值计算,平滑运动。获取的方式很多种,看实际项目需求。我是事先选取好的点。
var myPositions = [
[109.05832893717263, 37.441496598851096],
[109.05855416786699, 37.44130123438769],
//...
[109.0587449465546, 37.44119249116668],
[109.05845600554856, 37.441396645980845],
];只有经纬度没有高度,因为我是把高度写死的,如果需要高度变化,是可以加上高度。
指定动画的起始时间,然后把 timeline 调整至起始时间,然后设置相关参数
var start = Cesium.JulianDate.fromDate(new Date(2015, 2, 25, 16));
var stop = Cesium.JulianDate.addSeconds(
start,
myPositions.length - 1,
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 = 0.3;
//Set timeline to simulation bounds
viewer.timeline.zoomTo(start, stop);开始时间是可以随意给定的,我这里给的是 new Date(2015, 2, 25,16)
结束时间这一点需要注意的是,根据数组的长度来定的。结束时间必须大于开始时间。var stop = Cesium.JulianDate.addSeconds(
start,
myPositions.length - 1,
new Cesium.JulianDate()
);设置动画的参数:clockRange 是播放模式 Cesium.ClockRange.LOOP_STOP 自动循环播放。multiplier 是播放的速度
根据坐标数组,计算插值点数据
function computeCirclularFlight() {
var property = new Cesium.SampledPositionProperty();
//设置插入选项
property.setInterpolationOptions({
// interpolationDegree: 1,
// interpolationAlgorithm: Cesium.LinearApproximation,
// interpolationDegree: 5,
// interpolationAlgorithm:
// Cesium.LagrangePolynomialApproximation,
interpolationDegree: 2,
interpolationAlgorithm: Cesium.HermitePolynomialApproximation,
});
for (var i = 0; i < myPositions.length; i++) {
var time = Cesium.JulianDate.addSeconds(
start,
i,
new Cesium.JulianDate()
);
var position = Cesium.Cartesian3.fromDegrees(
myPositions[i][0],
myPositions[i][1],
5
);
property.addSample(time, position);
}
return property;
}不同插值配置设置,得出来的结果是不同的,可以参照Cesium示例查看。
创建运动的物体,并把物体设置为镜头追踪的对象。
var position = computeCirclularFlight();
//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),
model: {
uri: './SampleData/models/CesiumAir/Cesium_Air.glb',
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.GREEN,
}),
width: 16,
},
});
//追踪物体
viewer.trackedEntity = entity;
每一帧根据物体的坐标和走向,设置相机的角度
//视角变换
var matrix3Scratch = new Cesium.Matrix3();
function getModelMatrix(entity, time, result) {
var position = Cesium.Property.getValueOrUndefined(
entity.position,
time,
new Cesium.Cartesian3()
);
if (!Cesium.defined(position)) {
return undefined;
}
var orientation = Cesium.Property.getValueOrUndefined(
entity.orientation,
time,
new Cesium.Quaternion()
);
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;
}
var scratch = new Cesium.Matrix4();
var renderListener = function (e) {
//viewer.camera.positionCartographic.height = 2000 + $this.limitCamera(f_property);
if (viewer.trackedEntity) {
getModelMatrix(viewer.trackedEntity, viewer.clock.currentTime, scratch);
var transformX = 90; //距离运动点的距离(后方)
var transformZ = 55; //距离运动点的高度(上方)
var transformY = 0; //距离运动点的高度(侧方)
viewer.scene.camera.lookAtTransform(
scratch,
new Cesium.Cartesian3(-transformX, transformY, transformZ)
);
}
};
viewer.scene.preRender.addEventListener(renderListener);监听事件中,transformX 是相机距离运动点的正后方距离。transformY 是相机距离运动点的侧方距离。transformZ 是相机距离运动点的上方距离。
开始播放的时候 需要把 shouldAnimate 打开, viewer.clock.shouldAnimate = true;
暂停播放 需要把 shouldAnimate 关闭, viewer.clock.shouldAnimate = false; 同时把镜头追踪对象去除 viewer.trackedEntity = undefined;
结果
室外轨迹漫游
调整角度参数 室内漫游
代码
完整代码都放到 github 上,需要的移步Cesium-demo-view