Skip to content

Commit

Permalink
implement custom style layers (#7039)
Browse files Browse the repository at this point in the history
  • Loading branch information
ansis authored Sep 6, 2018
1 parent d97474c commit f556bee
Show file tree
Hide file tree
Showing 32 changed files with 1,440 additions and 170 deletions.
2 changes: 1 addition & 1 deletion debug/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"prefer-template": "off"
},
"env": {
"es6": false,
"es6": true,
"browser": true
},
"globals": {
Expand Down
117 changes: 117 additions & 0 deletions debug/custom3d.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<!DOCTYPE html>
<html>
<head>
<title>Mapbox GL JS debug page</title>
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link rel='stylesheet' href='/dist/mapbox-gl.css' />
<style>
body { margin: 0; padding: 0; }
html, body, #map { height: 100%; }
</style>
</head>

<body>
<div id='map'></div>

<script src='/dist/mapbox-gl-dev.js'></script>
<script src='/debug/access_token_generated.js'></script>
<script>


var map = window.map = new mapboxgl.Map({
container: 'map',
zoom: 1.69,
center: [-9.4, -26.8],
bearing: 131,
pitch: 60,
style: 'mapbox://styles/mapbox/light-v9',
hash: true
});

class Custom {
constructor() {
this.id = 'mycustomlayer';
this.type = 'custom';
this.renderingMode = '3d';
}

onAdd(map, gl) {

const vertexSource = `
attribute vec3 aPos;
uniform mat4 uMatrix;
void main() {
gl_Position = uMatrix * vec4(aPos, 1.0);
}
`;

const fragmentSource = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;

const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexSource);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentSource);
gl.compileShader(fragmentShader);

this.program = gl.createProgram();
gl.attachShader(this.program, vertexShader);
gl.attachShader(this.program, fragmentShader);
gl.linkProgram(this.program);
gl.validateProgram(this.program);

this.program.aPos = gl.getAttribLocation(this.program, "aPos");
this.program.uMatrix = gl.getUniformLocation(this.program, "uMatrix");

const x = 0.5;
const y = 0.5;
const z = 0.125;
const d = 0.125;

const vertexArray = new Float32Array([
x, y, 0,
x + d, y, 0,
x, y + d, z,
x + d, y + d, z,
x, y + d + d, 0,
x + d, y + d + d, 0]);
const indexArray = new Uint16Array([
0, 1, 2,
1, 2, 3,
2, 3, 4,
3, 4, 5
]);

this.vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertexArray, gl.STATIC_DRAW);
this.indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexArray, gl.STATIC_DRAW);
}

render(gl, matrix) {
gl.useProgram(this.program);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
gl.enableVertexAttribArray(this.program.a_pos);
gl.vertexAttribPointer(this.program.aPos, 3, gl.FLOAT, false, 0, 0);
gl.uniformMatrix4fv(this.program.uMatrix, false, matrix);
gl.drawElements(gl.TRIANGLES, 12, gl.UNSIGNED_SHORT, 0);
}
}

map.on('load', function() {
map.addLayer(new Custom());
});

</script>
</body>
</html>
101 changes: 101 additions & 0 deletions debug/threejs.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<!DOCTYPE html>
<html>
<head>
<title>Mapbox GL JS debug page</title>
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link rel='stylesheet' href='/dist/mapbox-gl.css' />
<style>
body { margin: 0; padding: 0; }
html, body, #map { height: 100%; }
</style>
</head>

<body>
<div id='map'></div>

<script src='/dist/mapbox-gl-dev.js'></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/94/three.min.js"></script>
<script src='/debug/access_token_generated.js'></script>
<script>


var map = window.map = new mapboxgl.Map({
container: 'map',
zoom: 16.5,
center: [-79.390307, 43.658956],
bearing: 20,
pitch: 60,
style: 'mapbox://styles/mapbox/light-v9',
hash: true
});

const THREE = window.THREE;

