從0開始疫情3D地球 - 3D疫情地球VDEarth - 3 - 3D地球組件實現(1)

接上篇,已經搭建好前端代碼框架,本文開始進行前端代碼的開發css

 

 

準備工做html

地球採用球體+蒙皮的方式實現,貼圖來自echarts: https://www.echartsjs.com/examples/data-gl/asset/world.topo.bathy.200401.jpg,下載貼圖jpg文件,存放至image文件夾,命名爲world.jpg前端

1 html模板 index.htmlnpm

在public文件夾中建立index.html,修改文件內容爲json

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4   <meta charset="UTF-8">
 5   <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6   <title>新冠疫情感染數</title>  
 7   <style>
 8     *{
 9       padding:0;
10       margin:0
11     }
12     .container {
13       overflow: hidden;
14       position: fixed;
15       top: 0;
16       left: 0;
17       right:0;
18       bottom: 0;
19       display: flex;
20       flex-direction: row;
21       margin: 0 auto;
22     }
23   </style>
24   <script src="https://cdn.bootcss.com/lodash.js/4.17.15/lodash.min.js"></script>
25 </head>
26 <body>
27   <div class="container"></div>
28 </body>
29   <script>
30     // 調用組件
31     VDEarth.init({container:document.querySelector('.container')});
32   </script>
33 </html>
View Code

 

2 主文件VDEarth.js瀏覽器

建立一個VDEarth類,構造屬性,方法app

class VDEarth{
     constructor() {
        this.scene = null;
        this.camera = null;
        this.renderer = null;
        this.textrue = null;
        this.font = null;
        this.light = null;
        this.controls = null;
        this.contentWidth = 0;
        this.contentHeight = 0;
        this.options={}    
     }
     init(opt = {}) {}
}
export default VDEarth;
View Code

修改初始化方法initecharts

因爲地球貼圖圖片較大,這裏在初始化的時候進行加載,加載完成後回調場景, 相機,渲染器,燈光,控制器,建立模型,動態更新等方法,具體實現參考後面地球實現章節。框架

 1   init(opt = {}) {
 2     var self = this;
 3     // 合併用戶配置屬性
 4     _.merge(this.options, opt);
 5 
 6     // 獲取容器的寬高
 7     this.contentWidth = this.options.container.offsetWidth;
 8     this.contentHeight = this.options.container.offsetHeight;
 9     // 加載貼圖
10     let globeTextureLoader = new TextureLoader();
11     globeTextureLoader.load('./images/world.jpg', function (textrue) {
12       self.textrue = textrue;
13       // 初始化渲染器
14       initRenderer.call(self);
15       // 初始化舞臺
16       initScene.call(self);
17       // 初始化相機
18       initCamera.call(self);
19       // 初始化燈光
20       initLight.call(self);
21       // 初始化控制器
22       initControls.call(self);
23       // 初始化模型
24       initObj.call(self);
25       // 播放
26       animate.call(self);
27     });
28   }
View Code

 

3 組件入口index.jsdom

調用VDEarth類,export一個初始化的方法供頁面調用

1 import VDEarth from './VDEarth';
2 
3 var myVDEarth = new VDEarth();
4 export function init(opt) {
5   return myVDEarth.init(opt);
6 }
View Code

 

4 組件初始化

建立場景

VDEarth.js中添加私有方法

// 初始化場景
function initScene() {
  this.scene = new Scene();
}

建立渲染器

VDEarth.js中添加私有方法

// 初始化渲染器
function initRenderer() {
  this.renderer = new WebGLRenderer({ antialias: true });
  this.renderer.setSize(this.contentWidth, this.contentHeight);
  this.options.container.appendChild(this.renderer.domElement);
}

建立相機

VDEarth.js中添加私有方法

// 初始化照相機
function initCamera() {
  this.camera = new PerspectiveCamera(50,this.contentWidth / this.contentHeight,1,2000);
  this.camera.up.x = 0;
  this.camera.up.y = 1;
  this.camera.up.z = 0;
  this.camera.position.x = 0;
  this.camera.position.y = 0;
  this.camera.position.z = 500;
  this.camera.lookAt(0, 0, 0);
}

建立燈光

VDEarth.js中添加私有方法

// 初始化燈光
function initLight() {
  // 天然光
  this.scene.add(new AmbientLight(0xffffff));
}

建立控制器

VDEarth.js中添加私有方法,建立一個盤旋控制器

// 盤旋控制器
function initControls() {
  this.controls = new OrbitControls(this.camera, this.renderer.domElement);
  // 若是使用animate方法時,將此函數刪除
  // 使動畫循環使用時阻尼或自轉 意思是否有慣性
  this.controls.enableDamping = true;
  //動態阻尼係數 就是鼠標拖拽旋轉靈敏度
  //controls.dampingFactor = 0.25;
  //是否能夠縮放
  this.controls.enableZoom = true;
  //是否自動旋轉
  this.controls.autoRotate = false;
  //是否容許旋轉
  this.controls.enableRotate = true;
  //設置相機距離原點的最近距離
  this.controls.minDistance = 20;
  //設置相機距離原點的最遠距離
  this.controls.maxDistance = 1000;
  //是否開啓右鍵拖拽
  this.controls.enablePan = false;
}

