Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-render when adding/removing primitives in requestRenderMode #6734

Open
chris-cooper opened this issue Jun 27, 2018 · 9 comments
Open

Re-render when adding/removing primitives in requestRenderMode #6734

chris-cooper opened this issue Jun 27, 2018 · 9 comments

Comments

@chris-cooper
Copy link
Contributor

In the development/Polylines On Terrain sandcastle example, if you initialize the viewer with...

var viewer = new Cesium.Viewer('cesiumContainer', {
    terrainProvider: worldTerrain,
    requestRenderMode: true,
});

The "Toggle instance show" button stops working after initial render.

In an app this prevents these polylines from initially appearing even if you requestRender() when adding the geometry.

@likangning93
Copy link
Contributor

This is expected behavior when using the Primitive API instead of the Entity API, as per the requestRenderMode documentation:

When true, rendering a frame will only occur when needed as determined by changes within the scene.
Enabling improves performance of the application, but requires using {@link Scene#requestRender}
to render a new frame explicitly in this mode. This will be necessary in many cases after making changes
to the scene in other parts of the API.

The view updates to the current state on camera move or if the timeline is playing. You can also explicitly call Scene.RequestRender on the button/menu handlers:

var worldTerrain = Cesium.createWorldTerrain({
    requestWaterMask: true,
    requestVertexNormals: true
});

var viewer = new Cesium.Viewer('cesiumContainer', {
    terrainProvider: worldTerrain,
    requestRenderMode: true,
});

if (!Cesium.GroundPolylinePrimitive.isSupported(viewer.scene)) {
    throw new Cesium.RuntimeError('Polylines on terrain are not supported on this platform.');
}

var polylineIds = ['polyline1', 'polyline2'];
var groundPrimitiveId = 'ground primitive';
var selectedId = polylineIds[0];
var polylineOnTerrainPrimitive;
var groundPrimitiveOnTop = false;

var lineWidth = 4.0;
var viewModel = {
    lineWidth : lineWidth
};

Cesium.knockout.track(viewModel);

var toolbar = document.getElementById('toolbar');
Cesium.knockout.applyBindings(viewModel, toolbar);

Cesium.knockout.getObservable(viewModel, 'lineWidth').subscribe(
    function(newValue) {
        lineWidth = parseFloat(viewModel.lineWidth);
        if (Cesium.defined(selectedId)) {
            var attributes = polylineOnTerrainPrimitive.getGeometryInstanceAttributes(selectedId);
            lineWidth = parseFloat(viewModel.lineWidth);
            attributes.width = [lineWidth];
        }
    }
);

var scene = viewer.scene;

// Add a Rectangle GroundPrimitive to demonstrate Z-indexing with GroundPrimitives
var rectangleGroundPrimitive = scene.groundPrimitives.add(new Cesium.GroundPrimitive({
    geometryInstances : new Cesium.GeometryInstance({
        geometry : new Cesium.RectangleGeometry({
            rectangle : Cesium.Rectangle.fromDegrees(-112.1340164450331, 36.05494287836128, -112.0840164450331, 36.10494287836128),
            vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT
        }),
        id : groundPrimitiveId
    }),
    appearance : new Cesium.EllipsoidSurfaceAppearance({
        aboveGround : false,
        material : Cesium.Material.fromType('Color')
    }),
    classificationType : Cesium.ClassificationType.TERRAIN
}));

var leftHandler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
leftHandler.setInputAction(function(movement) {
    var pickedObject = viewer.scene.pick(movement.position);
    if (Cesium.defined(pickedObject)) {
        console.log(pickedObject.id);
        // If picked the ground primitive, don't do anything
        if (pickedObject.id !== groundPrimitiveId) {
            selectedId = pickedObject.id;

            // Sync line width in toolbar with selected
            var attributes = polylineOnTerrainPrimitive.getGeometryInstanceAttributes(selectedId);
            viewModel.lineWidth = attributes.width[0];
        }
    } else {
        selectedId = undefined;
    }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

var polylinePositions = Cesium.Cartesian3.fromDegreesArray([
    -112.1340164450331, 36.05494287836128,
    -112.08821010582645, 36.097804071380715,
    -112.13296079730024, 36.168769146801104,
    -112.10828895143331, 36.20031318533197,
    -112.138548165717, 36.1691100215289, // hairpins
    -112.11482556496543, 36.20127524083297,
    -112.15921333464016, 36.17876011207708,
    -112.14700151155604, 36.21683132404626,
    -112.20919883052926, 36.19475754001766
]);

var loopPositions = Cesium.Cartesian3.fromDegreesArray([
    -111.94500779274114, 36.27638678884143,
    -111.90983004392696, 36.07985366173454,
    -111.80360100637773, 36.13694878292542,
    -111.85510122419183, 36.26029588763386,
    -111.69141601804614, 36.05128770351902
]);

function createPolylines(debugShowShadowVolume) {
    var instance1 = new Cesium.GeometryInstance({
        geometry : new Cesium.GroundPolylineGeometry({
            positions : polylinePositions,
            loop : false,
            width : 4.0
        }),
        id : polylineIds[0],
        attributes : {
            show : new Cesium.ShowGeometryInstanceAttribute(),
            color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString('green').withAlpha(0.7))
        }
    });

    var instance2 = new Cesium.GeometryInstance({
        geometry : new Cesium.GroundPolylineGeometry({
            positions : loopPositions,
            loop : true,
            width : 8.0
        }),
        id : polylineIds[1],
        attributes : {
            show : new Cesium.ShowGeometryInstanceAttribute(),
            color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString('#67ADDF').withAlpha(0.7))
        }
    });

    polylineOnTerrainPrimitive = new Cesium.GroundPolylinePrimitive({
        geometryInstances : [instance1, instance2],
        debugShowShadowVolume : debugShowShadowVolume
    });
    scene.groundPrimitives.add(polylineOnTerrainPrimitive);
}

function applyPerInstanceColor() {
    polylineOnTerrainPrimitive.appearance = new Cesium.PolylineColorAppearance();
}
function applyColorMaterial() {
    polylineOnTerrainPrimitive.appearance = new Cesium.PolylineMaterialAppearance({
        material : Cesium.Material.fromType('Color', {
            color : new Cesium.Color(0.7, 0.0, 1.0, 1.0)
        })
    });
}
function applyGlowMaterial() {
    polylineOnTerrainPrimitive.appearance = new Cesium.PolylineMaterialAppearance({
        material : Cesium.Material.fromType('PolylineGlow', {
            innerWidth : 1.0
        })
    });
}
function applyArrow() {
    polylineOnTerrainPrimitive.appearance = new Cesium.PolylineMaterialAppearance({
        material : Cesium.Material.fromType('PolylineArrow')
    });
}
function applyDash() {
    polylineOnTerrainPrimitive.appearance = new Cesium.PolylineMaterialAppearance({
        material : Cesium.Material.fromType('PolylineDash', {
            color : Cesium.Color.YELLOW
        })
    });
}
function applyOutline() {
    polylineOnTerrainPrimitive.appearance = new Cesium.PolylineMaterialAppearance({
        material : Cesium.Material.fromType('PolylineOutline')
    });
}

Sandcastle.addToolbarButton('Toggle instance show', function() {
    if (Cesium.defined(selectedId)) {
        var attributes = polylineOnTerrainPrimitive.getGeometryInstanceAttributes(selectedId);
        attributes.show = [attributes.show[0] ? 0 : 1];
    }
    scene.requestRender();
});

Sandcastle.addToolbarButton('Show all', function() {
    if (Cesium.defined(selectedId)) {
        var attributes = polylineOnTerrainPrimitive.getGeometryInstanceAttributes('polyline1');
        attributes.show = [1];
        attributes = polylineOnTerrainPrimitive.getGeometryInstanceAttributes('polyline2');
        attributes.show = [1];
    }
    scene.requestRender();
});

Sandcastle.addToolbarButton('Toggle debugShowShadowVolume', function() {
    var debugShowShadowVolume = !polylineOnTerrainPrimitive.debugShowShadowVolume;
    var appearance = polylineOnTerrainPrimitive.appearance;
    scene.groundPrimitives.remove(polylineOnTerrainPrimitive);
    createPolylines(debugShowShadowVolume);
    polylineOnTerrainPrimitive.appearance = appearance;
    scene.requestRender();
});

Sandcastle.addToolbarButton('Toggle z-index', function() {
    if (groundPrimitiveOnTop) {
        scene.groundPrimitives.raiseToTop(polylineOnTerrainPrimitive);
    } else {
        scene.groundPrimitives.lowerToBottom(polylineOnTerrainPrimitive);
    }
    groundPrimitiveOnTop = !groundPrimitiveOnTop;
    scene.requestRender();
});

function lookAt() {
    viewer.camera.lookAt(polylinePositions[1], new Cesium.Cartesian3(50000.0, 50000.0, 50000.0));
    viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
}

Sandcastle.addToolbarButton('reset view', function() {
    lookAt();
    scene.requestRender();
});

createPolylines(false);
applyPerInstanceColor();

lookAt();

Sandcastle.addToolbarMenu([{
    text : 'Per Instance Color',
    onselect : function() {
        applyPerInstanceColor();
        Sandcastle.highlight(applyPerInstanceColor);
        scene.requestRender();
    }
}, {
    text : 'Color',
    onselect : function() {
        applyColorMaterial();
        Sandcastle.highlight(applyColorMaterial);
        scene.requestRender();
    }
}, {
    text : 'Glow',
    onselect : function() {
        applyGlowMaterial();
        Sandcastle.highlight(applyGlowMaterial);
        scene.requestRender();
    }
}, {
    text : 'Arrow',
    onselect : function() {
        applyArrow();
        Sandcastle.highlight(applyArrow);
        scene.requestRender();
    }
}, {
    text : 'Dash',
    onselect : function() {
        applyDash();
        Sandcastle.highlight(applyDash);
        scene.requestRender();
    }
}, {
    text : 'Outline',
    onselect : function() {
        applyOutline();
        Sandcastle.highlight(applyOutline);
        scene.requestRender();
    }
}]);

@mramato
Copy link
Contributor

mramato commented Jun 27, 2018

@ggetz is @likangning93 correct here? This sounds like a bug to me. Isn't adding/removing primitives supposed to be one of the things that automatically renders even in request render mode?

@likangning93 likangning93 reopened this Jun 27, 2018
@ggetz
Copy link
Contributor

ggetz commented Jun 27, 2018

Loading in terrain, imagery, 3D Tiles, or data sources, including each individual tile load. At a lower level, this is triggered when a web request is resolved via a URI or blob, or an asynchronous process returns from a web worker.

While we don't explicitly watch for primitives to be added to the scene, we do watch for aync processes to be return from web workers, which occurs when geometries are created.

@likangning93
Copy link
Contributor

Isn't adding/removing primitives supposed to be one of the things that automatically renders even in request render mode?

we do watch for aync processes to be return from web workers, which occurs when geometries are created.

This doesn't seem to happen with standard primitives either though. Here on Sandcastle I still have to play the timeline to get the box to update on every button click.

Maybe this is a more overarching bug?

@ggetz
Copy link
Contributor

ggetz commented Jun 27, 2018

Adding scene.requestRender(); to the end of the addBox function will update the scene correctly, which was the original intention with requester render mode - Have the developer know when they want to request a new frame based on changes in the scene.

But, yes, this doesn't relate specifically to polylines.

@likangning93
Copy link
Contributor

Adding scene.requestRender(); to the end of the addBox function will update the scene correctly, which was the original intention with requester render mode - Have the developer know when they want to request a new frame based on changes in the scene.

Ah. addBox here is still asynchronously creating geometry for a Primitive via webworker though.

@likangning93
Copy link
Contributor

@ggetz @mramato given that GroundPolylinePrimitive seems to behave the same way as regular Primitives here, what's the next step? Is the missing async tracking a bug that should be fixed or can we close this as intentional?

@ggetz ggetz changed the title GroundPolylinePrimitive doesn't appear with requestRenderMode: true Re-render when adding/removing primitives in requestRenderMode Jun 28, 2018
@hpinkos
Copy link
Contributor

hpinkos commented Aug 27, 2018

While we don't explicitly watch for primitives to be added to the scene, we do watch for aync processes to be return from web workers, which occurs when geometries are created.

@ggetz does this mean that geometry created synchronously require a requestRender after scene.primitives.add but asynchronous geometry does not? That's an odd choice.

@ggetz
Copy link
Contributor

ggetz commented Aug 27, 2018

The initial push for requestRender mode was targeted to a small but commonly used subset of the API - Loading a scene with imagery, terrain, and a tileset. Some of the primitive functionality came along with that but not all. There's definitely some work to be done if we want it to be more robust with the lower level parts of the API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
Status: Notable backlog items
Development

No branches or pull requests

5 participants