diff --git a/debug/threejs.html b/debug/threejs.html
index cca332b4f4a..2587ec0348e 100644
--- a/debug/threejs.html
+++ b/debug/threejs.html
@@ -22,6 +22,7 @@
var map = window.map = new mapboxgl.Map({
container: 'map',
+ antialias: true,
zoom: 16.5,
center: [-79.390307, 43.658956],
bearing: 20,
diff --git a/src/render/draw_custom.js b/src/render/draw_custom.js
index e9dd3328e2b..6b493edc2ca 100644
--- a/src/render/draw_custom.js
+++ b/src/render/draw_custom.js
@@ -4,7 +4,6 @@ export default drawCustom;
import DepthMode from '../gl/depth_mode';
import StencilMode from '../gl/stencil_mode';
-import {prepareOffscreenFramebuffer, drawOffscreenTexture} from './offscreen';
import type Painter from './painter';
import type SourceCache from '../source/source_cache';
@@ -27,35 +26,23 @@ function drawCustom(painter: Painter, sourceCache: SourceCache, layer: CustomSty
painter.setBaseState();
}
- if (implementation.renderingMode === '3d') {
- painter.setCustomLayerDefaults();
-
- prepareOffscreenFramebuffer(painter, layer);
- implementation.render(context.gl, painter.transform.customLayerMatrix());
-
- context.setDirty();
- painter.setBaseState();
- }
-
} else if (painter.renderPass === 'translucent') {
- if (implementation.renderingMode === '3d') {
- drawOffscreenTexture(painter, layer, 1);
+ painter.setCustomLayerDefaults();
- } else {
- painter.setCustomLayerDefaults();
+ context.setColorMode(painter.colorModeForRenderPass());
+ context.setStencilMode(StencilMode.disabled);
- context.setColorMode(painter.colorModeForRenderPass());
- context.setStencilMode(StencilMode.disabled);
+ const depthMode = implementation.renderingMode === '3d' ?
+ new DepthMode(painter.context.gl.LEQUAL, DepthMode.ReadWrite, painter.depthRangeFor3D) :
+ painter.depthModeForSublayer(0, DepthMode.ReadOnly);
- const depthMode = painter.depthModeForSublayer(0, DepthMode.ReadOnly);
- context.setDepthMode(depthMode);
+ context.setDepthMode(depthMode);
- implementation.render(context.gl, painter.transform.customLayerMatrix());
+ implementation.render(context.gl, painter.transform.customLayerMatrix());
- context.setDirty();
- painter.setBaseState();
- context.bindFramebuffer.set(null);
- }
+ context.setDirty();
+ painter.setBaseState();
+ context.bindFramebuffer.set(null);
}
}
diff --git a/src/render/draw_fill.js b/src/render/draw_fill.js
index 9a55a8df978..43881296ab9 100644
--- a/src/render/draw_fill.js
+++ b/src/render/draw_fill.js
@@ -29,7 +29,8 @@ function drawFill(painter: Painter, sourceCache: SourceCache, layer: FillStyleLa
const colorMode = painter.colorModeForRenderPass();
const pattern = layer.paint.get('fill-pattern');
- const pass = (!pattern.constantOr((1: any)) &&
+ const pass = painter.opaquePassEnabledForLayer() &&
+ (!pattern.constantOr((1: any)) &&
color.constantOr(Color.transparent).a === 1 &&
opacity.constantOr(0) === 1) ? 'opaque' : 'translucent';
diff --git a/src/render/draw_fill_extrusion.js b/src/render/draw_fill_extrusion.js
index 40f1f03dac1..444f3d8d914 100644
--- a/src/render/draw_fill_extrusion.js
+++ b/src/render/draw_fill_extrusion.js
@@ -2,12 +2,12 @@
import DepthMode from '../gl/depth_mode';
import StencilMode from '../gl/stencil_mode';
+import ColorMode from '../gl/color_mode';
import CullFaceMode from '../gl/cull_face_mode';
import {
fillExtrusionUniformValues,
fillExtrusionPatternUniformValues,
} from './program/fill_extrusion_program';
-import {prepareOffscreenFramebuffer, drawOffscreenTexture} from './offscreen';
import type Painter from './painter';
import type SourceCache from '../source/source_cache';
@@ -18,21 +18,32 @@ import type {OverscaledTileID} from '../source/tile_id';
export default draw;
function draw(painter: Painter, source: SourceCache, layer: FillExtrusionStyleLayer, coords: Array) {
- if (layer.paint.get('fill-extrusion-opacity') === 0) {
+ const opacity = layer.paint.get('fill-extrusion-opacity');
+ if (opacity === 0) {
return;
}
- if (painter.renderPass === 'offscreen') {
- prepareOffscreenFramebuffer(painter, layer);
-
- const depthMode = new DepthMode(painter.context.gl.LEQUAL, DepthMode.ReadWrite, [0, 1]),
- stencilMode = StencilMode.disabled,
- colorMode = painter.colorModeForRenderPass();
-
- drawExtrusionTiles(painter, source, layer, coords, depthMode, stencilMode, colorMode);
-
- } else if (painter.renderPass === 'translucent') {
- drawOffscreenTexture(painter, layer, layer.paint.get('fill-extrusion-opacity'));
+ if (painter.renderPass === 'translucent') {
+ const depthMode = new DepthMode(painter.context.gl.LEQUAL, DepthMode.ReadWrite, painter.depthRangeFor3D);
+
+ if (opacity === 1 && !layer.paint.get('fill-extrusion-pattern').constantOr((1: any))) {
+ const colorMode = painter.colorModeForRenderPass();
+ drawExtrusionTiles(painter, source, layer, coords, depthMode, StencilMode.disabled, colorMode);
+
+ } else {
+ // Draw transparent buildings in two passes so that only the closest surface is drawn.
+ // First draw all the extrusions into only the depth buffer. No colors are drawn.
+ drawExtrusionTiles(painter, source, layer, coords, depthMode,
+ StencilMode.disabled,
+ ColorMode.disabled);
+
+ // Then draw all the extrusions a second type, only coloring fragments if they have the
+ // same depth value as the closest fragment in the previous pass. Use the stencil buffer
+ // to prevent the second draw in cases where we have coincident polygons.
+ drawExtrusionTiles(painter, source, layer, coords, depthMode,
+ painter.stencilModeFor3D(),
+ painter.colorModeForRenderPass());
+ }
}
}
@@ -42,6 +53,7 @@ function drawExtrusionTiles(painter, source, layer, coords, depthMode, stencilMo
const patternProperty = layer.paint.get('fill-extrusion-pattern');
const image = patternProperty.constantOr((1: any));
const crossfade = layer.getCrossfadeParameters();
+ const opacity = layer.paint.get('fill-extrusion-opacity');
for (const coord of coords) {
const tile = source.getTile(coord);
@@ -72,8 +84,8 @@ function drawExtrusionTiles(painter, source, layer, coords, depthMode, stencilMo
const shouldUseVerticalGradient = layer.paint.get('fill-extrusion-vertical-gradient');
const uniformValues = image ?
- fillExtrusionPatternUniformValues(matrix, painter, shouldUseVerticalGradient, coord, crossfade, tile) :
- fillExtrusionUniformValues(matrix, painter, shouldUseVerticalGradient);
+ fillExtrusionPatternUniformValues(matrix, painter, shouldUseVerticalGradient, opacity, coord, crossfade, tile) :
+ fillExtrusionUniformValues(matrix, painter, shouldUseVerticalGradient, opacity);
program.draw(context, context.gl.TRIANGLES, depthMode, stencilMode, colorMode, CullFaceMode.backCCW,
diff --git a/src/render/offscreen.js b/src/render/offscreen.js
deleted file mode 100644
index 30e7bb1ec64..00000000000
--- a/src/render/offscreen.js
+++ /dev/null
@@ -1,64 +0,0 @@
-// @flow
-
-import Texture from './texture';
-import Color from '../style-spec/util/color';
-import DepthMode from '../gl/depth_mode';
-import StencilMode from '../gl/stencil_mode';
-import CullFaceMode from '../gl/cull_face_mode';
-import {extrusionTextureUniformValues} from './program/fill_extrusion_program';
-
-import type Painter from './painter';
-import type CustomStyleLayer from '../style/style_layer/custom_style_layer';
-import type FillExtrusionStyleLayer from '../style/style_layer/fill_extrusion_style_layer';
-
-export function prepareOffscreenFramebuffer(painter: Painter, layer: CustomStyleLayer | FillExtrusionStyleLayer) {
- const context = painter.context;
- const gl = context.gl;
-
- let renderTarget = layer.viewportFrame;
-
- if (painter.depthRboNeedsClear) {
- painter.setupOffscreenDepthRenderbuffer();
- }
-
- if (!renderTarget) {
- const texture = new Texture(context, {width: painter.width, height: painter.height, data: null}, gl.RGBA);
- texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
-
- renderTarget = layer.viewportFrame = context.createFramebuffer(painter.width, painter.height);
- renderTarget.colorAttachment.set(texture.texture);
- }
-
- context.bindFramebuffer.set(renderTarget.framebuffer);
- renderTarget.depthAttachment.set(painter.depthRbo);
-
- if (painter.depthRboNeedsClear) {
- context.clear({ depth: 1 });
- painter.depthRboNeedsClear = false;
- }
-
- context.clear({ color: Color.transparent });
-
- context.setStencilMode(StencilMode.disabled);
- context.setDepthMode(new DepthMode(gl.LEQUAL, DepthMode.ReadWrite, [0, 1]));
- context.setColorMode(painter.colorModeForRenderPass());
-}
-
-export function drawOffscreenTexture(painter: Painter, layer: CustomStyleLayer | FillExtrusionStyleLayer, opacity: number) {
- const renderedTexture = layer.viewportFrame;
- if (!renderedTexture) return;
-
- const context = painter.context;
- const gl = context.gl;
-
- context.activeTexture.set(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_2D, renderedTexture.colorAttachment.get());
-
- painter.useProgram('extrusionTexture').draw(context, gl.TRIANGLES,
- DepthMode.disabled, StencilMode.disabled,
- painter.colorModeForRenderPass(),
- CullFaceMode.disabled,
- extrusionTextureUniformValues(painter, opacity, 0),
- layer.id, painter.viewportBuffer, painter.quadTriangleIndexBuffer,
- painter.viewportSegments, layer.paint, painter.transform.zoom);
-}
diff --git a/src/render/painter.js b/src/render/painter.js
index 6ccd0ba4743..03cadf9e8ba 100644
--- a/src/render/painter.js
+++ b/src/render/painter.js
@@ -61,7 +61,7 @@ import type ImageManager from './image_manager';
import type GlyphManager from './glyph_manager';
import type VertexBuffer from '../gl/vertex_buffer';
import type IndexBuffer from '../gl/index_buffer';
-import type {DepthMaskType, DepthFuncType} from '../gl/types';
+import type {DepthRangeType, DepthMaskType, DepthFuncType} from '../gl/types';
export type RenderPass = 'offscreen' | 'opaque' | 'translucent';
@@ -108,9 +108,12 @@ class Painter {
lineAtlas: LineAtlas;
imageManager: ImageManager;
glyphManager: GlyphManager;
- depthRange: number;
+ depthRangeFor3D: DepthRangeType;
+ opaquePassCutoff: number;
renderPass: RenderPass;
currentLayer: number;
+ currentStencilSource: ?string;
+ nextStencilID: number;
id: string;
_showOverdrawInspector: boolean;
cache: { [string]: Program<*> };
@@ -219,6 +222,9 @@ class Painter {
const context = this.context;
const gl = context.gl;
+ this.nextStencilID = 1;
+ this.currentStencilSource = undefined;
+
// As a temporary workaround for https://github.com/mapbox/mapbox-gl-js/issues/5490,
// pending an upstream fix, we draw a fullscreen stencil=0 clipping mask here,
// effectively clearing the stencil buffer: once an upstream patch lands, remove
@@ -235,20 +241,28 @@ class Painter {
this.quadTriangleIndexBuffer, this.viewportSegments);
}
- _renderTileClippingMasks(tileIDs: Array) {
+ _renderTileClippingMasks(layer: StyleLayer, tileIDs: Array) {
+ if (this.currentStencilSource === layer.source || !layer.isTileClipped() || !tileIDs || !tileIDs.length) return;
+
+ this.currentStencilSource = layer.source;
+
const context = this.context;
const gl = context.gl;
+ if (this.nextStencilID + tileIDs.length > 256) {
+ // we'll run out of fresh IDs so we need to clear and start from scratch
+ this.clearStencil();
+ }
+
context.setColorMode(ColorMode.disabled);
context.setDepthMode(DepthMode.disabled);
const program = this.useProgram('clippingMask');
- let idNext = 1;
this._tileClippingMaskIDs = {};
for (const tileID of tileIDs) {
- const id = this._tileClippingMaskIDs[tileID.key] = idNext++;
+ const id = this._tileClippingMaskIDs[tileID.key] = this.nextStencilID++;
program.draw(context, gl.TRIANGLES, DepthMode.disabled,
// Tests will always pass, and ref value will be written to stencil buffer.
@@ -259,6 +273,16 @@ class Painter {
}
}
+ stencilModeFor3D(): StencilMode {
+ if (this.nextStencilID + 1 > 256) {
+ this.clearStencil();
+ }
+
+ const id = this.nextStencilID++;
+ const gl = this.context.gl;
+ return new StencilMode({ func: gl.NOTEQUAL, mask: 0xFF }, id, 0xFF, gl.KEEP, gl.KEEP, gl.REPLACE);
+ }
+
stencilModeForClipping(tileID: OverscaledTileID): StencilMode {
const gl = this.context.gl;
return new StencilMode({ func: gl.EQUAL, mask: 0xFF }, this._tileClippingMaskIDs[tileID.key], 0x00, gl.KEEP, gl.KEEP, gl.REPLACE);
@@ -278,11 +302,23 @@ class Painter {
}
}
- depthModeForSublayer(n: number, mask: DepthMaskType, func: ?DepthFuncType): DepthMode {
+ depthModeForSublayer(n: number, mask: DepthMaskType, func: ?DepthFuncType): $ReadOnly {
+ if (!this.opaquePassEnabledForLayer()) return DepthMode.disabled;
const depth = 1 - ((1 + this.currentLayer) * this.numSublayers + n) * this.depthEpsilon;
return new DepthMode(func || this.context.gl.LEQUAL, mask, [depth, depth]);
}
+ /*
+ * The opaque pass and 3D layers both use the depth buffer.
+ * Layers drawn above 3D layers need to be drawn using the
+ * painter's algorithm so that they appear above 3D features.
+ * This returns true for layers that can be drawn using the
+ * opaque pass.
+ */
+ opaquePassEnabledForLayer() {
+ return this.currentLayer < this.opaquePassCutoff;
+ }
+
render(style: Style, options: PainterOptions) {
this.style = style;
this.options = options;
@@ -323,6 +359,15 @@ class Painter {
updateTileMasks(visibleTiles, this.context);
}
+ this.opaquePassCutoff = Infinity;
+ for (let i = 0; i < layerIds.length; i++) {
+ const layerId = layerIds[i];
+ if (this.style._layers[layerId].is3D()) {
+ this.opaquePassCutoff = i;
+ break;
+ }
+ }
+
// Offscreen pass ===============================================
// We first do all rendering that requires rendering to a separate
// framebuffer, and then save those for rendering back to the map
@@ -345,36 +390,29 @@ class Painter {
// Clear buffers in preparation for drawing to the main framebuffer
this.context.clear({ color: options.showOverdrawInspector ? Color.black : Color.transparent, depth: 1 });
+ this.clearStencil();
this._showOverdrawInspector = options.showOverdrawInspector;
- this.depthRange = (style._order.length + 2) * this.numSublayers * this.depthEpsilon;
+ this.depthRangeFor3D = [0, 1 - ((style._order.length + 2) * this.numSublayers * this.depthEpsilon)];
// Opaque pass ===============================================
// Draw opaque layers top-to-bottom first.
this.renderPass = 'opaque';
- let prevSourceId;
for (this.currentLayer = layerIds.length - 1; this.currentLayer >= 0; this.currentLayer--) {
const layer = this.style._layers[layerIds[this.currentLayer]];
const sourceCache = sourceCaches[layer.source];
const coords = coordsAscending[layer.source];
- if (layer.source !== prevSourceId && sourceCache) {
- this.clearStencil();
- if (sourceCache.getSource().isTileClipped) {
- this._renderTileClippingMasks(coords);
- }
- }
-
+ this._renderTileClippingMasks(layer, coords);
this.renderLayer(this, sourceCache, layer, coords);
- prevSourceId = layer.source;
}
// Translucent pass ===============================================
// Draw all other layers bottom-to-top.
this.renderPass = 'translucent';
- for (this.currentLayer = 0, prevSourceId = null; this.currentLayer < layerIds.length; this.currentLayer++) {
+ for (this.currentLayer = 0; this.currentLayer < layerIds.length; this.currentLayer++) {
const layer = this.style._layers[layerIds[this.currentLayer]];
const sourceCache = sourceCaches[layer.source];
@@ -383,15 +421,8 @@ class Painter {
// separate clipping masks
const coords = (layer.type === 'symbol' ? coordsDescendingSymbol : coordsDescending)[layer.source];
- if (layer.source !== prevSourceId && sourceCache) {
- this.clearStencil();
- if (sourceCache.getSource().isTileClipped) {
- this._renderTileClippingMasks(coordsAscending[layer.source]);
- }
- }
-
+ this._renderTileClippingMasks(layer, coordsAscending[layer.source]);
this.renderLayer(this, sourceCache, layer, coords);
- prevSourceId = layer.source;
}
if (this.options.showTileBoundaries) {
diff --git a/src/render/program/fill_extrusion_program.js b/src/render/program/fill_extrusion_program.js
index 080420a9b37..dbf4a680d7a 100644
--- a/src/render/program/fill_extrusion_program.js
+++ b/src/render/program/fill_extrusion_program.js
@@ -10,7 +10,7 @@ import {
UniformMatrix4f
} from '../uniform_binding';
-import {mat3, vec3, mat4} from 'gl-matrix';
+import {mat3, vec3} from 'gl-matrix';
import { extend } from '../../util/util';
import type Context from '../../gl/context';
@@ -25,7 +25,8 @@ export type FillExtrusionUniformsType = {|
'u_lightpos': Uniform3f,
'u_lightintensity': Uniform1f,
'u_lightcolor': Uniform3f,
- 'u_vertical_gradient': Uniform1f
+ 'u_vertical_gradient': Uniform1f,
+ 'u_opacity': Uniform1f
|};
export type FillExtrusionPatternUniformsType = {|
@@ -41,13 +42,7 @@ export type FillExtrusionPatternUniformsType = {|
'u_pixel_coord_upper': Uniform2f,
'u_pixel_coord_lower': Uniform2f,
'u_scale': Uniform4f,
- 'u_fade': Uniform1f
-|};
-
-export type ExtrusionTextureUniformsType = {|
- 'u_matrix': UniformMatrix4f,
- 'u_world': Uniform2f,
- 'u_image': Uniform1i,
+ 'u_fade': Uniform1f,
'u_opacity': Uniform1f
|};
@@ -56,7 +51,8 @@ const fillExtrusionUniforms = (context: Context, locations: UniformLocations): F
'u_lightpos': new Uniform3f(context, locations.u_lightpos),
'u_lightintensity': new Uniform1f(context, locations.u_lightintensity),
'u_lightcolor': new Uniform3f(context, locations.u_lightcolor),
- 'u_vertical_gradient': new Uniform1f(context, locations.u_vertical_gradient)
+ 'u_vertical_gradient': new Uniform1f(context, locations.u_vertical_gradient),
+ 'u_opacity': new Uniform1f(context, locations.u_opacity)
});
const fillExtrusionPatternUniforms = (context: Context, locations: UniformLocations): FillExtrusionPatternUniformsType => ({
@@ -72,20 +68,15 @@ const fillExtrusionPatternUniforms = (context: Context, locations: UniformLocati
'u_pixel_coord_upper': new Uniform2f(context, locations.u_pixel_coord_upper),
'u_pixel_coord_lower': new Uniform2f(context, locations.u_pixel_coord_lower),
'u_scale': new Uniform4f(context, locations.u_scale),
- 'u_fade': new Uniform1f(context, locations.u_fade)
-});
-
-const extrusionTextureUniforms = (context: Context, locations: UniformLocations): ExtrusionTextureUniformsType => ({
- 'u_matrix': new UniformMatrix4f(context, locations.u_matrix),
- 'u_world': new Uniform2f(context, locations.u_world),
- 'u_image': new Uniform1i(context, locations.u_image),
+ 'u_fade': new Uniform1f(context, locations.u_fade),
'u_opacity': new Uniform1f(context, locations.u_opacity)
});
const fillExtrusionUniformValues = (
matrix: Float32Array,
painter: Painter,
- shouldUseVerticalGradient: boolean
+ shouldUseVerticalGradient: boolean,
+ opacity: number
): UniformValues => {
const light = painter.style.light;
const _lp = light.properties.get('position');
@@ -103,7 +94,8 @@ const fillExtrusionUniformValues = (
'u_lightpos': lightPos,
'u_lightintensity': light.properties.get('intensity'),
'u_lightcolor': [lightColor.r, lightColor.g, lightColor.b],
- 'u_vertical_gradient': +shouldUseVerticalGradient
+ 'u_vertical_gradient': +shouldUseVerticalGradient,
+ 'u_opacity': opacity
};
};
@@ -111,40 +103,21 @@ const fillExtrusionPatternUniformValues = (
matrix: Float32Array,
painter: Painter,
shouldUseVerticalGradient: boolean,
+ opacity: number,
coord: OverscaledTileID,
crossfade: CrossfadeParameters,
tile: Tile
): UniformValues => {
- return extend(fillExtrusionUniformValues(matrix, painter, shouldUseVerticalGradient),
+ return extend(fillExtrusionUniformValues(matrix, painter, shouldUseVerticalGradient, opacity),
patternUniformValues(crossfade, painter, tile),
{
'u_height_factor': -Math.pow(2, coord.overscaledZ) / tile.tileSize / 8
});
};
-const extrusionTextureUniformValues = (
- painter: Painter,
- opacity: number,
- textureUnit: number
-): UniformValues => {
- const matrix = mat4.create();
- mat4.ortho(matrix, 0, painter.width, painter.height, 0, 0, 1);
-
- const gl = painter.context.gl;
-
- return {
- 'u_matrix': matrix,
- 'u_world': [gl.drawingBufferWidth, gl.drawingBufferHeight],
- 'u_image': textureUnit,
- 'u_opacity': opacity
- };
-};
-
export {
fillExtrusionUniforms,
fillExtrusionPatternUniforms,
- extrusionTextureUniforms,
fillExtrusionUniformValues,
- fillExtrusionPatternUniformValues,
- extrusionTextureUniformValues
+ fillExtrusionPatternUniformValues
};
diff --git a/src/render/program/program_uniforms.js b/src/render/program/program_uniforms.js
index 5dbf64cef07..34fafaa4993 100644
--- a/src/render/program/program_uniforms.js
+++ b/src/render/program/program_uniforms.js
@@ -1,6 +1,6 @@
// @flow
-import { fillExtrusionUniforms, fillExtrusionPatternUniforms, extrusionTextureUniforms } from './fill_extrusion_program';
+import { fillExtrusionUniforms, fillExtrusionPatternUniforms } from './fill_extrusion_program';
import { fillUniforms, fillPatternUniforms, fillOutlineUniforms, fillOutlinePatternUniforms } from './fill_program';
import { circleUniforms } from './circle_program';
import { collisionUniforms } from './collision_program';
@@ -16,7 +16,6 @@ import { backgroundUniforms, backgroundPatternUniforms } from './background_prog
export const programUniforms = {
fillExtrusion: fillExtrusionUniforms,
fillExtrusionPattern: fillExtrusionPatternUniforms,
- extrusionTexture: extrusionTextureUniforms,
fill: fillUniforms,
fillPattern: fillPatternUniforms,
fillOutline: fillOutlineUniforms,
diff --git a/src/shaders/extrusion_texture.fragment.glsl b/src/shaders/extrusion_texture.fragment.glsl
deleted file mode 100644
index d857c50b894..00000000000
--- a/src/shaders/extrusion_texture.fragment.glsl
+++ /dev/null
@@ -1,11 +0,0 @@
-uniform sampler2D u_image;
-uniform float u_opacity;
-varying vec2 v_pos;
-
-void main() {
- gl_FragColor = texture2D(u_image, v_pos) * u_opacity;
-
-#ifdef OVERDRAW_INSPECTOR
- gl_FragColor = vec4(0.0);
-#endif
-}
diff --git a/src/shaders/extrusion_texture.vertex.glsl b/src/shaders/extrusion_texture.vertex.glsl
deleted file mode 100644
index 0e57d0faaf7..00000000000
--- a/src/shaders/extrusion_texture.vertex.glsl
+++ /dev/null
@@ -1,11 +0,0 @@
-uniform mat4 u_matrix;
-uniform vec2 u_world;
-attribute vec2 a_pos;
-varying vec2 v_pos;
-
-void main() {
- gl_Position = u_matrix * vec4(a_pos * u_world, 0, 1);
-
- v_pos.x = a_pos.x;
- v_pos.y = 1.0 - a_pos.y;
-}
diff --git a/src/shaders/fill_extrusion.vertex.glsl b/src/shaders/fill_extrusion.vertex.glsl
index df1b8556227..7a771b6dc97 100644
--- a/src/shaders/fill_extrusion.vertex.glsl
+++ b/src/shaders/fill_extrusion.vertex.glsl
@@ -3,6 +3,7 @@ uniform vec3 u_lightcolor;
uniform lowp vec3 u_lightpos;
uniform lowp float u_lightintensity;
uniform float u_vertical_gradient;
+uniform lowp float u_opacity;
attribute vec2 a_pos;
attribute vec4 a_normal_ed;
@@ -61,4 +62,5 @@ void main() {
v_color.r += clamp(color.r * directional * u_lightcolor.r, mix(0.0, 0.3, 1.0 - u_lightcolor.r), 1.0);
v_color.g += clamp(color.g * directional * u_lightcolor.g, mix(0.0, 0.3, 1.0 - u_lightcolor.g), 1.0);
v_color.b += clamp(color.b * directional * u_lightcolor.b, mix(0.0, 0.3, 1.0 - u_lightcolor.b), 1.0);
+ v_color *= u_opacity;
}
diff --git a/src/shaders/fill_extrusion_pattern.vertex.glsl b/src/shaders/fill_extrusion_pattern.vertex.glsl
index 4c314f19bff..2761d56b6a9 100644
--- a/src/shaders/fill_extrusion_pattern.vertex.glsl
+++ b/src/shaders/fill_extrusion_pattern.vertex.glsl
@@ -4,6 +4,7 @@ uniform vec2 u_pixel_coord_lower;
uniform float u_height_factor;
uniform vec4 u_scale;
uniform float u_vertical_gradient;
+uniform lowp float u_opacity;
uniform vec3 u_lightcolor;
uniform lowp vec3 u_lightpos;
@@ -71,4 +72,5 @@ void main() {
}
v_lighting.rgb += clamp(directional * u_lightcolor, mix(vec3(0.0), vec3(0.3), 1.0 - u_lightcolor), vec3(1.0));
+ v_lighting *= u_opacity;
}
diff --git a/src/shaders/shaders.js b/src/shaders/shaders.js
index 7c569fda562..85c9e058349 100644
--- a/src/shaders/shaders.js
+++ b/src/shaders/shaders.js
@@ -34,8 +34,6 @@ import fillExtrusionFrag from './fill_extrusion.fragment.glsl';
import fillExtrusionVert from './fill_extrusion.vertex.glsl';
import fillExtrusionPatternFrag from './fill_extrusion_pattern.fragment.glsl';
import fillExtrusionPatternVert from './fill_extrusion_pattern.vertex.glsl';
-import extrusionTextureFrag from './extrusion_texture.fragment.glsl';
-import extrusionTextureVert from './extrusion_texture.vertex.glsl';
import hillshadePrepareFrag from './hillshade_prepare.fragment.glsl';
import hillshadePrepareVert from './hillshade_prepare.vertex.glsl';
import hillshadeFrag from './hillshade.fragment.glsl';
@@ -71,7 +69,6 @@ export const fillOutlinePattern = compile(fillOutlinePatternFrag, fillOutlinePat
export const fillPattern = compile(fillPatternFrag, fillPatternVert);
export const fillExtrusion = compile(fillExtrusionFrag, fillExtrusionVert);
export const fillExtrusionPattern = compile(fillExtrusionPatternFrag, fillExtrusionPatternVert);
-export const extrusionTexture = compile(extrusionTextureFrag, extrusionTextureVert);
export const hillshadePrepare = compile(hillshadePrepareFrag, hillshadePrepareVert);
export const hillshade = compile(hillshadeFrag, hillshadeVert);
export const line = compile(lineFrag, lineVert);
diff --git a/src/style/style_layer.js b/src/style/style_layer.js
index 131f055aedf..263b123eab7 100644
--- a/src/style/style_layer.js
+++ b/src/style/style_layer.js
@@ -237,6 +237,14 @@ class StyleLayer extends Evented {
}));
}
+ is3D() {
+ return false;
+ }
+
+ isTileClipped() {
+ return false;
+ }
+
hasOffscreenPass() {
return false;
}
diff --git a/src/style/style_layer/custom_style_layer.js b/src/style/style_layer/custom_style_layer.js
index ebb88deedb5..9e585ff8a44 100644
--- a/src/style/style_layer/custom_style_layer.js
+++ b/src/style/style_layer/custom_style_layer.js
@@ -1,7 +1,6 @@
// @flow
import StyleLayer from '../style_layer';
-import type Framebuffer from '../../gl/framebuffer';
import type Map from '../../ui/map';
import assert from 'assert';
@@ -175,16 +174,18 @@ export function validateCustomStyleLayer(layerObject: CustomLayerInterface) {
class CustomStyleLayer extends StyleLayer {
implementation: CustomLayerInterface;
- viewportFrame: ?Framebuffer;
constructor(implementation: CustomLayerInterface) {
super(implementation, {});
this.implementation = implementation;
}
+ is3D() {
+ return this.implementation.renderingMode === '3d';
+ }
hasOffscreenPass() {
- return this.implementation.prerender !== undefined || this.implementation.renderingMode === '3d';
+ return this.implementation.prerender !== undefined;
}
recalculate() {}
@@ -195,13 +196,6 @@ class CustomStyleLayer extends StyleLayer {
assert(false, "Custom layers cannot be serialized");
}
- resize() {
- if (this.viewportFrame) {
- this.viewportFrame.destroy();
- this.viewportFrame = null;
- }
- }
-
onAdd(map: Map) {
if (this.implementation.onAdd) {
this.implementation.onAdd(map, map.painter.context.gl);
diff --git a/src/style/style_layer/fill_extrusion_style_layer.js b/src/style/style_layer/fill_extrusion_style_layer.js
index 1bfb784d641..9e90893e7b3 100644
--- a/src/style/style_layer/fill_extrusion_style_layer.js
+++ b/src/style/style_layer/fill_extrusion_style_layer.js
@@ -13,7 +13,6 @@ import Point from '@mapbox/point-geometry';
import type { FeatureState } from '../../style-spec/expression';
import type {BucketParameters} from '../../data/bucket';
import type {PaintProps} from './fill_extrusion_style_layer_properties';
-import type Framebuffer from '../../gl/framebuffer';
import type Transform from '../../geo/transform';
import type {LayerSpecification} from '../../style-spec/types';
@@ -21,7 +20,6 @@ class FillExtrusionStyleLayer extends StyleLayer {
_transitionablePaint: Transitionable;
_transitioningPaint: Transitioning;
paint: PossiblyEvaluated;
- viewportFrame: ?Framebuffer;
constructor(layer: LayerSpecification) {
super(layer, properties);
@@ -35,6 +33,10 @@ class FillExtrusionStyleLayer extends StyleLayer {
return translateDistance(this.paint.get('fill-extrusion-translate'));
}
+ is3D(): boolean {
+ return true;
+ }
+
queryIntersectsFeature(queryGeometry: Array,
feature: VectorTileFeature,
featureState: FeatureState,
@@ -59,17 +61,6 @@ class FillExtrusionStyleLayer extends StyleLayer {
const projectedTop = projected[1];
return checkIntersection(projectedBase, projectedTop, projectedQueryGeometry);
}
-
- hasOffscreenPass() {
- return this.paint.get('fill-extrusion-opacity') !== 0 && this.visibility !== 'none';
- }
-
- resize() {
- if (this.viewportFrame) {
- this.viewportFrame.destroy();
- this.viewportFrame = null;
- }
- }
}
function dot(a, b) {
diff --git a/src/style/style_layer/fill_style_layer.js b/src/style/style_layer/fill_style_layer.js
index 9d46e9cad1b..c7a555676d5 100644
--- a/src/style/style_layer/fill_style_layer.js
+++ b/src/style/style_layer/fill_style_layer.js
@@ -55,6 +55,10 @@ class FillStyleLayer extends StyleLayer {
transform.angle, pixelsToTileUnits);
return polygonIntersectsMultiPolygon(translatedPolygon, geometry);
}
+
+ isTileClipped() {
+ return true;
+ }
}
export default FillStyleLayer;
diff --git a/src/style/style_layer/line_style_layer.js b/src/style/style_layer/line_style_layer.js
index 224836e4ebb..63ce50f1c4b 100644
--- a/src/style/style_layer/line_style_layer.js
+++ b/src/style/style_layer/line_style_layer.js
@@ -110,6 +110,10 @@ class LineStyleLayer extends StyleLayer {
}
return polygonIntersectsBufferedMultiLine(translatedPolygon, geometry, halfWidth);
}
+
+ isTileClipped() {
+ return true;
+ }
}
export default LineStyleLayer;
diff --git a/src/ui/map.js b/src/ui/map.js
index ca86320323e..55a159fbf5f 100755
--- a/src/ui/map.js
+++ b/src/ui/map.js
@@ -75,6 +75,7 @@ type MapOptions = {
logoPosition?: ControlPosition,
failIfMajorPerformanceCaveat?: boolean,
preserveDrawingBuffer?: boolean,
+ antialias?: boolean,
refreshExpiredTiles?: boolean,
maxBounds?: LngLatBoundsLike,
scrollZoom?: boolean,
@@ -183,6 +184,7 @@ const defaultOptions = {
* @param {boolean} [options.failIfMajorPerformanceCaveat=false] If `true`, map creation will fail if the performance of Mapbox
* GL JS would be dramatically worse than expected (i.e. a software renderer would be used).
* @param {boolean} [options.preserveDrawingBuffer=false] If `true`, the map's canvas can be exported to a PNG using `map.getCanvas().toDataURL()`. This is `false` by default as a performance optimization.
+ * @param {boolean} [options.antialias] If `true`, create the gl context will be created with msaa antialiasing, which can be useful for antialiasing custom layers. this is `false` by default as a performance optimization.
* @param {boolean} [options.refreshExpiredTiles=true] If `false`, the map won't attempt to re-request tiles once they expire per their HTTP `cacheControl`/`expires` headers.
* @param {LngLatBoundsLike} [options.maxBounds] If set, the map will be constrained to the given bounds.
* @param {boolean|Object} [options.scrollZoom=true] If `true`, the "scroll to zoom" interaction is enabled. An `Object` value is passed as options to {@link ScrollZoomHandler#enable}.
@@ -255,6 +257,7 @@ class Map extends Camera {
_trackResize: boolean;
_preserveDrawingBuffer: boolean;
_failIfMajorPerformanceCaveat: boolean;
+ _antialias: boolean;
_refreshExpiredTiles: boolean;
_hash: Hash;
_delegatedListeners: any;
@@ -317,6 +320,7 @@ class Map extends Camera {
this._maxTileCacheSize = options.maxTileCacheSize;
this._failIfMajorPerformanceCaveat = options.failIfMajorPerformanceCaveat;
this._preserveDrawingBuffer = options.preserveDrawingBuffer;
+ this._antialias = options.antialias;
this._trackResize = options.trackResize;
this._bearingSnap = options.bearingSnap;
this._refreshExpiredTiles = options.refreshExpiredTiles;
@@ -1547,10 +1551,11 @@ class Map extends Camera {
}
_setupPainter() {
- const attributes = extend({
+ const attributes = extend({}, isSupported.webGLContextAttributes, {
failIfMajorPerformanceCaveat: this._failIfMajorPerformanceCaveat,
- preserveDrawingBuffer: this._preserveDrawingBuffer
- }, isSupported.webGLContextAttributes);
+ preserveDrawingBuffer: this._preserveDrawingBuffer,
+ antialias: this._antialias || false
+ });
const gl = this._canvas.getContext('webgl', attributes) ||
this._canvas.getContext('experimental-webgl', attributes);
diff --git a/test/ignores.json b/test/ignores.json
index ab5dfad74d0..57763daab8d 100644
--- a/test/ignores.json
+++ b/test/ignores.json
@@ -12,5 +12,6 @@
"render-tests/regressions/mapbox-gl-js#3682": "skip - true",
"render-tests/runtime-styling/image-update-icon": "skip - https://github.com/mapbox/mapbox-gl-js/issues/4804",
"render-tests/runtime-styling/image-update-pattern": "skip - https://github.com/mapbox/mapbox-gl-js/issues/4804",
- "render-tests/mixed-zoom/z10-z11": "current behavior conflicts with https://github.com/mapbox/mapbox-gl-js/pull/6803. can be fixed when https://github.com/mapbox/api-maps/issues/1480 is done"
+ "render-tests/mixed-zoom/z10-z11": "current behavior conflicts with https://github.com/mapbox/mapbox-gl-js/pull/6803. can be fixed when https://github.com/mapbox/api-maps/issues/1480 is done",
+ "render-tests/fill-extrusion-pattern/tile-buffer": "https://github.com/mapbox/mapbox-gl-js/issues/4403"
}
diff --git a/test/integration/render-tests/custom-layer-js/tent-3d/expected.png b/test/integration/render-tests/custom-layer-js/tent-3d/expected.png
index c6ee90d6690..cae223d5c02 100644
Binary files a/test/integration/render-tests/custom-layer-js/tent-3d/expected.png and b/test/integration/render-tests/custom-layer-js/tent-3d/expected.png differ
diff --git a/test/integration/render-tests/fill-extrusion-pattern/@2x/expected.png b/test/integration/render-tests/fill-extrusion-pattern/@2x/expected.png
index c7bdf3b886e..2994ade87fc 100644
Binary files a/test/integration/render-tests/fill-extrusion-pattern/@2x/expected.png and b/test/integration/render-tests/fill-extrusion-pattern/@2x/expected.png differ
diff --git a/test/integration/render-tests/fill-extrusion-pattern/@2x/style.json b/test/integration/render-tests/fill-extrusion-pattern/@2x/style.json
index d68b7d32b03..91ff69322a3 100644
--- a/test/integration/render-tests/fill-extrusion-pattern/@2x/style.json
+++ b/test/integration/render-tests/fill-extrusion-pattern/@2x/style.json
@@ -9,6 +9,7 @@
"sources": {
"geojson": {
"type": "geojson",
+ "buffer": 0,
"data": {
"type": "FeatureCollection",
"features": [
@@ -96,4 +97,4 @@
}
}
]
-}
\ No newline at end of file
+}
diff --git a/test/integration/render-tests/fill-extrusion-pattern/feature-expression/expected.png b/test/integration/render-tests/fill-extrusion-pattern/feature-expression/expected.png
index aa2ef97b9d5..d7573106f76 100644
Binary files a/test/integration/render-tests/fill-extrusion-pattern/feature-expression/expected.png and b/test/integration/render-tests/fill-extrusion-pattern/feature-expression/expected.png differ
diff --git a/test/integration/render-tests/fill-extrusion-pattern/feature-expression/style.json b/test/integration/render-tests/fill-extrusion-pattern/feature-expression/style.json
index 360934bf306..8e408e81f55 100644
--- a/test/integration/render-tests/fill-extrusion-pattern/feature-expression/style.json
+++ b/test/integration/render-tests/fill-extrusion-pattern/feature-expression/style.json
@@ -8,6 +8,7 @@
"sources": {
"geojson": {
"type": "geojson",
+ "buffer": 0,
"data": {
"type": "FeatureCollection",
"features": [
diff --git a/test/integration/render-tests/fill-extrusion-pattern/function-2/expected.png b/test/integration/render-tests/fill-extrusion-pattern/function-2/expected.png
index 367f73f7545..cd86e8dccfe 100644
Binary files a/test/integration/render-tests/fill-extrusion-pattern/function-2/expected.png and b/test/integration/render-tests/fill-extrusion-pattern/function-2/expected.png differ
diff --git a/test/integration/render-tests/fill-extrusion-pattern/function-2/style.json b/test/integration/render-tests/fill-extrusion-pattern/function-2/style.json
index 3b51dc820f6..fcde2e7bab0 100644
--- a/test/integration/render-tests/fill-extrusion-pattern/function-2/style.json
+++ b/test/integration/render-tests/fill-extrusion-pattern/function-2/style.json
@@ -9,6 +9,7 @@
"sources": {
"geojson": {
"type": "geojson",
+ "buffer": 0,
"data": {
"type": "FeatureCollection",
"features": [
diff --git a/test/integration/render-tests/fill-extrusion-pattern/function/expected.png b/test/integration/render-tests/fill-extrusion-pattern/function/expected.png
index 753a82851c4..e60cd56c3a6 100644
Binary files a/test/integration/render-tests/fill-extrusion-pattern/function/expected.png and b/test/integration/render-tests/fill-extrusion-pattern/function/expected.png differ
diff --git a/test/integration/render-tests/fill-extrusion-pattern/function/style.json b/test/integration/render-tests/fill-extrusion-pattern/function/style.json
index 9849b8ae27a..8ff57ee9568 100644
--- a/test/integration/render-tests/fill-extrusion-pattern/function/style.json
+++ b/test/integration/render-tests/fill-extrusion-pattern/function/style.json
@@ -8,6 +8,7 @@
"sources": {
"geojson": {
"type": "geojson",
+ "buffer": 0,
"data": {
"type": "FeatureCollection",
"features": [
@@ -107,4 +108,4 @@
}
}
]
-}
\ No newline at end of file
+}
diff --git a/test/integration/render-tests/fill-extrusion-pattern/literal/expected.png b/test/integration/render-tests/fill-extrusion-pattern/literal/expected.png
index 753a82851c4..8f4c7eb60d7 100644
Binary files a/test/integration/render-tests/fill-extrusion-pattern/literal/expected.png and b/test/integration/render-tests/fill-extrusion-pattern/literal/expected.png differ
diff --git a/test/integration/render-tests/fill-extrusion-pattern/literal/style.json b/test/integration/render-tests/fill-extrusion-pattern/literal/style.json
index 48abec51f93..39209caf993 100644
--- a/test/integration/render-tests/fill-extrusion-pattern/literal/style.json
+++ b/test/integration/render-tests/fill-extrusion-pattern/literal/style.json
@@ -8,6 +8,7 @@
"sources": {
"geojson": {
"type": "geojson",
+ "buffer": 0,
"data": {
"type": "FeatureCollection",
"features": [
@@ -95,4 +96,4 @@
}
}
]
-}
\ No newline at end of file
+}
diff --git a/test/integration/render-tests/fill-extrusion-pattern/opacity/expected.png b/test/integration/render-tests/fill-extrusion-pattern/opacity/expected.png
index 09f7eb3e18d..31f8fb76e34 100644
Binary files a/test/integration/render-tests/fill-extrusion-pattern/opacity/expected.png and b/test/integration/render-tests/fill-extrusion-pattern/opacity/expected.png differ
diff --git a/test/integration/render-tests/fill-extrusion-pattern/opacity/style.json b/test/integration/render-tests/fill-extrusion-pattern/opacity/style.json
index f8694f44428..f0435da36db 100644
--- a/test/integration/render-tests/fill-extrusion-pattern/opacity/style.json
+++ b/test/integration/render-tests/fill-extrusion-pattern/opacity/style.json
@@ -8,6 +8,7 @@
"sources": {
"geojson": {
"type": "geojson",
+ "buffer": 0,
"data": {
"type": "FeatureCollection",
"features": [
@@ -96,4 +97,4 @@
}
}
]
-}
\ No newline at end of file
+}
diff --git a/test/integration/render-tests/fill-extrusion-pattern/tile-buffer/expected.png b/test/integration/render-tests/fill-extrusion-pattern/tile-buffer/expected.png
new file mode 100644
index 00000000000..8b08b54ea97
Binary files /dev/null and b/test/integration/render-tests/fill-extrusion-pattern/tile-buffer/expected.png differ
diff --git a/test/integration/render-tests/fill-extrusion-pattern/tile-buffer/style.json b/test/integration/render-tests/fill-extrusion-pattern/tile-buffer/style.json
new file mode 100644
index 00000000000..dd60969401c
--- /dev/null
+++ b/test/integration/render-tests/fill-extrusion-pattern/tile-buffer/style.json
@@ -0,0 +1,98 @@
+{
+ "version": 8,
+ "metadata": {
+ "test": {
+ "height": 256
+ }
+ },
+ "sources": {
+ "geojson": {
+ "type": "geojson",
+ "data": {
+ "type": "FeatureCollection",
+ "features": [
+ {
+ "type": "Feature",
+ "properties": {
+ "property": 20
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ -0.0004,
+ 0
+ ],
+ [
+ -0.0002,
+ 0.0002
+ ],
+ [
+ 0,
+ 0
+ ],
+ [
+ -0.0002,
+ -0.0002
+ ],
+ [
+ -0.0004,
+ 0
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "property": 20
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 0,
+ -0.0002
+ ],
+ [
+ 0,
+ 0.0002
+ ],
+ [
+ 0.0003,
+ 0.0002
+ ],
+ [
+ 0.0003,
+ -0.0002
+ ],
+ [
+ 0,
+ -0.0002
+ ]
+ ]
+ ]
+ }
+ }
+ ]
+ }
+ }
+ },
+ "sprite": "local://sprites/emerald",
+ "pitch": 60,
+ "zoom": 18,
+ "layers": [
+ {
+ "id": "extrusion",
+ "type": "fill-extrusion",
+ "source": "geojson",
+ "paint": {
+ "fill-extrusion-pattern": "generic_icon",
+ "fill-extrusion-height": 10
+ }
+ }
+ ]
+}