-
[Web] Mapbox 활용하기 3Dmap(three.js 라이브러리)Web 2019. 11. 21. 13:20
이번에는 Mapbox를 활용하여 web상에 3D지도를 올려보겠습니다.
먼저 Mapbox사이트에서 예제를 복사합니다.
https://docs.mapbox.com/mapbox-gl-js/example/3d-buildings/
이제 위도와 경도를 원하는 위치로 바꿔주고 style을 원하는 지도 색으로 바꿉니다. accessToken은 사이트 로그인을 해서 각자 API키를 생성하고 붙여넣기 합니다.
<!DOCTYPE html> <html> <head> <meta charset='utf-8' /> <title>Display buildings in 3D</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.5.0/mapbox-gl.js'></script> <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.5.0/mapbox-gl.css' rel='stylesheet' /> <style> body { margin:0; padding:0; } #map { position:absolute; top:0; bottom:0; width:100%; } </style> </head> <body> <div id='map'></div> <script> mapboxgl.accessToken = 'pk.eyJ1IjoianV5ZW9uZyIsImEiOiJjand2ZnE3OTEwMnIxNDhwY2o5c3E3OXZiIn0.QqunDiqyjmZBsm8avQBM3g'; var map = window.map = new mapboxgl.Map({ container: 'map', style: 'mapbox://styles/mapbox/streets-v10', zoom: 15, center: [126.735901, 37.348980], pitch: 0, antialias: true // create the gl context with MSAA antialiasing, so custom layers are antialiased }); </script> </body> </html>
그리고 three.js를 활용하여 3D오브젝트 파일을 가져와 지도 위에 올려보겠습니다.
한 폴더 안에 html파일과 obj파일, three.js 라이브러리를 넣습니다.
three.js 라이브러리는 https://threejs.org/ 홈페이지에서 다운받을 수 있습니다.
<script src="js/three.js"></script> <script src="js/OBJLoader.js"></script> <script src="js/OrbitControls.js"></script>
스크립트로 라이브러리를 가져옵니다. OBJLoader는 obj파일을 가져오고 OrbitControls는 마우스 컨트롤 할 수 있는 기능을 추가합니다.
그리고 three.js에서 사용하는 화면(Scene)과 카메라(Camera)를 추가하고 빛(directlight)을 비추어 그림자를 만듭니다. 건물이 입체적으로 표현될 수 있습니다.
this.camera = new THREE.Camera(); this.scene = new THREE.Scene(); // create two three.js lights to illuminate the model 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);
다음은 maps.obj파일을 불러오는 방법입니다. loader함수를 사용하여 크기와 위치를 조정할 수 있습니다.
var loader = new THREE.OBJLoader(); loader.load('maps.obj', (function(object) { object.scale.set(1000, 1000, 1000); object.position.set(-5420, 0, 5420); // object.position(0,0,0); this.scene.add(object); }).bind(this)); this.map = map; // use the Mapbox GL JS map canvas for three.js this.renderer = new THREE.WebGLRenderer({ canvas: map.getCanvas(), context: gl, antialias: true });
전체코드
<!DOCTYPE html> <html> <head> <meta charset='utf-8' /> <title>Display buildings in 3D</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.5.0/mapbox-gl.js'></script> <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.5.0/mapbox-gl.css' rel='stylesheet' /> <style> body { margin: 0; padding: 0; } #map { position: absolute; top: 0; bottom: 0; width: 100%; } </style> </head> <body> <script src="js/three.js"></script> <script src="js/OBJLoader.js"></script> <script src="js/OrbitControls.js"></script> <div id='map'></div> <script> mapboxgl.accessToken = 'pk.eyJ1IjoianV5ZW9uZyIsImEiOiJjand2ZnE3OTEwMnIxNDhwY2o5c3E3OXZiIn0.QqunDiqyjmZBsm8avQBM3g'; var map = window.map = new mapboxgl.Map({ container: 'map', style: 'mapbox://styles/mapbox/streets-v10', zoom: 15, center: [126.735901, 37.348980], pitch: 0, antialias: true // create the gl context with MSAA antialiasing, so custom layers are antialiased }); // parameters to ensure the model is georeferenced correctly on the map var modelOrigin = [126.735901, 37.348980]; var modelAltitude = 0; var modelRotate = [Math.PI / 2, 0, 0]; var modelAsMercatorCoordinate = mapboxgl.MercatorCoordinate.fromLngLat(modelOrigin, modelAltitude); // transformation parameters to position, rotate and scale the 3D model onto the map var modelTransform = { translateX: modelAsMercatorCoordinate.x, translateY: modelAsMercatorCoordinate.y, translateZ: modelAsMercatorCoordinate.z, rotateX: modelRotate[0], rotateY: modelRotate[1], rotateZ: modelRotate[2], /* Since our 3D model is in real world meters, a scale transform needs to be * applied since the CustomLayerInterface expects units in MercatorCoordinates. */ scale: modelAsMercatorCoordinate.meterInMercatorCoordinateUnits() }; var THREE = window.THREE; // configuration of the custom layer for a 3D model per the CustomLayerInterface var customLayer = { id: '3d-model', type: 'custom', renderingMode: '3d', onAdd: function(map, gl) { this.camera = new THREE.Camera(); this.scene = new THREE.Scene(); // create two three.js lights to illuminate the model 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.OBJLoader(); loader.load('maps.obj', (function(object) { object.scale.set(1000, 1000, 1000); object.position.set(-5420, 0, 5420); // object.position(0,0,0); this.scene.add(object); }).bind(this)); this.map = map; // use the Mapbox GL JS map canvas for three.js this.renderer = new THREE.WebGLRenderer({ canvas: map.getCanvas(), context: gl, antialias: true }); this.renderer.autoClear = false; }, render: function(gl, matrix) { var rotationX = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(1, 0, 0), modelTransform.rotateX); var rotationY = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 1, 0), modelTransform.rotateY); var rotationZ = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 0, 1), modelTransform.rotateZ); var m = new THREE.Matrix4().fromArray(matrix); var l = new THREE.Matrix4().makeTranslation(modelTransform.translateX, modelTransform.translateY, modelTransform.translateZ) .scale(new THREE.Vector3(modelTransform.scale, -modelTransform.scale, modelTransform.scale)) .multiply(rotationX) .multiply(rotationY) .multiply(rotationZ); 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(customLayer, 'waterway-label'); }); </script> </body> </html>
이제 자신이 원하는 obj모델을 가져와서 웹에 보여줄 수 있습니다.
'Web' 카테고리의 다른 글
[Web] Leaflet 활용하기 2Dmap (2) 2019.11.20