Three.js开发中遇到的常见问题总结和性能优化

关于Three.js开发中遇到的一些问题总结

1.加载外部模型文件无法在场景中显示:

(1) 确保当前文件内容是否能被读取,在Javascript的console中查找错误,并确定当你调用.load()的时候,使用了onError回调函数来输出结果, 如果err 输出则表示当前glb 文件内容无法被读取从新换一个glb文件尝试

	const loader = new GLTFLoader()
	loader.load('/three/1.glb', (result) => {
			 console.log(result)
			}, () => {
			}, (err) => {
				console.log(err)
		})

(2) 尝试将模型放大缩小到原来的1000倍。许多模型的缩放比例各不相同,如果摄像机位于模型内,则大型模型将可能不会显示。或者可以在模型加载完成之后根据模型比例大小设置合适的缩放值

		//设置模型位置
		this.model.updateMatrixWorld()
		const box = new THREE.Box3().setFromObject(this.model);
		const size = box.getSize(new THREE.Vector3());
		const center = box.getCenter(new THREE.Vector3());
		// 计算缩放比例
		const maxSize = Math.max(size.x, size.y, size.z);
		const targetSize = 2.5; // 目标大小
		const scale = targetSize / (maxSize > 1 ? maxSize : .5);
		this.model.scale.set(scale, scale, scale)
	     // 设置控制器最小缩放值
		this.controls.maxDistance = size.length() * 10
		// 设置相机位置
		this.camera.position.set(0, 2, 6)
		// 设置相机坐标系
		this.camera.lookAt(center)
		this.camera.updateProjectionMatrix();

(3)增加相机远端面的值 far,如果在创建相机时摄像机视锥体远端面的值设置过小也无法蒋模型正确的显示出来

this.camera = new THREE.PerspectiveCamera(45, clientWidth / clientHeight, 0.25, 100)
this.camera.far = 2000
this.camera.updateProjectionMatrix()

(4) 尝试添加一个光源并改变其位置。模型或许被隐藏在黑暗中。

       // 创建一个平行光
		this.directionalLight = new THREE.DirectionalLight('#1E90FF', 1)
		this.directionalLight.position.set(-1.44, 2.2, 1)
		this.directionalLight.castShadow = true
		this.scene.add(this.directionalLight)

2.模型材质辉光效果影响背景图的正常显示

(1)在场景动画帧渲染中对背景图进行单独处理

	sceneAnimation() {
		this.renderAnimation = requestAnimationFrame(() => this.sceneAnimation())
		// 将不需要处理辉光的材质进行存储备份
		this.scene.traverse((v) => {
			if (v instanceof THREE.Scene) {
				this.materials.scene = v.background
				v.background = null
			}
			if (!this.glowMaterialList.includes(v.name) && v.isMesh) {
				this.materials[v.uuid] = v.material
				v.material = new THREE.MeshBasicMaterial({ color: 'black' })
			}
		})
		this.glowComposer.render()
		// 在辉光渲染器执行完之后在恢复材质原效果
		this.scene.traverse((v) => {
			if (this.materials[v.uuid]) {
				v.material = this.materials[v.uuid]
				delete this.materials[v.uuid]
			}
			if (v instanceof THREE.Scene) {
				v.background = this.materials.scene
				delete this.materials.scene
			}
		})

		this.effectComposer.render()
	}

3.窗口大小改变场景画面像素变得模糊

在窗口监听方法中更新相机,渲染器等相关信息

	window.addEventListener("resize", this.onWindowResize.bind(this))
				// 监听窗口变化
	onWindowResize() {
		const { clientHeight, clientWidth } = this.container
		//调整屏幕大小
		this.camera.aspect = clientWidth / clientHeight //摄像机宽高比例
		this.camera.updateProjectionMatrix() //相机更新矩阵,将3d内容投射到2d面上转换
		this.renderer.setSize(clientWidth, clientHeight)
		this.effectComposer.setSize(clientWidth, clientHeight)
		this.glowComposer.setSize(clientWidth, clientHeight)
	}
			

4.修改材质的position(x,y,z)没有实际的效果

模型材质类型为 Mesh 的材质支持修改 position

	const mesh = this.model.getObjectByName(name)
	if(mesh.type == 'Mesh){
        mesh.position.set(1,10,1)
   }

5.材质设置网格,透明度和颜色没有实际效果或者造成材质显示不正确?

three.js支持 修改网格,透明渡和颜色的材质有:
MeshBasicMaterial,MeshLambertMaterial,MeshPhongMaterial,MeshStandardMaterial,MeshPhysicalMaterial,MeshToonMaterial 这六种

6.鼠标(点击,拖拽,缩放,移动)等操作不影响场景内容