建立實時更新方法

VDEarth.js增長私有方法

// 實時更新
function animate() {
  //更新控制器
  this.controls.update();
  render.call(this);
  requestAnimationFrame(animate.bind(this));
}

地球的實現

地球採用球體+蒙皮的方式實現,貼圖來自echarts: https://www.echartsjs.com/examples/data-gl/asset/world.topo.bathy.200401.jpg,下載貼圖jpg文件

建立地球模型

建立材質 - material.js

建立方法createGlobeMat 接受一個蒙皮的參數 textrue

import {
  MeshStandardMaterial,
  PointsMaterial,
  MeshPhongMaterial,
  DoubleSide,
  MeshBasicMaterial,
} from 'three';
class material {
  constructor() {}
  createGlobeMat(texture) {
    let mat = new MeshStandardMaterial({
      map: texture,
    });
    return mat;
  }
}

建立geometry -geometry.js

建立一個球體,createGlobeGeom接受一個size屬性,用來定義地球的半徑

class vdGeom {
  constructor() {}
  createGlobeGeom(size) {
    let geom = new SphereGeometry(size, 200, 200);
    return geom;
  }
}

建立地球對象- model.js

一個threejs的模型的對象,包含materail和geometry,這裏引入前面的geometry.js 和material.js

 1 import { Mesh, Points } from 'three';
 2 import material from './material';
 3 import geometry from './geometry';
 4 class mesh {
 5   constructor() {
 6     this.vdGeom = new geometry();
 7     this.vdMaterial = new material();
 8   }
 9   createGlobe(size,textrue) {
10     let vdGeom = this.vdGeom.createGlobeGeom(size);
11     let vdMaterial = this.vdMaterial.createGlobeMat(textrue);
12     return new Mesh(vdGeom, vdMaterial);
13   }
14 }
15 export default mesh;
View Code

 調用建立地球隊形-VDEarth.js

新增私有方法 initObj,初始化地球模型的加載

function initObj() {
  let self = this;
  let fontloader = new FontLoader();
  // 建立地球模型組
  this.baseGroup = new Group();
  // 建立地球
  this.radius = minSize(this.contentWidth, this.contentHeight) * 0.2;
  let globalMesh = new model().createGlobe(this.radius, this.textrue);
  this.baseGroup.add(globalMesh);
  // 添加到場景
  this.scene.add(this.baseGroup);
}

修改init方法,增長initObj的調用

init(opt = {}) {
    var self = this;
    // 合併用戶配置屬性
    _.merge(this.options, opt);

    // 獲取容器的寬高
    this.contentWidth = this.options.container.offsetWidth;
    this.contentHeight = this.options.container.offsetHeight;
    // 加載貼圖
    let globeTextureLoader = new TextureLoader();
    globeTextureLoader.load('./images/world.jpg', function (textrue) {
      self.textrue = textrue;
      // 初始化渲染器
      initRenderer.call(self);
      // 初始化舞臺
      initScene.call(self);
      // 初始化相機
      initCamera.call(self);
      // 初始化燈光
      initLight.call(self);
      // 初始化控制器
      initControls.call(self);
      // 初始化模型
      initObj.call(self);
      .
      .
      .
    });
  }

而後一個簡單的地球就實現了,npm run start ,打開瀏覽器就能夠看到一個3D地球,能夠經過鼠標進行拖拽,旋轉等操做

 

 

加點佐料

這裏地球是靜止的,加上地球自轉效果

修改VDEarth.js 內 的animate方法,增長地球自轉的代碼

// 實時更新
function animate() {
  //更新控制器
  this.controls.update();
  render.call(this);

  // 地球自轉
  this.baseGroup.rotation.y -= 0.002;
  requestAnimationFrame(animate.bind(this));
}

刷新下瀏覽器,地球就能夠轉動起來了

文內未說明import的模塊,能夠參照上篇裏的環境搭建的pagekage.json ,  npm 安裝響應的組件

 

相關連接

從0開始疫情3D地球 - 3D疫情地球VDEarth - 1- 引言 

從0開始疫情3D地球 - 3D疫情地球VDEarth - 2 - 前端代碼構建 

從0開始疫情3D地球 - 3D疫情地球VDEarth - 3 - 3D地球組件實現(1) 

從0開始疫情3D地球 - 3D疫情地球VDEarth - 4 - 3D地球組件實現(2) 

從0開始疫情3D地球 - 3D疫情地球VDEarth - 5 - 疫情數據爬蟲 

從0開始疫情3D地球 - 3D疫情地球VDEarth - 6 - 數據推送  

相關文章
相關標籤/搜索