three.js报错集锦

这篇博客总结了在使用three.js时遇到的一些常见错误,包括KeyframeTrack帧动画的矩阵错误、EffectComposer非构造函数问题、EffectComposer对透明背景的影响、CSS2DRenderer导致的鼠标控制失效、TextureLoader贴图不透明问题、BufferGeometry警告以及boundingBox计算错误。针对每个问题,博主提供了详细的错误描述、问题原因和解决方法。

1、KeyframeTrack 帧动画

报错:
THREE.Matrix3: .getInverse() can’t invert matrix, determinant is 0
代码:

// 此处是一个缩放动画
let times = [0, 1]
let scales = [0, 0, 0, 1, 1, 1]
let scaleKeyframeTrack = new THREE.KeyframeTrack('circle.scale', times, scales)

由上可知,缩放从x,y,z坐标的0倍到1倍变化,导致0倍时报错,没有逆矩阵。
改为如下即可:

let times = [0, 1]
let scales = [1, 1, 1, 2, 2, 2]
let scaleKeyframeTrack = new THREE.KeyframeTrack('circle.scale', times, scales)

将缩放变化改为,从x,y,z坐标的1倍到2倍变化即可。

2、EffectComposer 效果组合器

报错:
THREE.EffectComposer is not a constructor
‘THREE.EffectComposer不是构造函数’
因为:EffectComposer不包含在three.js的包中,需要单独导入,并且配置webpack导入导出变量。
和其他非官方的three.js模块,如OrbitControls引入的方法一致。
正确配置引用代码如下:

// webpack.base.conf.js中配置
module.exports = {
	……
	module: {
		rules: [
			……
			{
				test: require.resolve("three/examples/js/postprocessing/EffectComposer"),
				use: "imports-loader?THREE=three"
			},
			{
				test: require.resolve("three/examples/js/postprocessing/EffectComposer"),
				use: "exports-loader?THREE.EffectComposer"
			}
		]
	}
}
// 引入和使用
import EffectComposer from 'three/examples/js/postprocessing/EffectComposer'
composer = new EffectComposer(renderer)

3、EffectComposer 毁坏原始透明背景

代码:

// 原始WebGLRenderer渲染器
renderer = new THREE.WebGLRenderer({alpha: true, antialias: true})
// 设置宽和高
renderer.setSize(div3D.clientWidth, div3D.clientHeight)
// 设置背景 0x0E3866表示16进制 若不设置则背景透明 特效渲染时产生的背景会显示出来
// renderer.setClearColor(0x102440)

// 效果组合器包裹原始渲染器
composer = new EffectComposer(renderer)
// 添加特效渲染通道
let renderPass = new RenderPass(scene, camera)
composer.addPass(renderPass)
outlinePass = new OutlinePass(new THREE.Vector2(div3D.clientWidth, div3D.clientHeight), scene, camera)
composer.addPass(outlinePass)
// 将结果输出到屏幕上的通道
let effectFXAA = new ShaderPass(THREE.FXAAShader)
effectFXAA.renderToScreen = true
effectFXAA.clear = true
composer.addPass(effectFXAA)

问题:
加上特效之后,因为原始背景设置为透明,而OutlinePass里面强制设置了背景颜色,此时强制设置的黑色背景被显示了出来。
在这里插入图片描述
结果:
不使用透明背景,放开注释,设置renderer.setClearColor(0x102440)。
其实问题并没有解决,求解!!!
最新说明:
更新three.js版本,从jsm下引入相关包即可。貌似新版本修复了这个bug?

import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass'
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'
import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass'

4、CSS2DRenderer 渲染DIV后鼠标移动场景失效

代码:

// 获取详情模板DIV 设置为显示
let detailDiv = document.getElementById('detailInfo')
detailDiv.style.display = 'block'
// 使用CSS2DObject创建DIV对象 并设置位置 加入场景
let detailCSS2D = new THREE.CSS2DObject(detailDiv)
detailCSS2D.position.set(buildLoc.x, 6, buildLoc.z)
scene.add(detailCSS2D)
// 使用CSS2DRenderer 渲染DIV对象 并挂到页面中去
labelRenderer = new THREE.CSS2DRenderer()
labelRenderer.setSize(div3D.clientWidth, div3D.clientHeight)
labelRenderer.domElement.style.position = 'absolute'
labelRenderer.domElement.style.top = 0
labelRenderer.domElement.id = 'renderFrame'
div3D.appendChild(labelRenderer.domElement)
// 控制屏幕缩放、旋转 但是无法整体拖动
/* eslint-disable */
let labelControls = new OrbitControls(camera, labelRenderer.domElement)
/* eslint-enable */

问题:
1、若注释 // let labelControls = new OrbitControls(camera, labelRenderer.domElement)
整个鼠标控制失效。
2、即便使用 let labelControls = new OrbitControls(camera, labelRenderer.domElement)
也会导致在div渲染后,shift+鼠标移动就失效了。
所以:
适时展示完详情DIV后,将其清除还原或者隐藏。
比如:

// 获取原来的详情renderFrame 删除或者隐藏 看具体业务场景决定
let renderFrame = document.getElementById('renderFrame')
if (renderFrame !== null) {
	// 直接移除
	div3D.removeChild(renderFrame)
	// 或者隐藏
	// renderFrame.style.display = 'none'
}

5、TextureLoader 贴图加载PNG背景不透明 充填了白色

代码:

// 管道路径
let pipeline = new THREE.CatmullRomCurve3([
	new THREE.Vector3(36, -6, -13),
	new THREE.Vector3(-30, 16, -13)
], false)
// 创建管道,沿路径方向分段数默认64越长越大,管道半径默认1,圆周方向的分段数默认8,首尾是否连接默认否
let tubeGeometry = new THREE.TubeGeometry(pipeline, 100, 0.3, 2, false)
// 纹理加载器
let textureLoader = new THREE.TextureLoader()
texture = textureLoader.load('/static/3d/textures/test.png')
// 设置阵列模式为 RepeatWrapping
texture.wrapS = THREE.RepeatWrapping
texture.wrapT = THREE.RepeatWrapping
// 设置x方向的偏移(沿着管道路径方向),y方向默认1
texture.repeat.x = 5
texture.repeat.y = 2
// texture.premultiplyAlpha = true // 不设置的话背景透明会变白
let tubeMaterial = new THREE.MeshPhongMaterial({
	map: texture,
	side: THREE.FrontSide
})
let tube = new THREE.Mesh(tubeGeometry, tubeMaterial)
scene.add(tube)

有代码如上,创建管道贴上纹理图。
问题:
若图片大小为4040,和任意边长非2的次方数的正方形,会有如下警告,但是纹理贴图正常,是png图形背景透明。
THREE.WebGLRenderer: image is not power of two (40x40). Resized to 32x32
若图片大小裁剪为32
32,再使用上述代码贴上纹理图,png图片的背景明显被充填了白色,不再透明。
最后发现Texture里有个属性premultiplyAlpha,默认为false,不设置为true的话透明背景会变白。
即放开注释 // texture.premultiplyAlpha = true 即可。
官方文档说明:
https://www.techbrood.com/threejs/docs/#%E5%8F%82%E8%80%83%E6%89%8B%E5%86%8C/%E7%BA%B9%E7%90%86(Textures)/%E7%BA%B9%E7%90%86(Texture)

6、THREE.BufferGeometry警告

警告:

THREE.BufferGeometry: .addAttribute() has been renamed to .setAttribute().

警告解释:
BufferGeometry的.addAttribute()方法已经更名为.setAttribute()
查看源码:
MeshLine.process @ THREE.MeshLine.js?547e:341 对应文件中果然用的是addAttribute

this.geometry.addAttribute( 'position', this.attributes.position );

解决办法:
1、修改源码中addAttribute为setAttribute,不提倡。
2、更新版本找替代版本,行不通。
npm上看到有两个meshline:three.meshline和threejs-meshline
都下载最新版本使用,都存在同样的问题。
3、关了浏览器的警告显示,暂时也只能这样了。
F12-Console-Default levels去掉Warnings,好了没有了,眼不见心不烦。

7、获取boundingBox有误

代码

selectedObjects[0].geometry.computeBoundingBox()

问题

直接对对象使用computeBoundingBox()得到的boundingBox容易出错

办法

对象先BoxHelper获取盒子辅助线,再调用盒子辅助线的computeBoundingBox()得到的boundingBox就对了

let labelObj = selectedObjects[0]
let box = new THREE.BoxHelper(labelObj, 0xff0000)
box.geometry.computeBoundingBox()
console.log(selectedObjects[0].geometry.computeBoundingBox())
console.log(box.geometry.boundingBox.max.y)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值