我试图更改已添加到基本体中并显示在铯控件/查看器中的圆柱体的长度或圆的extruddedHeight。例如这个圆柱体:
var length = 100;
var cylinderGeometry = new Cesium.CylinderGeometry({
length : length,
topRadius : cylinderradius,
bottomRadius : cylinderradius,
slices: cylinderslices,
vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
});
var cylinder = new Cesium.GeometryInstance({
geometry: cylinderGeometry,
modelMatrix: Cesium.Matrix4.multiplyByTranslation(
Cesium.Transforms.eastNorthUpToFixedFrame(ellipsoid.cartographicToCartesian(Cesium.Cartographic.fromDegrees(lon, lat))),
new Cesium.Cartesian3(0.0, 0.0, length * 0.5)),
attributes: {
color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED)
},
id: "Cylinder1"
});
var primitive = new Cesium.Primitive({
geometryInstances : cylinder ,
appearance : new Cesium.PerInstanceColorAppearance({
closed : false,
translucent: true,
flat: false,
faceForward: true
}),
allow3DOnly: true,
vertexCacheOptimize: true,
allowPicking: true,
releaseGeometryInstances: false
});
widget.scene.primitives.add(primitive);
由于已将其添加到基本数组,因此它将显示在小部件中,但是例如在2秒钟后,我收到一条通知,告知应将长度减半(即设置为50)。有什么办法吗?只是在
cylinderGeometry
中更改它似乎无法完成任务。我通过创建一个具有新高度的新圆柱体,添加它并移除旧圆柱体来使其工作。但是,这会在显示新的圆柱体之前使圆柱体闪烁(它消失了一秒钟)。我通过在添加新实例后的设置时间后删除旧实例来解决此问题。整个解决方案不是很好,并且在具有少量计算能力的设备上不能很好地工作,因此我寻求一个更好的解决方案。
我不在乎是否可以使用圆柱体或拉伸圆来实现。如果您需要更多信息,请随时在问题下方的评论中提问。
编辑
我实施了Matthew建议的第二个解决方案,但是在运行了一段时间之后,圆柱体停止了改变高度(这在我使用我的解决方案时并没有发生。间隔中的回调确实被调用了。下面的代码展示了我的新解决方案不管用):
primitives.add(prim);
window.nodeValuesInterval = setInterval(function () {
if (prim._state == Cesium.PrimitiveState.COMPLETE) {
clearInterval(window.nodeValuesInterval);
clearTimeout(window.nodeValuesTimeout);
primitives.remove(primitiveObjects.value);
primitiveObjects.value = prim;
}
}, cylindervalueinterval);
window.nodeValuesTimeout = setTimeout(function () {
clearInterval(window.nodeValuesInterval);
primitives.remove(primitiveObjects.value);
primitiveObjects.value = prim;
}, cylindervaluedelay);
最佳答案
Cesium的几何图形当前针对静态数据进行了优化。某些属性(例如可见性,颜色和材质)可以随时更改,但是实际修改几何图形(例如圆柱体高度)的项目要求您删除基元并重新计算几何图形。您所看到的闪烁是默认情况下启用异步基元创建的结果。有两种方法可以满足您的需求。
通过将[options.asynchronous: false
传递给Primitive
构造函数来禁用异步基元创建。这意味着,当您添加新的原语时,Cesium不会渲染,直到准备好为止。对于一个或两个对象,您不会注意到任何东西。对于许多对象,它将锁定浏览器,直到一切准备就绪。这确实保证您可以删除旧的/添加的新基元而不会闪烁。
第二种选择是添加新的原语(不删除旧的原语),然后在每一帧中,检查新的原语的_state
属性(我认为这是公共API的一部分,但显然不是)。当_state
等于Cesium.PrimitiveState.COMPLETE
时,您可以安全地删除旧基元,并保证将渲染新基元(因此不会闪烁)。
我认为我们有一个错误/功能请求,可以公开公开状态变量,或者以其他方式通知原始变量准备就绪;但是在可预见的将来使用_state
应该很好。如果我们在某个时候添加官方方式,我将更新此问题。
希望能有所帮助。
编辑:由于要求更多的帮助;这是一个完整的例子。您可以使用this link将以下代码复制并粘贴到Sandcastle中。
基本上,它使用scene.preRender事件而不是超时(在这里,preRender几乎总是更好的答案)。另外,如果在旧的更新完成之前收到新的更新,则在计算新的更新之前将其删除很重要。让我知道您是否仍然有问题。
require(['Cesium'], function(Cesium) {
"use strict";
var widget = new Cesium.CesiumWidget('cesiumContainer');
var ellipsoid = widget.scene.globe.ellipsoid;
var lon = 0;
var lat = 0;
var cylinderradius = 30000;
var length = 10000000;
var cylinderslices = 32;
var newPrimitive;
var currentPrimitive;
//This function creates a new cylinder that is half the length of the old one.
function decreaseLength() {
//If there's a pending primitive already, remove it.
if(Cesium.defined(newPrimitive)){
widget.scene.primitives.remove(newPrimitive);
}
length /= 2;
var cylinderGeometry = new Cesium.CylinderGeometry({
length : length,
topRadius : cylinderradius,
bottomRadius : cylinderradius,
slices: cylinderslices,
vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
});
var cylinder = new Cesium.GeometryInstance({
geometry: cylinderGeometry,
modelMatrix: Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(ellipsoid.cartographicToCartesian(Cesium.Cartographic.fromDegrees(lon, lat))),
new Cesium.Cartesian3(0.0, 0.0, length * 0.5)),
attributes: {
color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED)
},
id: "Cylinder1"
});
newPrimitive = new Cesium.Primitive({
geometryInstances : cylinder ,
appearance : new Cesium.PerInstanceColorAppearance({
closed : false,
translucent: true,
flat: false,
faceForward: true
}),
allow3DOnly: true,
vertexCacheOptimize: true,
allowPicking: true,
releaseGeometryInstances: false
});
//We add the new cylinder immediately, but don't remove the old one yet.
widget.scene.primitives.add(newPrimitive);
}
//Create the initial cylinder.
decreaseLength();
//Subscribe to the preRender event so we can check the primitive every frame.
widget.scene.preRender.addEventListener(function(scene, time) {
//Remove the old cylinder once the new one is ready.
if(Cesium.defined(newPrimitive) && newPrimitive._state === Cesium.PrimitiveState.COMPLETE){
if(Cesium.defined(currentPrimitive)){
widget.scene.primitives.remove(currentPrimitive);
}
currentPrimitive = newPrimitive;
newPrimitive = undefined;
}
});
Sandcastle.addToolbarButton('Decrease Length', decreaseLength);
Sandcastle.finishedLoading();
});