deck.gl
deck.gl copied to clipboard
[Bug] MapLibre Globe Integration
Description
ℹ Caveat up front: I know Globe integration is technically experimental still, this is mostly to document some findings I am seeing in the wild.
When utilizing the @deck.gl/mapbox-overlay extension there appears to be an issue with the canvas interleaving (and technically when not interleaving per example 3 below). I have tried adjusting the parameters prop at the Deck level and layer level but cannot find a combination that draws things correctly. Notably depthCompare: 'always' kind of gives the result I am looking for but effectively removes culling so layers are drawn behind the globe still.
Video of issue:
https://github.com/user-attachments/assets/1472debe-a957-472a-b14d-4c6cda24a57e
Additional oddities:
Text is rendered upside down and has a similar culling/depth type issue:
Flavors
- [x] React
- [x] MapboxOverlay
Steps to Reproduce
https://github.com/brandonjpierce/deckgl-maplibre-bug
pnpm i
pnpm run example1
pnpm run example2
pnpm run example3
pnpm run example4
- Example 1:
@deckg-fiber-renderer/dom+maplibre-glw/ interleaving - Example 2:
react-map-gl/maplibre+@deck.gl/mapbox-overlayw/ interleaving - Example 3:
react-map-gl/maplibre+@deck.gl/mapbox-overlayw/ no interleaving - Example 4:
react-map-gl/maplibreonly, no Deck
Examples 1, 2, and 3 each have a different setup just to sanity check things. Examples 2 and 3 in particular are effectively taken directly from the website example. Example 4 is just Maplibre in isolation to ensure there was nothing wrong with the underlying basemap renderer.
I also tried the beforeId and parameters: { cullMode: 'none' } tricks.
Environment
- Framework version: 9.1.10
- Browser: Chrome
- OS: MacOS
I identified that the TextLayer issue only occurs if you have billboard: false applied. If billboarding is enabled the text is in the correct orientation.
Another interesting find:
If you set depthCompare: "always" on the Deckgl parameters prop it does fix the depth fighting issue but culling does not seem to work appropriately. Adding in parameters: { cullMode: 'back' } or a getPolygonOffset accessor does not change anything. This code was added to the reproduction repo under example1 https://github.com/brandonjpierce/deckgl-maplibre-bug/tree/main/example1
https://github.com/user-attachments/assets/af5ce840-9b7b-4151-9cf6-586d86ef1685
Interestingly with no MapLibre at all and just a _GlobeView there appears to be some culling issues at play (notice the PathLayer bleeding through when I turn the globe):
https://github.com/user-attachments/assets/e8055eae-8d5a-4ebc-a05b-a697f4dcbcc9
In this example I have cullMode: 'back' and depthCompare: 'always' on.
@brandonjpierce I investigated this a bit, and while I don't have a fix I found that making the following change will correct the label orientation for billboard: false
It is in line with my hunch that the Maplibre globe view has a different coordinate system (perhaps right-handed rather than left-handed) which is causing confusing with the vector algebra. It would also explain would cullMode: 'front' is often needed when typically one would want cullMode: 'back'
Good catch @felixpalmer appreciate you investigating this!
@felixpalmer an additional update: that incorrect rotation on the text issue is actually present without Maplibre in the picture at all. You can reproduce it on deck v9.1.12 by adding a TextLayer with a _GlobeView.
@brandonjpierce @felixpalmer I confirm:
cullMode: 'front'is needed where I'd expectcullMode: 'back'instead. At least by the orientation how we're looking at the back or the front of the rendered deck layer. I have tried to override it withfrontFace: 'cw'(default isccw). This used to throw "GL_INVALID_ENUM: Enum 0x0000 is currently not supported." in the past, but seems to work now. Which one is expected?- TextLayer is rotated by 180deg in GlobeView.
My workaround is using these helper functions:
export function getViewportPixelOffset(viewport: Viewport, offset: number): number {
return offset * (isViewportGlobe(viewport) ? -1 : 1);
}
export function getViewportAngle(viewport: Viewport, angle: number): number {
return angle + (isViewportGlobe(viewport) ? 180 : 0);
}
@brandonjpierce - The issue with the pathlayer is that the mitering has a bug and is not allowing the triangles to face upwards. I plan on submitting a pull request with the fix on Monday.
Essentially the following code in path-layer-vertex.glsl.ts
// extend out a triangle to envelope the round cap
if (isCap) {
offsetVec = mix(perp * sideOfPath, dir * path.capType * 4.0 * flipIfTrue(isStartCap), isJoint);
vJointType = path.capType;
} else {
vJointType = path.jointType;
}
should be changed to
vec2 offsetVec;
// extend out a triangle to envelope the round cap
if (isCap) {
offsetVec = mix(perp * sideOfPath, dir * path.capType * 4.0 * flipIfTrue(isStartCap), isJoint);
vJointType = path.capType;
} else {
vJointType = path.jointType;
if (isJoint > 0.5) {
offsetVec = miterVec * miterSize * turnDirection;
} else {
offsetVec = perp * sideOfPath;
}
}
In the video I have cullMode: 'back' and depthCompare: 'always' with the fix I pasted above.
https://github.com/user-attachments/assets/141ff14f-d0c0-402f-8cce-a90879c3a9ac