关于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
}
})
关于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()
}