更改圆柱体的长度或圆形的挤出高度

时间:2014-07-01 09:21:43

标签: javascript cesium

当我将圆圈的长度或圆形的挤出高度添加到基元并在cesium小部件/查看器中显示时,我试图改变它的长度。例如这个圆柱体:

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);

1 个答案:

答案 0 :(得分:1)

Cesium的几何体目前针对静态数据进行了优化。某些属性(如可见性,颜色和材质)可以动态更改,但实际修改几何体的项(如柱面高度)要求您删除基元并重新计算几何体。您看到的闪烁是默认情况下启用异步基元创建的结果。有两种方法可以让你想要。

  1. 通过将[options.asynchronous: false传递给Primitive构造函数来禁用异步原语创建。这意味着当您添加新基元时,Cesium在准备好之前不会渲染。对于一个或两个对象,您将不会注意到任何事物。对于许多对象,它将锁定浏览器,直到一切准备就绪。这确保您可以在没有任何闪烁的情况下删除旧的/添加新原语。

  2. 第二个选项是添加新原语(不删除旧原语)然后每帧,检查新原语的_state属性(我认为这是公共API的一部分但是显然它不是)。当_state等于Cesium.PrimitiveState.COMPLETE时,您可以安全地删除旧基元,并保证新基元将呈现(因此不会闪烁)。

  3. 我认为我们有一个错误/功能请求公开公开状态变量,或者在Primitive准备就绪时通知;但是对于可预见的未来,使用_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();
    });