mapbox gl js:使用中间渲染步骤作为自定义图层的遮罩

时间:2019-08-22 12:06:29

标签: javascript mapbox mapbox-gl-js mapbox-gl

我的目标是在地图框地图上覆盖自定义图层。该自定义图层应被其他mapbox地图遮盖。

用例:

我有一些默认地图。最重要的是,我想渲染一些特殊的热图。只需在道路上方显示热图即可。

当前方法:

  • 在地图框中添加图层,以生成地图,其中所有道路均为白色,背景为黑色
  • 添加一个自定义层,将帧缓冲区的内容复制到纹理
  • 添加图层以渲染一些默认地图
  • 添加使用上述纹理作为蒙版绘制特殊热图的自定义层。

问题:

渲染图层的顺序似乎与将其添加到mapbox的顺序不匹配。此示例具有一个自定义层,该层在被调用时输出帧缓冲区中中心像素的颜色:

var map = window.map = new mapboxgl.Map({
container: 'map',
zoom: 16,
center: [8.30468, 47.05232],
style: {
    "version":8, 
    "name":"test", 
    "sources": {
        "openmaptiles": {
            "type": "vector",
            "url": "https://api.maptiler.com/tiles/v3/tiles.json?key=X0HhMcrAjHfR6MvFLSSn"
        }
    },
    "layers":[]}
});

var getPixelLayer = {
    id: 'highlight',
    type: 'custom',

    onAdd: function (map, gl) { },

    render: function (gl, matrix) {
        var pixels = new Uint8Array(4);
        gl.readPixels(Math.round(gl.drawingBufferWidth/2), Math.round(gl.drawingBufferHeight/2), 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
        document.getElementById("color").innerHTML = pixels[0]+","+pixels[1]+","+pixels[2];
    }
};

map.on('load', function() {
  //expected output: "255,255,255" everywhere
  //actual output: "0,0,0" everywhere
    /*
    map.addLayer({"id":"bkg1","paint":{"background-color":"rgb(255, 255, 255)"},"type":"background"});
    map.addLayer(getPixelLayer);
    map.addLayer({"id":"bkg2","paint":{"background-color":"rgb(0, 0, 0)"},"type":"background"});
    */

  //expected output: "0,0,0" everywhere
  //actual output: "177,177,177" above buildings
  //               "0,0,0" above streets
  //               "0,0,0" above background
    map.addLayer({"id":"bkg1","paint":{"background-color":"rgb(0, 0, 0)"},"type":"background"});
    map.addLayer(getPixelLayer);
    map.addLayer({"id":"roads","layout":{"line-cap":"round","line-join":"round","visibility":"visible"},"paint":{"line-color":"#fff","line-offset":0,"line-width":{"base":1.4,"stops":[[8,1.2],[16,12]]}},"source":"openmaptiles","source-layer":"transportation","type":"line"});
    map.addLayer({"id":"building","paint":{"fill-color":"rgb(177, 177, 177)"},"source":"openmaptiles","source-layer":"building","type":"fill"});


});

https://jsfiddle.net/t31cj5v0/

可以看出,渲染顺序似乎是背景->建筑物-> custom_layer->街道,而不是背景-> custom_layer->街道->建筑物。最后,层顺序在屏幕上显示正确,但是像这样做是不可能的。

有人知道导致这种现象的原因以及如何避免这种情况吗?

我尝试过的其他实施方式:

我还尝试通过同步运动将黑白街道地图呈现到另一个mapbox对象。这行得通,但是由于每个Mapbox都有自己的webgl上下文,因此我不能在其他上下文中使用生成的黑白纹理。

功能请求(?)

如果可以实现某些“遮罩”层以本机完成此目标,那将是非常好的。但是现在我只是在寻找一些技巧来做到这一点。预先感谢。

1 个答案:

答案 0 :(得分:1)

在3个渲染过程中绘制

mapbox图层。 “屏幕外”,“不透明”和“半透明”。 “屏幕外”并不重要,因为随后的遍历总是覆盖它。由于首先绘制了所有分类为“不透明”的图层,然后分类为“半透明”的所有图层,所以出现了问题(在渲染过程中遵守了图层顺序)。因此,渲染顺序与声明的顺序不匹配。

自定义图层是在“半透明”过程中绘制的,但是由于上述原因,可能会发生以后的图层已经被渲染(如果“不透明”的情况)的情况。通常这不是问题,因为mapbox使用模板缓冲区跟踪哪一层在哪一层之下/之上,即使它们没有按顺序绘制。

要使渲染顺序匹配,请在创建mapbox实例后添加此行。它将禁用“不透明”渲染过程,并强制使“不透明”的每一层都是“半透明的”:

map.painter.opaquePassEnabledForLayer = function() { return false; }