vue项目中使用 threeJS threeJS globe 实现github globe

543 阅读2分钟

由于参与的内部系统项目系统登陆页面过于简陋不忍直视,在开发的空余喜欢篮球唱跳Rap 干脆实现个地球实现了github首页的地球 主要使用了 threejs three-globe

  1. 首先新建vue 项目 引入 threeGlobe 以及threeJS
  2. npm i three-globe npm i three

包安装完成之后引入必要的组件以及生命所需要的组件 下面是生成画布以及地球的核心js代码

import { WebGLRenderer, Scene } from 'three'
import {
  PerspectiveCamera,
  AmbientLight,
  DirectionalLight,
  Color,
  Fog,
  // AxesHelper,
  // DirectionalLightHelper,
  // CameraHelper,
  PointLight
} from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import countries from './files/globe-data-min.json'
var renderer, camera, scene, controls
var Globe

// 初始化声明核心的threeJs 控件
function init() {
  // 初始化渲染器
  renderer = new WebGLRenderer({ antialias: true })
  // 设置像素比
  renderer.setPixelRatio(window.devicePixelRatio)
  // 设置渲染画布大小
  renderer.setSize(window.innerWidth, window.innerHeight)
  // renderer.outputEncoding = THREE.sRGBEncoding;
  // 将当前画布挂载到body子对象上
  document.body.appendChild(renderer.domElement)

  // 初始化场景以及光线
  scene = new Scene()
  scene.add(new AmbientLight(0xbbbbbb, 0.3))
  // 设置画布背景颜色
  scene.background = new Color(0x040d21)

  // 初始化相机 以及光线
  camera = new PerspectiveCamera()
  camera.aspect = 800 / 600
  camera.updateProjectionMatrix()

  var dLight = new DirectionalLight(0xffffff, 0.8)
  dLight.position.set(-800, 2000, 400)
  camera.add(dLight)

  var dLight1 = new DirectionalLight(0x7982f6, 1)
  dLight1.position.set(-200, 500, 200)
  camera.add(dLight1)

  var dLight2 = new PointLight(0x8566cc, 0.5)
  dLight2.position.set(-200, 500, 200)
  camera.add(dLight2)

  camera.position.z = 400
  camera.position.x = 0
  camera.position.y = 0

  scene.add(camera)
  // Additional effects
  scene.fog = new Fog(0x535ef3, 400, 2000)

  // Helpers
  // const axesHelper = new AxesHelper(800);
  // scene.add(axesHelper);
  // var helper = new DirectionalLightHelper(dLight);
  // scene.add(helper);
  // var helperCamera = new CameraHelper(dLight.shadow.camera);
  // scene.add(helperCamera);

  // 初始化控制器  轨道控制
  controls = new OrbitControls(camera, renderer.domElement)
  controls.enableDamping = true
  controls.dynamicDampingFactor = 0.01
  controls.enablePan = true
  controls.minDistance = 200
  controls.maxDistance = 300
  controls.rotateSpeed = 0.8
  controls.zoomSpeed = 1
  controls.autoRotate = true
  controls.minPolarAngle = Math.PI / 3.5
  controls.maxPolarAngle = Math.PI - Math.PI / 3
}
// 地球初始化
function initGlobe() {
  // 初始化地球
  Globe = new ThreeGlobe({
    waitForGlobeReady: true,
    animateIn: true
  })
    .hexPolygonsData(countries.features)
    .hexPolygonResolution(3)
    .hexPolygonMargin(0.7)
    .showAtmosphere(true)
    .atmosphereColor('#3a228a')
    .atmosphereAltitude(0.25)
    .hexPolygonColor((e) => {
      if (
        ['KGZ', 'KOR', 'THA', 'RUS', 'UZB', 'IDN', 'KAZ', 'MYS'].includes(
          e.properties.ISO_A3
        )
      ) {
        return 'rgba(255,255,255, 1)'
      } else return 'rgba(255,255,255, 0.7)'
    })
  Globe.rotateY(-Math.PI * (5 / 9))
  Globe.rotateZ(-Math.PI / 6)
  const globeMaterial = Globe.globeMaterial()
  globeMaterial.color = new Color(0x3a228a)
  globeMaterial.emissive = new Color(0x220038)
  globeMaterial.emissiveIntensity = 0.1
  globeMaterial.shininess = 0.7

  globeMaterial.wireframe = true
  // 场景添加地球
  scene.add(Globe)
}
// 窗口重置大小的时候
function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()
  renderer.setSize(window.innerWidth, window.innerHeight)
}
// 动画效果
function animate() {
  if (!camera) return
  camera.position.x += 5
  camera.position.y += 5
  camera.lookAt(scene.position)
  controls.update()
  renderer.render(scene, camera)
  requestAnimationFrame(animate)
}
// 初始化渲染 先初始化画布场景 再初始化地球 再添加当window resize 控制渲染 最后添加动画
export function initRender() {
  init()
  initGlobe()
  onWindowResize()
  animate()
}
// 销毁地球以及画布释放内存 ,canvas 创建后不主动清空会一直存在
export function destroyCanvas() {
  cancelAnimationFrame(animate)
  scene.traverse((child) => {
    if (child.material) {
      child.material.dispose()
    }
    if (child.geometry) {
      child.geometry.dispose()
    }
    child = null
  })
  // 场景中的参数释放清理或者置空等
  scene.clear()
  scene = null
  camera = null
  controls = null
  renderer.forceContextLoss()
  renderer.dispose()
  renderer = null
  document.body.removeChild(document.getElementsByTagName('canvas')[0])
  // renderer.domElement = null
}

生成后需要挂载在dom上才能看到效果 需要在mounted 时引入 引文canvas创建后会一直存在 需要在离开时销毁 所以提供了 两个方法一个是初始化一个是封装的销毁方法 import { initRender, destroyCanvas } from './githubGlobal'

 mounted() {
    initRender()
  },
  //在离开页面时进行销毁
   beforeDestroy() {
   destroyCanvas()
 },

旧页面 微信截图_20221026134813.png 最终效果展示 微信截图_20221026110822.png 最后附上连接 需要的小伙伴直接冲!!! github herobrinePerssion