Canvas problem

Hello all,

I am implementing my own ImageryProvider. I have a problem with the requestImage() function. In the returning statement, I am trying to return the current canvas to which the scene is bound. There is no error message printed in the console, but the returned canvas looks like a slice of regular canvas. The screen shot is attached, and my code is pasted below. In my render() function, I am only drawing rectangles, and there is no code should affect the size of canvas.

W10nImageryProvider.prototype.requestImage = function (x, y, level){

this.render(this.getCurrentView(), level);

return this._widget.scene.canvas;

}

I’ve been spending hours on this bug, and couldn’t figure out why. Any pointer will be helpful.

Thanks,

Steven

Hi Steven,

I’m a bit confused about what you’re trying to do. Returning Cesium’s canvas from a requestImage call doesn’t make a whole lot of sense to me. Am I understanding you correctly? At best, it will be a snapshot of the canvas at the time the canvas is uploaded to the GPU as a texture, which may be in the same or later render frame compared to the requestImage call itself.

Kevin

Hi Kevin,

Thanks for the reply.

Based on the requestImage function’s description in reference document below, the return of requestImage can be either an image or a canvas DOM object. Since I don’t have the images returned from the remote server I use, I just return the canvas object.

A promise for the image that will resolve when the image is available, or undefined if there are too many active requests to the server, and the request should be retried later. The resolved image may be either an Image or a Canvas DOM object.

Thanks,

Steven

在 2014年10月15日星期三UTC-7下午3时20分07秒,Kevin Ring写道:

Hi Steven,

Right, returning a Canvas from requestImage is reasonable. Returning the Canvas that Cesium itself is rendered to doesn’t make much sense, however.

Kevin

Hi Kevin,

Thanks again for the reply.

Yes, I realized that. I am now returning a Canvas instead of the Canvas that Cesium itself is rendered to, and it solves my original problem I posted in this thread.

However, I noticed that the requestImage function is not called on zooming out behavior.

Here is what I did, I define the min and max zooming level to be 0 and 5. When I zoom in from level 0 to level 5, I can see the requestImage function is called properly, but when I zoom out from level 5 to level 0, requestImage function is not called.

Do you have any idea why?

Thanks,

Steven

在 2014年10月21日星期二UTC-7下午3时39分59秒,Kevin Ring写道:

Hi Steven,

Cesium doesn’t call requestImage when zooming out because it already has those tiles. There’s no need for it to request them from the ImageryProvider again.

Kevin

Hi Kevin,

Right, it’s so obvious, I am sorry I asked a stupid question.

What if I need to trigger requestImage when zooming out, would you please give me some pointers on how to do it?

For example, I need to draw 10 rectangles at level 5, and I need to remove all the 10 rectangles and redraw another 20 rectangles at level 4.

I am thinking maybe I can add an event listener/handler on the zooming distance, but I am worrying there will be performance issues if the event is triggered too many times.

Thanks,

Steven

在 2014年10月21日星期二UTC-7下午3时51分27秒,Kevin Ring写道:

There’s no way to trigger requests on zooming out, short of hacking up Cesium. I suggest an entirely different approach. If you need to create actual geometry (rectangles and such) at different levels of detail, I suggest you take a look at the QuadtreePrimitive. This is definitely an advanced feature, though. If you tell me more about what you’re actually trying to accomplish, maybe I can suggest an easier way.

Kevin

Hi Kevin,

Matthew told me once about this QuadtreePrimitive, but he said it is currently a private interface, and it is not public documented.

Just like what you said, I am trying to create geometries (rectangles and circles) at different levels of detail. I retrieve latitude, longitude, and values arrays in JSON format from a web service. I use the latitude and longitude arrays for the location to draw geometry, and then use the value array to color map the the geometry. Since the there JSON arrays are large (very large), it is impossible to draw the entire arrays on the globe because of the performance issues. First, drawing too many rectangles is too slow, and secondly, sometimes when I draw a large amount of rectangles, the browser crashes. With the levels of detail feature, I can draw rectangles within only the current screen view that is visible. When the zooming in/out or rotating handlers are triggered, I need to remove all the rectangles from the pervious screen view, and redraw rectangles within the current screen view.

Thanks,

Steven

在 2014年10月21日星期二UTC-7下午4时20分12秒,Kevin Ring写道:

Yes, it’s currently considered private, but it’s probably your best bet. There’s an example here:
https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Specs/Sandcastle/QuadtreePrimitive.html

