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

Flickering when zooming with terrain enabled #1077

Open
florianf opened this issue Mar 7, 2022 · 13 comments
Open

Flickering when zooming with terrain enabled #1077

florianf opened this issue Mar 7, 2022 · 13 comments
Labels
bug Something isn't working PR is more than welcomed Extra attention is needed terrain

Comments

@florianf
Copy link

florianf commented Mar 7, 2022

Hi all,

great work on the 3d feature, looks beautiful!

When testing your branch I noticed some flickering when zooming in (using the toursprung/terrain.json style) which is quite noticeable. It seems like semi-transparent polygons are rendered twice and for a few frames and the opacity is therefore doubled.
Edit: It only seems to happen on the first zooming of an area, when all tiles are cached it doesn't happen.

Tile in the southeast with wrong opacity:
2200ms

200ms later the tile is rendered correctly:
2400ms

This doesn't happen with terrain disabled, I think it's related to some networking activity (new DEM or image tiles available).

Any idea where that may come from? Happy to help if you can point me in the right direction.

Regards,
Florian

Original issue in prozessor13's repo: prozessor13#60

@florianf
Copy link
Author

florianf commented Mar 8, 2022

I made some further tests. My initial suspicion was, it's because of the hillshade raster layer, but that's not the case. Confirmed this on another machine as well. Is this reproducible for anybody else?

Zooming in:
Screenshot_20220308_125019

First artifacts appear:
Screenshot_20220308_125041

Then some more:
Screenshot_20220308_125054

When everything is loaded, everything is allright:
Screenshot_20220308_125118

Any pointers appreciated!

@prozessor13
Copy link
Collaborator

Hi, i think the issue is only with raster-tiles, and in the terrain-testpage the hillshading is done via raster-tiles.

In 2d mode the raster-tiles are rendered on every frame, and between zoomleves and loading the rastertiles will fade into each other, but 3d works completele different.
The vectortiles will render into a texture and this texture will draped over the terrain-mesh. During zooming maplibre resample existing rastertiles while loading the new tiles in background. But because of performance the rendert-to-texture is done only when tile-data changes, so in between this time you see the artefacts (e.g. when resampled and already loaded tiles are mixed).
Maybe this logic can be optimized, but currently i have no time to focus on that.

@florianf
Copy link
Author

florianf commented Mar 9, 2022

hi,
thanks for your reply. My first suspicion also were raster tiles, but take a look at the screenshots from yesterday, this also happens if the raster hillshade layer is switched off and no raster tiles are used.

so in between this time you see the artefacts (e.g. when resampled and already loaded tiles are mixed)
Could you point me to the location in the source?

@prozessor13
Copy link
Collaborator

OK, you are right, i will have a look onto it!

@HarelM HarelM added the terrain label Mar 11, 2022
@HarelM HarelM changed the title [Terrain 3D] Flickering when zooming with terrain enabled Flickering when zooming with terrain enabled Mar 11, 2022
@florianf
Copy link
Author

After some more digging, I can reproduce the overlapping rendering now in a simple example with only the natural-wood layer.
It seems, that in higher zoom levels there are overlapping tiles. Like here, it seems there is one parent 13 zoom tile, covered with two child tiles in 14, but not all four:

Screenshot_20220318_214019

@prozessor13
Copy link
Collaborator

Ok thanks, i think i know now where to start!

I think the problem is when filling _coordsDescendingInv. May after the fill process (below line 56) we have to check that there are no parent-tiles in the to-render-tiles array.

@florianf
Copy link
Author

You're right, there are loads of parents in the to-render array. That's clear, because some low zoom tiles (f.ex. 5) are always visible. But the problem really only shows on zooming in, until all requested tiles are loaded. A simple hacky fix reduces the flickering to almost not noticeable.
I added this in the inner loop in _init

                let parentPresent = false
                for (const parentTileID of tileIDs) {
                    if (parentTileID != tileID && tileID.isChildOf(parentTileID) && (tileID.overscaledZ - parentTileID.overscaledZ) < 3) {
                        parentPresent = true
                    }
                }
                
                if (parentPresent) {
                    continue;
                }

The tile isn't rendered, if there is a parent or grandparent tile visible. I don't get why the double rendering isn't notice all the time, because tiles are rendered on top of another all the time?

@prozessor13
Copy link
Collaborator

Thx for your effort! I shortly digged into this but currently i do not have a correct answer for the issue. As soon as i have time, i will look again onto this issue.

@HarelM HarelM added bug Something isn't working PR is more than welcomed Extra attention is needed labels Aug 21, 2022
@florianf
Copy link
Author

@prozessor13 I finally found the issue, took me a couple of hours. Based on your #1651 PR:

The problem is in the renderLayer methode in render_to_texture.ts. When a zoom event occurs and not all tiles are completely loaded, the coords array in the layer loop contains overlapping tiles. Link to source: https://github.com/prozessor13/maplibre-gl-js/blob/c82c13eac651bf96f23e44985bbf62326fc93ad2/src/render/render_to_texture.ts#L247

grafik

My suggested fix would be, remove the overlapping tiles for fill layers. Lower zoom levels should be always rendered first, because of ordering in coords array.

                for (let l = 0; l < layers.length; l++) {
                    const layer = painter.style._layers[layers[l]];
                    let coords = layer.source ? this._coordsDescendingInv[layer.source][tile.tileID.key] : [tile.tileID];
                    if (coords && coords.length > 1 && layer.type == "fill") {
                        let parentPresent = false
                        let nonOverlappingCoords = []
                        for (const tileID of coords) {
                            for (const parentTileID of coords) {
                                if (parentTileID != tileID && tileID.isChildOf(parentTileID)) {
                                    parentPresent = true
                                    break;
                                }
                            }
                            if (!parentPresent) {
                                nonOverlappingCoords[nonOverlappingCoords.length] = tileID
                            }
                        }
                        coords = nonOverlappingCoords
                    }
                    painter._renderTileClippingMasks(layer, coords);
                    painter.renderLayer(painter, painter.style.sourceCaches[layer.source], layer, coords);
                    if (layer.source) tile.rttCoords[layer.source] = this._coordsDescendingInvStr[layer.source][tile.tileID.key];
                }

What do you think?

@prozessor13
Copy link
Collaborator

Hi, thanks very much for digging into this. Your approach is one way, but i think the problem can be solved otherwise. In 2d Maplibre has a stencil logic to render on a pixel only the data of the tile with the highest zoomlevel. But currently in terrain-mode the stencil is not handled correct, and so this artefacts accours.

I played also with a solution you did, but run into problems when sources has no global coverage.

So i created another branch for this issue https://github.com/prozessor13/maplibre-gl-js/tree/rtt_stencil . Hopefully with this logic your problem dissapears as well, because currently i only tested with raster and hillshade layers. It would be great, if you can test this branch.

@florianf
Copy link
Author

I tested your rtt_stencil branch an it works great! It also fixes another related issue where tile borders (overdraw) where overlapping when zooming out. Really fantastic!

@HarelM
Copy link
Collaborator

HarelM commented Mar 4, 2023

@florianf I've assigned a bounty for adding tests to the #1672 in #1540.
Feel free to add some test so the PR can be merged.

@HarelM
Copy link
Collaborator

HarelM commented Mar 4, 2023

No need to assign a bounty here since it was assigned in #1540.
Link to parent Bounty: maplibre/maplibre#189

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working PR is more than welcomed Extra attention is needed terrain
Projects
None yet
Development

No branches or pull requests

3 participants