cesium 使用Primitive实现DynamicRiver,并给出详细代码
时间: 2024-03-17 21:42:51 浏览: 176
好的,下面是一个完整的示例代码,演示如何使用 Cesium 的 Primitive 实现一个动态的河流。这个河流由多个小段组成,每个小段都是一个 PolylinePrimitive,通过改变每个小段的位置和纹理坐标,来实现河流的动态效果。代码如下:
```javascript
var viewer = new Cesium.Viewer('cesiumContainer');
// 创建一个河道路径
var positions = [
Cesium.Cartesian3.fromDegrees(-100.0, 40.0),
Cesium.Cartesian3.fromDegrees(-90.0, 40.0),
Cesium.Cartesian3.fromDegrees(-80.0, 35.0),
Cesium.Cartesian3.fromDegrees(-70.0, 30.0),
Cesium.Cartesian3.fromDegrees(-60.0, 30.0),
Cesium.Cartesian3.fromDegrees(-50.0, 35.0),
Cesium.Cartesian3.fromDegrees(-40.0, 40.0)
];
// 创建一个 Material,表示水的外观
var material = new Cesium.WaterMaterial({
baseWaterColor: new Cesium.Color(0.0, 0.3, 0.8, 0.8),
normalMap: './assets/images/waterNormals.jpg',
frequency: 10000.0,
animationSpeed: 0.01,
amplitude: 10.0
});
// 创建一个 Primitive,表示河流
var river = new Cesium.Primitive({
geometryInstances : new Cesium.GeometryInstance({
geometry : new Cesium.PolylineGeometry({
positions : positions,
width : 5.0
}),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.WHITE)
}
}),
appearance : new Cesium.PolylineMaterialAppearance({
material : material
})
});
// 将河流添加到场景中
viewer.scene.primitives.add(river);
// 创建一些小段,用来实现动态效果
var segmentCount = 100;
var segmentLength = 1000.0; // 每个小段的长度
var segmentPositions = [];
var segmentTextureCoords = [];
for (var i = 0; i < segmentCount; i++) {
// 计算当前小段的起点和终点
var start = positions[i];
var end = positions[i + 1];
var direction = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()), new Cesium.Cartesian3());
var length = Cesium.Cartesian3.distance(start, end);
// 将当前小段分成若干个点
var pointCount = Math.ceil(length / segmentLength);
var step = length / pointCount;
for (var j = 0; j < pointCount; j++) {
var t = j / (pointCount - 1);
var position = Cesium.Cartesian3.add(start, Cesium.Cartesian3.multiplyByScalar(direction, j * step, new Cesium.Cartesian3()), new Cesium.Cartesian3());
segmentPositions.push(position);
// 计算当前点的纹理坐标
var s = i / (segmentCount - 1);
var v = j / (pointCount - 1);
segmentTextureCoords.push(new Cesium.Cartesian2(s, v));
}
}
// 创建小段的 Geometry 和 Appearance
var segmentGeometry = new Cesium.PolylineGeometry({
positions : segmentPositions,
width : 5.0,
vertexFormat : Cesium.VertexFormat.POSITION_AND_ST
});
var segmentAppearance = new Cesium.PolylineMaterialAppearance({
material : material
});
// 创建每个小段的 Primitive
var segmentPrimitives = [];
for (var i = 0; i < segmentCount - 1; i++) {
var start = i * pointCount;
var end = (i + 1) * pointCount - 1;
var segmentInstance = new Cesium.GeometryInstance({
geometry : segmentGeometry,
attributes : {
st : new Cesium.GeometryInstanceAttribute({
componentDatatype : Cesium.ComponentDatatype.FLOAT,
componentsPerAttribute : 2,
values : Cesium.Cartesian2.packArray(segmentTextureCoords.slice(start, end))
})
}
});
var segmentPrimitive = new Cesium.Primitive({
geometryInstances : segmentInstance,
appearance : segmentAppearance
});
segmentPrimitives.push(segmentPrimitive);
}
// 将每个小段的 Primitive 添加到场景中
for (var i = 0; i < segmentPrimitives.length; i++) {
viewer.scene.primitives.add(segmentPrimitives[i]);
}
// 控制水流速度和方向的代码
var startTime = Cesium.JulianDate.now();
var speed = 0.01;
var direction = new Cesium.Cartesian3(-1.0, 0.0, 0.0);
viewer.clock.onTick.addEventListener(function(clock) {
// 计算时间差
var time = Cesium.JulianDate.secondsDifference(clock.currentTime, startTime);
// 设置 Material 的时间和流速
material.time = time;
material.speed = speed;
// 计算水流的方向
var rotation = Cesium.Matrix3.fromRotationZ(time * speed);
var rotatedDirection = Cesium.Matrix3.multiplyByVector(rotation, direction, new Cesium.Cartesian3());
material.flowDirection = rotatedDirection;
// 更新每个小段的纹理坐标
for (var i = 0; i < segmentPrimitives.length; i++) {
var instance = segmentPrimitives[i].geometryInstances.get(0);
var st = instance.attributes.st.values;
var start = i * pointCount;
var end = (i + 1) * pointCount - 1;
for (var j = start; j <= end; j++) {
var v = (j - start) / (pointCount - 1);
st[j * 2 + 1] = st[j * 2 + 1] + speed * v;
}
instance.attributes.st.values = st;
}
});
```
上面的代码首先创建了一个河道路径,然后创建了一个 WaterMaterial 对象,表示水的外观。接着,将 PolylineGeometry 和 PolylineMaterialAppearance 对象作为参数,创建了一个 Primitive 对象,表示河流。最后,将这个 Primitive 添加到场景中。
接着,创建了一些小段,用来实现动态效果。首先计算每个小段的起点和终点,然后将每个小段分成若干个点,计算每个点的位置和纹理坐标。然后,分别创建每个小段的 Geometry 和 Appearance,用来表示小段的形状和外观。最后,将每个小段的 Geometry 和 Appearance 组合成一个 Primitive,表示一个小段,然后将所有的小段添加到场景中。
接着,使用 Cesium 的时钟对象来控制水流的速度和流向。在每一帧的时候,计算当前时间和开始时间的差值,然后将这个差值作为参数,设置 Material 的时间,就可以让水的纹理动起来了。同时,可以通过改变 Material 的 speed 属性,来控制水流的速度。最后,计算一个旋转矩阵,用来旋转水流的方向,然后将这个方向向量作为 Material 的 flowDirection 属性,就可以控制水流的流向了。同时,更新每个小段的纹理坐标,使得河流看起来是在动态变化的。
阅读全文