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

Async pick/sample functions don't work with explicit rendering #8281

Closed
richard-ling opened this issue Oct 14, 2019 · 1 comment · Fixed by #8283
Closed

Async pick/sample functions don't work with explicit rendering #8281

richard-ling opened this issue Oct 14, 2019 · 1 comment · Fixed by #8283

Comments

@richard-ling
Copy link

richard-ling commented Oct 14, 2019

Async functions Scene.prototype.sampleHeightMostDetailed() and Scene.prototype.clampToHeightMostDetailed() do not play nice with explicit rendering. The way these functions work is:

  1. create a promise for each point to be sampled, which resolves when all high-detail tiles needed for sampling that point have been loaded.

  2. create a promise which resolves when all promises created at step 1 resolve.

  3. pass the promise from step 2 to deferPromiseUntilPostRender(), which returns a new promise that resolves during the next post-render event after the promise from step 2 has resolved. This prevents the risk of modifying primitives during render callback (see https://git.patrocinium.com/pub/cesium/commit/502f34abebb4ffb06dfc1671db0983c52fdffe70)

  4. The return value is the promise created at step 3.

If an app that is using explicit rendering calls sampleHeightMostDetailed(), and waits for the returned promise without explicitly calling scene.requestRender(), the promise won't resolve, because there are no post-render events. This means the app may seem non-responsive to the user.

The app can't easily schedule a render using calling scene.requestRender(), because there's no way to know when the promise from step 2 resolved. The solution that worked for me is to modify deferPromiseUntilPostRender() to call scene.requestRender() when promise 2 resolves:

    function deferPromiseUntilPostRender(scene, promise) {
        // Resolve promise after scene's postRender in case entities are created when the promise resolves.
        // Entities can't be created between viewer._onTick and viewer._postRender.
        var deferred = when.defer();
        promise.then(function(result) {
            var removeCallback = scene.postRender.addEventListener(function() {
                deferred.resolve(result);
                removeCallback();
            });
            scene.requestRender();      <== add this line
        });
        return deferred.promise;
    }

Incidentally, it would also be very desirable for an app to be able to cancel pending calls to the async pick/sample functions when they are no longer needed. I'm doing it by setting scene._mostDetailedRayPicks = [], because I know I'm the only user of that array, but that wouldn't work in a more complex app.

Browser: Chrome

Operating System: MacOS 10.14.6

No time to do a sandcastle, sorry.

@lilleyse
Copy link
Contributor

@richard-ling that seems like a good fix. I'll open a PR shortly.

Incidentally, it would also be very desirable for an app to be able to cancel pending calls to the async pick/sample functions when they are no longer needed.

Can you open a separate issue for this? It does sound like a useful feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants