【3D】three.js在同一个div下切换不同模型挂载的问题

·  阅读 1115

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

需求

同一个div下,通过查询不同的设备展示不同的模型。

在这里插入图片描述

1、实现新202011

实现形式:不清除场景,只清除场景中的模型,加载新的模型到场景中。

关键代码:

this.paramsThree = {
    modelName: '', // .glb模型的文件名字
    name: 'devGlb', // 模型加入场景的名字,此处统一是devGlb
    offsetY: 0 // 模型加入场景的y轴偏移量
}
if (`当前设备模型不为空`) {
    clearModel() // 清除模型
    this.paramsThree.modelName = `从接口中获取模型文件名字`
    initModel(this.paramsThree) // 加载新模型
} else {
    clearModel() // 清除模型
    this.paramsThree.modelName = ''
}
复制代码
// 主要变量
let LOAD_PARAMS = null
// 模型清除
export function clearModel () {
    if (scene) {
        let objM = scene.getObjectByName(LOAD_PARAMS.name)
        if (objM) scene.remove(objM)
    }
}
// 模型加载
export function initModel (paramsThree) {
    LOAD_PARAMS = paramsThree
    let glbname = paramsThree.modelName
    // 实例化加载器
    let loader = new GLTFLoader()
    loader.load('/static/3d/subway/dev/' + glbname + '.glb', function (obj) {
        obj.scene.position.y = LOAD_PARAMS.offsetY
        obj.scene.name = LOAD_PARAMS.name
        if (scene !== null && glbname === LOAD_PARAMS.modelName) { // 当前对应的模型和加载完成的模型一致时才放到场景中
        scene.add(obj.scene)
        }
    }, function (xhr) {
        console.log((xhr.loaded / xhr.total * 100) + '% loaded')
    }, function (error) {
        console.error(error, 'load error!')
    })
}
复制代码

后面是以前旧代码的实现遇到的问题,做个记录。

======================

2、实现旧

关键代码如下:

<div id="equip-model"></div>
// 加载three.js
needReloadThreeJs (devtype) {
  div3D = document.getElementById('equip-model')
  this.initScene() // 场景
  this.initCamera() // 相机
  this.initRender() // 渲染器
  this.initLight() // 灯光
  this.initControls() // 模型控制
  this.initModel(devtype) // 模型加载
  this.animate() // 场景动画 动起来
},
// 清除模型
clearModel () {
  // 清除局部的模型
  if (scene !== null) {
	// 确保3D相关对象已销毁
	window.cancelAnimationFrame(stop) // 可以取消动画
	scene = null
	camera = null
	renderer = null
	controls = null
	div3D = null
  }
}
复制代码

问题

明明每次调用needReloadThreeJs之前先调用clearModel清除上一次的模型包括场景全部置为空,但是仍然达不到效果。

  • 1、原来的模型存在,停止转动(initControls中设置了autoRotate=true)
  • 2、新的模型追加上去,在浏览器端查看,有多个canvas叠加显示。

思考

尝试了各种清除模型的方法,最后发现只有清除scene的children中对应的模型对象。

因为当前只添加了三个环境光和一个模型,所以用scene.children.pop()去掉最后一个对象(模型对象)即可。

但是!!canvas始终存在,模型是清空了但是canvas占位在那里导致界面乱了。

于是想移除子节点不就可以了

let domDiv = document.getElementById('equip-model')
domDiv.removeChild(domDiv.firstChild)
复制代码

最终代码

// 清除模型
clearModel () {
  // 清除局部的模型
  if (scene !== null && scene.children.length > 3) {
	scene.children.pop()
	// 必须要清空当前div下的canvas不然canvas会继续叠加为什么呢?明明场景和相机等等都清空了
	let domDiv = document.getElementById('equip-model')
	if (domDiv !== null) {
	  domDiv.removeChild(domDiv.firstChild)
	}
	// 确保3D相关对象已销毁
	window.cancelAnimationFrame(stop) // 可以取消动画
	scene = null
	camera = null
	renderer = null
	controls = null
	div3D = null
  }
}
复制代码

延伸

删除dom子节点时,最开始使用的是全部子节点删除

let domDiv = document.getElementById('equip-model')
for(let i = 0; i < domDiv.length; i++) {
    domDiv.removeChild(domDiv[i])
}
复制代码

明显是有问题的,因为domDiv子节点在删除,其长度在变化,如果要删除所有子节点可以用

while(domDiv.hasChildNodes()) {
    domDiv.removeChild(domDiv.firstChild)
}
复制代码

于是乎,canvas没有被删掉是不是也是因为用错了方法呢,应该不是,因为canvas不是留下一个未删除,是一直没有被删除,一直在叠加,为什么呢???

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改