RFC: data-driven styling for fill-extrusion-opacity and robust opacity blending
@arindam1993 is already working on this.
Since Jan 15, 2020.
- Dominant language
- TypeScript
- Stars
- 12.4k
- Forks
- 2.4k
- PR merge metrics
- No merged PRs in 30d
Description
We currently do not support data-driven styling for `fill-extrusion-opacity`, and transparent fill-extrusions that overlap each other do not blend correctly, with the extrusion closer to the camera culling the one behind.

Both of these issues stem from the fact that we do not render fill extrusions in an order defined by their distance to the camera. This RFC presents a few options for implementing this, comments and thoughts would really be appreciated!
### Part 1) Handing tiles:
#### Sort visible tiles every frame based on distance to camera:
(calling this `z-sorting` from here on out, slightly confusing since we overload the term `z` with zoom level )
Since every tile is a separate draw call we can sort on the CPU before entering the draw loop for each tile.
My intuition is that we should have enough CPU budget for this assuming roughly ~20-50 visible tiles on the screen, and we'd only do this when fill extrusions need to be rendered, typically at higher zoom levels, and we might even win some performance back by rendering front to back for
opaque extrusions.
### Part 2) Handling extrusions within the tile:
#### z-sort each feature on the CPU:
Doing this every frame will definitely be too expensive, but I was thinking we could precompute multiple sort-orders for for a a few different values of azimuth ( which would be in the range [0, 180] degrees) on the worker when we build the bucket.
Then every frame, we can perform an `O(1)` lookup for the sort-order by taking `Math.round(camera_azimuth/num_sort_orders)`.
Illustration, each black arrow represents a pre-computed sort order for that azimuth:
##### Pros:
- No special hardware support required
- Easier and simpler to implement(?)
- Less z-fighting coz we render them one at a time
##### Cons:
- Additional drawcall overhead, each extrusion would have to drawn with a separate draw call.
- Slower load times for the extrusion layer.
- Potentially inaccurate sorting since we're approximating based on closest available azimuth.
#### - OR -
#### Weighted, blended order-independent transparency:
http://casual-effects.blogspot.com/2015/03/implemented-weighted-blended-order.html
Multi-pass technique, that just needs a separate pass for opaque and transparent objects.
But this requires `OES_texture_half_float` support :(, WebGL stats says only 69% of mobile devices support it.https://webglstats.com/webgl/extension/OES_texture_half_float
### style-spec dependencies:
if we decide to do this, it shouldn't be the default behavior because it will change how existing maps look and maybe make them much noisier. We should probably have a new style-spec property that explicitly enables this. Most 3D engines, define separate `transparent: boolean` and `opacity: float` parameters. This lets the designer have control by by allowing rendering of `translucent` extrusions that actually obscure each other ( our current implementation ).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.