• 从0开始疫情3D地球


    接上篇,已经搭建好前端代码框架,本文开始进行前端代码的开发

    准备工作

    地球采用球体+蒙皮的方式实现,贴图来自echarts: https://www.echartsjs.com/examples/data-gl/asset/world.topo.bathy.200401.jpg,下载贴图jpg文件,存放至image文件夹,命名为world.jpg

    1 html模板 index.html

    在public文件夹中创建index.html,修改文件内容为

     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类,构造属性,方法

    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

    修改初始化方法init

    由于地球贴图图片较大,这里在初始化的时候进行加载,加载完成后回调场景, 相机,渲染器,灯光,控制器,创建模型,动态更新等方法,具体实现参考后面地球实现章节。

     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.js

    调用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 - 数据推送  

  • 相关阅读:
    UVA1452|LA4727-----Jump------经典的约瑟夫公式的变形(DP)
    ORM框架Hibernate (四) 一对一单向、双向关联映射
    heaters
    对SIGQUIT的实验 & Java dump
    【Todo】单例模式各种实现方式及并发安全
    【转载】Spark系列之运行原理和架构
    git本地文件回滚操作
    Java异常与运行时异常,以及与线程的关系
    Callable与Future、FutureTask的学习 & ExecutorServer 与 CompletionService 学习 & Java异常处理-重要
    Linux系统负载排查
  • 原文地址:https://www.cnblogs.com/dpwow/p/12736647.html
Copyright © 2020-2023  润新知