Another option is to rasterize your geometry. Implement an ImageryProvider, as you’re already doing, except instead of trying to create geometry in requestImage, you rasterize (draw) that geometry to a Canvas and return the Canvas.

Kevin

Hi Kevin,

Wow, I think this is exactly what I need!

I quickly went through the code, I have two questions:

  1. There is a function DemoTileProvider.prototype.computeTileVisibility = function(tile, frameState, occluders), is this function used to calculate which tiles are within the current screen view and needed to redraw? I want to update only the tiles within the current screen view, and don’t update the tiles that are outside the current screen view.

  2. Considering the performance, which method between QuadtreePrimitive and ImageryProvider would you recommend I use?

Thanks,

Steven

在 2014年10月21日星期二UTC-7下午5时09分00秒,Kevin Ring写道:

Hi Steven,

There’s documentation of each method on the QuadtreeTileProvider interface:

https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Source/Scene/QuadtreeTileProvider.js

But basically, yes, Cesium uses that method to determine whether each tile is visible to the current camera view.

It’s hard to judge the performance of writing a QuadtreeTileProvider versus of an ImageryProvider because it entirely depends on how you implement them. If you have a fast way to rasterize your features, the ImageryProvider approach should be pretty fast and has the advantage that it will be nicely draped on terrain. If you have an efficient way to determine feature visibility, the QuadtreeTileProvider could be faster and will provide “sharper” results (because they’re not rasterized).

Kevin

Hi Kevin,

I am able to create a simple demo based on the example you gave me. Using quadtree to solve the levels of detail is brilliant, and very impressive.

I can see that maximumScreenSpaceError affects the performance. I will probably need to set maximumScreenSpaceError value to be 0.1. Is there a trick to improve the performance when maximumScreenSpaceError equals 0.1 or even smaller?

Thanks again,

Steven

在 2014年10月21日星期二UTC-7下午5时58分27秒,Kevin Ring写道:

Hi Steven,

I’m glad it’s working well for you!

I’m surprised to hear you say you need a maximumScreenSpaceError of 0.1. That’s expressed in pixels, so you’re basically saying that your rendering has to be accurate to 1/10 of a pixel, which seems unlikely. More likely your getLevelMaximumGeometricError method is returning an an error value that is smaller than the actual error, or your computeDistanceToTile method is returning a distance that is greater than the actual distance.

Kevin

Hi Kevin,

Thanks to the book you and Patrick wrote. Now, I have the rough understanding of the mathematical/geometric concepts underneath screen space error and geometric error. However, I don’t understand how is the screen space error related to the numbers of tiles are shown on the globe?

For example,

//Below is how I create the tiling scheme.

this._tilingScheme = new GeographicTilingScheme({

numberOfLevelZeroTilesX : 90,

numberOfLevelZeroTilesY : 45 //I need at least 9045 tiles at level 0. However, the performance doesn’t meet the requirements. It takes a long time (roughly 30 seconds) to draw 9045 tiles. Is there a way to improve the performance?

});

primitives.add(new QuadtreePrimitive({

tileProvider : new LODProvider(),

maximumScreenSpaceError : 2, // I can see that the smaller the value of screen space error, the smaller size of tiles. This is why I am asking how is the screen space error is related to the numbers of tiles.

tileCacheSize : 500

}));

My goal here is to be able to draw at least 90*45 tiles at level 0 effectively.

Thanks again,

Steven

在 2014年10月22日星期三UTC-7下午3时47分13秒,Kevin Ring写道:

Hi Steven,

Specifying 90x45 tiles at level zero is not going to work. The problem is that Cesium would need to download and render all 4050 tiles (well, at least half of them) in order to render a view where you can see the entire globe. For good performance, you need to find a way to reduce the number of tiles at level 0 to around 4 or less.

Kevin

Hi Kevin,

Okay, I see. Right now, I make one tile contains only one rectangle, so I need more tiles at level 0 to display enough data. However, if I make one tile contains multiple rectangles, then I don’t need too many tiles and still can display enough data. I will give it a try. Thanks,

Steven

在 2014年10月27日星期一UTC-7下午4时20分08秒,Kevin Ring写道:

Hi Kevin,

Drawing multiple rectangles in one tile improves the performance significantly.

How do I define the maximum zooming level?

Thanks,

Steven

在 2014年10月27日星期一UTC-7下午4时41分49秒,Steven写道:

Hi Steven,

To limit the zoom level, set “tile.state = QuadtreeTileLoadState.FAILED” in your loadTile method when the requested tile’s level is greater than the level you want to support.

Kevin