ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [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/

     

    Display buildings in 3D

    Use extrusions to display buildings' height in 3D.

    docs.mapbox.com

    3D 지도 예제

    이제 위도와 경도를 원하는 위치로 바꿔주고 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
Designed by Tistory.