|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<meta charset='utf-8' /> |
|
<title>Add a 3D model to Mapbox</title> |
|
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' /> |
|
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.1.0-beta.1/mapbox-gl.js"></script> |
|
<link rel="stylesheet" type="text/css" href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.1.0-beta.1/mapbox-gl.css"> |
|
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/94/three.min.js'></script> |
|
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/loaders/GLTFLoader.js"></script> |
|
<style> |
|
body { margin:0; padding:0; } |
|
#map { position:absolute; top:0; bottom:0; width:100%; } |
|
#controls { position:absolute; top:0; left:0; } |
|
</style> |
|
</head> |
|
<body> |
|
<div id='map'></div> |
|
|
|
<script> |
|
mapboxgl.accessToken = 'pk.eyJ1IjoicnNiYXVtYW5uIiwiYSI6ImNqNmhkZnhkZDA4M3Yyd3AwZDR4cmdhcDIifQ.TGKKAC6pPP0L-uMDJ5xFAA'; |
|
|
|
// Load the mapbox map |
|
var map = new mapboxgl.Map({ |
|
container: 'map', |
|
style: 'mapbox://styles/mapbox/outdoors-v11?optimize=true', |
|
center: [148.98190, -35.39847], |
|
zoom: 17.5, |
|
pitch: 60, |
|
antialias: true |
|
}); |
|
|
|
// converts from WGS84 Longitude, Latitude into a unit vector anchor at the top left as needed for GL JS custom layers |
|
var fromLL = function (lon,lat) { |
|
// derived from https://gist.github.com/springmeyer/871897 |
|
var extent = 20037508.34; |
|
|
|
var x = lon * extent / 180; |
|
var y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180); |
|
y = y * extent / 180; |
|
|
|
return [(x + extent) / (2 * extent), 1 - ((y + extent) / (2 * extent))]; |
|
} |
|
var translate = fromLL(148.98190, -35.39847); |
|
|
|
var transform = { |
|
translateX: translate[0], |
|
translateY: translate[1], |
|
translateZ: 0, |
|
rotateX: Math.PI / 2, |
|
rotateY: 0, |
|
rotateZ: 0, |
|
scale: 5.41843220338983e-8 |
|
} |
|
|
|
var THREE = window.THREE; |
|
|
|
// Create the Mapbox Custom Layer object |
|
// See |
|
var threeJSModel = { |
|
id: 'custom_layer', |
|
type: 'custom', |
|
renderingMode: '3d', |
|
onAdd: function(map, gl) { |
|
this.camera = new THREE.Camera(); |
|
this.scene = new THREE.Scene(); |
|
|
|
var directionalLight = new THREE.DirectionalLight(0xffffff); |
|
directionalLight.position.set(0, -70, 100).normalize(); |
|
this.scene.add(directionalLight); |
|
|
|
var directionalLight2 = new THREE.DirectionalLight(0xffffff); |
|
directionalLight2.position.set(0, 70, 100).normalize(); |
|
this.scene.add(directionalLight2); |
|
|
|
var loader = new THREE.GLTFLoader(); |
|
loader.load('34M_17.gltf', (function (gltf) { |
|
this.scene.add(gltf.scene); |
|
}).bind(this)); |
|
this.map = map; |
|
|
|
this.renderer = new THREE.WebGLRenderer({ |
|
canvas: map.getCanvas(), |
|
context: gl |
|
}); |
|
|
|
this.renderer.autoClear = false; |
|
}, |
|
render: function(gl, matrix) { |
|
var rotationX = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(1, 0, 0), transform.rotateX); |
|
var rotationY = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 1, 0), transform.rotateY); |
|
var rotationZ = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 0, 1), transform.rotateZ); |
|
|
|
var m = new THREE.Matrix4().fromArray(matrix); |
|
var l = new THREE.Matrix4().makeTranslation(transform.translateX, transform.translateY, transform.translateZ) |
|
.scale(new THREE.Vector3(transform.scale, -transform.scale, transform.scale)) |
|
.multiply(rotationX) |
|
.multiply(rotationY) |
|
.multiply(rotationZ); |
|
|
|
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('style.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"] |
|
} |
|
}, 'waterway-label'); |
|
|
|
map.addLayer(threeJSModel, 'waterway-label'); |
|
}); |
|
</script> |
|
|
|
</body> |
|
</html> |