threejs loading optimization with compass

Loading optimization with compass

Get into the habit of writing together! This is the 5th day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the details of the event .

This article mainly introduces the threejs optimization of loading efficiency and the implementation of the compass . The above picture is the integration diagram of the previous functional articles, and I specially edited it~

Why put optimization and compass in one article? Since both are relatively simple, consider combining them into one article~

I mention it here, if you are interested in particles , you can read my previous article! I wrote it in great detail, but! I am limited and not recommended to the homepage! Creation is not easy, pigs sigh~

compass

The effect is shown in the cover picture, mainly because the two pictures follow the scene to rotate and synchronize the angle, which is relatively simple

Code analysis: Through the superposition of a base map and a compass image, the angle of the camera is calculated through frame animation and synchronized to the compass for rotation

Viewer.prototype.initCompass = function () {
  const znzbg = document.createElement('img')
  znzbg.src = '/static/images/znzd.png'
  znzbg.style.position = 'absolute'
  znzbg.style.right = '500px'
  znzbg.style.top = '80px'
  znzbg.style.width = '80px'
  znzbg.style.height = '80px'
  const znz = document.createElement('img')
  znz.src = '/static/images/znz.png'
  znz.style.position = 'absolute'
  znz.style.right = '510px'
  znz.style.top = '90px'
  znz.style.width = '60px'
  znz.style.height = '60px'
  this.znz = znz
  this.el.appendChild(znzbg)
  this.el.appendChild(znz)
  this.renderFunction.push(() => {
    var dir = new THREE.Vector3(-this.camera.position.x, 0, -this.camera.position.z).normalize()
    var theta = Math.atan2(-dir.x, -dir.z)
    if (this.znz) this.znz.style.transform = `rotate(${THREE.Math.radToDeg(theta) + 45}deg)`
  })
}
复制代码

threejs loading optimization

Experienced students have a problem, that is, the scene is large, and it takes a lot of time to load each time. If multiple scenes are loaded into memory at the same time, there will be stuttering . How to solve this problem?

Model tile loading

When loading the scene for the first time, the model file needs to be parsed. The time for parsing the file cannot be optimized, but we can fragment the model file - tile loading . There must be some students here who will ask, loading in the form of tiles seems to be just split loading , it will not affect the time we load the scene~

Think about it, what if we load the fragmented model asynchronously through a configuration JSON ? Will this greatly speed up the loading rate? Ideally, the more fragmented the model, the faster the loading rate~

const configFile = 'data/parkBuildings/fbs/config.json' //配置JSON
return new Promise((resolve, reject) => {
  axios.get(configFile, {baseURL}).then(res => {
  //加载模型
  loadModel
}).catch(reason => {
  console.error(reason)
  reject(reason)
})
复制代码
//瓦片加载
Viewer.prototype.loadModel = (url, layeridx, callback) => {
  const that = gapp
  const loader = new GLTFExtensionLoader(gapp.manager)
  loader.workingPath = loader.workingPathForURL(url)
  loader.load(url)
    .then(gltf => {
      gltf.scene.traverse((e) => {
        e.layers.set(layeridx)
        e.userData.orglayers = layeridx //原始层级
      })
      const clips = gltf.animations || []//如果存在动画片段。提取所有动画片段
      gapp.addclips(clips, layeridx)
      gapp.glayers[layeridx].add(gltf.scene)
      callback ? callback(gltf.scene) : ''
    })
}
复制代码

Problems with tile loading

通过上面的优化,是不是觉得还有缺陷~大家通常实现多场景的方案是一次性加载通过相机层级切换呢?还是切换完加载模型呢?

其实问题其中就显现出上面优化还存在的问题!我们在需要切换多场景的需求时,如果通过一次性加载完,将其存储于内存中,虽然通过相机调整层级无需多次加载,但是存在内存占用过大卡顿问题。所以通过第一个方案我们还是无法最大限度解决加载快并不卡顿的问题。当然我们如果切换场景才去做加载的话未免用户体验也太差了,这个方案当然是被pass。那我们应该怎么做才能鱼和熊掌兼得呢!

加载优化

不知道大家对indexDb是否熟悉,indexDb作为浏览器一个非关系型数据库。相比平时大家也都不会涉及到,这里介绍一个indexDb对于场景这一块如何起到优化的作用!

indexDb

  1. 模型文件解析后的JSON通过有几十兆到几百兆不等,回关浏览器所常用的存储是无法满足这么大的容量
  2. indexDb恰巧可以满足,并是类似mongodb的数据库。我们大可将文件名及解析后的对象以一一对应的形式存储到indexDb中
  3. 这样我们即可在第一次加载完所有场景模型后,将所有的瓦片解析对象通过threejs的toJSON转为特定的json格式以键值对的形式存储于indexDb中。
  4. Secondary loading and switching only need to take out the corresponding tile object in indexDb according to the configuration object , parse the json into object format and add it to the scene through the fromJSON method of threejs
//转化为threejs特有的json格式
 scene.toJSON() 
 (了解过json的同学可以发现,threejs为了缩小大小,将瓦片对象最大限度的拆分材质等,通过id关联并保存为json)
//解析json转为对象
Viewer.prototype.fromJSON = function (json, layeridx, isRayobj) {
  return new Promise((resolve, reject) => {
    // 解析 json 对象
    let loader = new THREE.ObjectLoader();
    let loadedMesh = loader.parse(json);
    let scene = this.mergeToMaterialsMap(loadedMesh, true)
    resolve(scene)
  })
}
复制代码

Scenario Optimization Solution Summary

<Asynchronous loading of tiles> <Storing and converting tile objects> <Parsing tile objects to avoid repetitive parsing work> <Multi-scene switching without re-parsing the model> <Loading one scene at a time to reduce memory usage>

Summarize

Creation is not easy, pigs sigh! Students who are interested in threejs can follow my column and update threejs related cases and solutions from time to time~ threejs column

Guess you like

Origin juejin.im/post/7085167057792155662