class ThreeJSCube {
constructor() {
this.id = 'mycustomlayer';
this.type = 'custom';
this.renderingMode = '3d';

this.translate = [0.279471, 0.364935, 0.0000025];
this.scale = 0.000003;

this.camera = new THREE.Camera();
this.scene = new THREE.Scene();

var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshPhongMaterial({ color: 0xeeeeff });
this.cube = new THREE.Mesh(geometry, material);
this.scene.add(this.cube);

const directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(0, -70, 100).normalize();
this.scene.add(directionalLight);
}

onAdd(map, gl) {
this.map = map;

this.renderer = new THREE.WebGLRenderer({
canvas: map.getCanvas(),
context: gl
});

this.renderer.autoClear = false;
}

render(gl, matrix) {
const m = new THREE.Matrix4().fromArray(matrix);
const l = new THREE.Matrix4().makeTranslation(this.translate[0], this.translate[1], this.translate[2])
.scale(new THREE.Vector3(this.scale, -this.scale, this.scale));
this.cube.rotation.x += 0.01;
this.cube.rotation.y += 0.01;

this.camera.projectionMatrix.elements = matrix;
this.camera.projectionMatrix = m.multiply(l);
this.renderer.state.reset();
this.renderer.render(this.scene, this.camera);
this.map.triggerRepaint();
}
}

map.on('load', function() {
map.addLayer({
'id': '3d-buildings',
'source': 'composite',
'source-layer': 'building',
'filter': ['==', 'extrude', 'true'],
'type': 'fill-extrusion',
'minzoom': 15,
'paint': {
'fill-extrusion-color': '#ccc',
'fill-extrusion-height': ["get", "height"]
}
});

map.addLayer(new ThreeJSCube());
});
</script>
</body>
</html>
1 change: 1 addition & 0 deletions docs/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ toc:
- CameraOptions
- PaddingOptions
- RequestParameters
- CustomLayerInterface
- name: Geography & Geometry
description: |
`LngLat` and `LngLatBounds` represent points and rectanges in geographic
Expand Down
52 changes: 52 additions & 0 deletions docs/pages/example/custom-style-layer.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<div id='map'></div>
<script>
var map = window.map = new mapboxgl.Map({
container: 'map',
zoom: 4,
center: [0, 0],
style: 'mapbox://styles/mapbox/light-v9',
hash: true
});


var nullIslandLayer = {
id: 'null-island',
type: 'custom',

onAdd: function (map, gl) {
var vertexSource = "" +
"uniform mat4 u_matrix;" +
"void main() {" +
" gl_Position = u_matrix * vec4(0.5, 0.5, 0.0, 1.0);" +
" gl_PointSize = 100.0;" +
"}";

var fragmentSource = "" +
"void main() {" +
" gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);" +
"}";

var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexSource);
gl.compileShader(vertexShader);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentSource);
gl.compileShader(fragmentShader);

this.program = gl.createProgram();
gl.attachShader(this.program, vertexShader);
gl.attachShader(this.program, fragmentShader);
gl.linkProgram(this.program);
},

render: function(gl, matrix) {
gl.useProgram(this.program);
gl.uniformMatrix4fv(gl.getUniformLocation(this.program, "u_matrix"), false, matrix);
gl.drawArrays(gl.POINTS, 0, 1);
}
};

map.on('load', function() {
map.addLayer(nullIslandLayer);
});
</script>
10 changes: 10 additions & 0 deletions docs/pages/example/custom-style-layer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*---
title: Add a custom style layer
description: Use a custom style layer to add custom gl rendering.
tags:
- layers
pathname: /mapbox-gl-js/example/custom-style-layer/
---*/
import Example from '../../components/example';
import html from './custom-style-layer.html';
export default Example(html);
9 changes: 9 additions & 0 deletions src/geo/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class Transform {
zoomFraction: number;
pixelsToGLUnits: [number, number];
cameraToCenterDistance: number;
mercatorMatrix: Array<number>;
projMatrix: Float64Array;
alignedProjMatrix: Float64Array;
pixelMatrix: Float64Array;
Expand Down Expand Up @@ -464,6 +465,10 @@ class Transform {
return cache[posMatrixKey];
}

customLayerMatrix(): Array<number> {
return this.mercatorMatrix.slice();
}

_constrain() {
if (!this.center || !this.width || !this.height || this._constraining) return;

Expand Down Expand Up @@ -560,6 +565,10 @@ class Transform {
mat4.rotateZ(m, m, this.angle);
mat4.translate(m, m, [-x, -y, 0]);

// The mercatorMatrix can be used to transform points from mercator coordinates
// ([0, 0] nw, [1, 1] se) to GL coordinates.
this.mercatorMatrix = mat4.scale([], m, [this.worldSize, this.worldSize, this.worldSize]);

// scale vertically to meters per pixel (inverse of ground resolution):
// worldSize / (circumferenceOfEarth * cos(lat * π / 180))
const verticalScale = this.worldSize / (2 * Math.PI * 6378137 * Math.abs(Math.cos(this.center.lat * (Math.PI / 180))));
Expand Down
Loading

0 comments on commit f556bee

Please sign in to comment.