// 启用或禁用摄像机平移,默认为true。
this.controls.enablePan = false
// 当设置为false时,控制器将不会响应用户的操作。默认值为true。
thsi.controls.enabled =false
// 启用或禁用摄像机水平或垂直旋转。默认值为true。
thsi.controls.enableRotate  =false
// 启用或禁用摄像机的缩放。
thsi.controls.enableZoom =false

7.将three.js color 值转化为普通 css 值

const colot = new THREE.Color(colorRGB).getStyle()

8.调整相机角度,模型的部分材质内容显示不完整或者不显示

将 frustumCulled值设置为false不管是否在相机视椎体都会渲染

   this.model.traverse(item => {
        if (item.isMesh && item.material) {
            item.frustumCulled = false  
        }
    })

9.模型文件加载进度条 total 为0 lengthComputable为false?

可能原因有以下几种:
1.文件资源在项目本地文件夹public(vue项目)
2.服务器未提供 Content-Length: 服务器在响应头中未提供正确的 Content-Length 字段,或者提供的值无效。在这种情况下,浏览器无法确定要加载的总字节数,因此 lengthComputable 被设置为 false
3.流式传输: 一些加载场景中,数据是通过流式传输的方式加载的,因此无法预先知道要加载的总字节数。例如,通过 WebSocket 或 SSE (Server-Sent Events) 加载数据时,通常无法确定总字节数。
lengthComputable 为false 情况单独处理 :

  onModelProgress(progressEvent ){
      const { loaded ,total ,lengthComputable } = progressEvent 
        //lengthComputable  true 可以获取到当前文件的总字节大小
       if(lengthComputable ){
        const progress = loaded / total * 100
        console.log( progress + '% loaded' )
        }else{
          console.log('已加载'+loaded+'字节' )
      }
   }

10.使用 GLTFExporter 导出模型文件(.glb, .gltf) 动画丢失?

在需要把当前场景的内容导出为一个glb或者gltf文件时,使用 GLTFExporter方法对场景进行导出,在导出来新的glb文件时发现原来的模型文件的动画丢失了
解决方法: three.js GLTFExporter 方法的第三个参数提供 导出相关配置的传入 options , 获取到当前场景需要的导出的剪辑动画 animations 在调用导出方法时传入即可。
代码如下示例: 注意是GLTFExporter第三个参数第二个参数为 导出错误的回调函数

    const type = 'glb'
  	const exporter = new GLTFExporter();
		const options = {
			trs: true,      // 是否保留位置、旋转、缩放信息
			animations: this.modelAnimation, // 导出的动画
			binary: type == 'glb' ? true : false,  // 是否以二进制格式输出
			embedImages: true,//是否嵌入贴图
			onlyVisible: true, //是否只导出可见物体展
		}
		exporter.parse(this.scene, function (result) {
			if (result instanceof ArrayBuffer) {
				// 将结果保存为GLB二进制文件
				saveArrayBuffer(result, `${new Date().toLocaleString()}.glb`);
			} else {
				// 将结果保存为GLTF JSON文件
				saveString(JSON.stringify(result), `${new Date().toLocaleString()}.gltf`);
			}
			function saveArrayBuffer(buffer, filename) {
				// 将二进制数据保存为文件
				const blob = new Blob([buffer], { type: 'application/octet-stream' });
				const url = URL.createObjectURL(blob);
				const link = document.createElement('a');
				link.href = url;
				link.download = filename;
				link.click();
				URL.revokeObjectURL(url);
				console.log('导出成功')
			}
			function saveString(text, filename) {
				// 将字符串数据保存为文件
				const blob = new Blob([text], { type: 'application/json' });
				const url = URL.createObjectURL(blob);
				const link = document.createElement('a');
				link.href = url;
				link.download = filename;
				link.click();
				URL.revokeObjectURL(url);
				console.log('导出成功')
			}
		}, (err) => {
			console.log('导出错误',err)
		}, options);

关于Three.js开发中性能优化

在页面关闭销毁跳转离开时清除代码中 定时器事件监听动画帧等相关方法。释放场景中的材质内存,清除场景和模型相关信息

   // 清除模型数据
	onClearModelData(){
		cancelAnimationFrame(this.rotationAnimationFrame)
		cancelAnimationFrame(this.renderAnimation)
		cancelAnimationFrame(this.animationFrame)
		this.container.removeEventListener('click', this.onMouseClickModel)
		this.container.removeEventListener('mousedown', this.onMouseDownModel)
		this.container.removeEventListener('mousemove', this.onMouseMoveModel)
		window.removeEventListener("resize", this.onWindowResize)
		// 材质释放内存
	 	this.scene.traverse((v) => {
			  if (v.type === 'Mesh') {
						v.geometry.dispose();
						v.material.dispose();
		    	}
		  })
		  // 清除场景和模型相关信息
	    this.model.clear()
        this.scene.clear()
	}

完整的代码可参考:

https://gitee.com/ZHANG_6666/Three.js3D
https://github.com/zhangbo126/Three3d-view
基于three.js开发3d模型可视化编辑器
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值