Three.js代码在macOS无法执行:Vertex buffer不足错误排查求助
Three.js线条动画macOS浏览器报错修复
问题概况
- 预期功能:实现从屏幕中心到当前鼠标位置的线条动画效果
- 异常表现:代码在Windows系统正常运行,但在macOS的Safari/Chrome浏览器中无法执行,控制台抛出错误:
GL_INVALID_OPERATION: Vertex buffer is not big enough for the draw call.
问题根源
使用THREE.LineDashedMaterial时,必须为每个顶点提供lineDistance属性数据。你的线条包含2个顶点(起点+终点),但代码中仅初始化了长度为1的Float32Array作为lineDistance,导致WebGL缓冲区大小不匹配。Windows浏览器可能存在容错机制,而macOS的WebGL实现更严格,直接抛出错误。
另外,代码中this.lineLength指向了lineDistance数组而非实际数值,会导致动画计算异常。
修复步骤
1. 修正构造函数中的lineDistance初始化
将构造函数中lineDistance的创建和赋值改为:
this.lineDistance = new Float32Array(2); // 2个顶点对应2个距离值 this.lineDistance[0] = 0; // 第一个顶点(起点)距离自身为0 this.lineDistance[1] = this.start.distanceTo(this.end); // 第二个顶点距离起点的长度 this.lineLength = this.lineDistance[1]; // 存储线条长度数值,而非数组
2. 更新update方法,动态刷新lineDistance
在update方法末尾添加代码,每次更新线条位置后重新计算长度并更新缓冲区:
// 更新lineDistance和线条长度 const lineLength = start.distanceTo(end); const lineDistanceAttr = this.line.geometry.getAttribute('lineDistance'); lineDistanceAttr.array[0] = 0; lineDistanceAttr.array[1] = lineLength; lineDistanceAttr.needsUpdate = true; this.lineLength = lineLength;
3. 确保动画计算正确
animate方法中的dashSize计算已自动修正,因为this.lineLength现在是数值而非数组:
this.line.material.dashSize = this.fraction * this.lineLength;
修复后完整Line类代码
class Line { constructor(_start, _end) { this.geometry = new THREE.BufferGeometry(); this.material = new THREE.LineDashedMaterial( { color: 0xffffff, linewidth: 1, scale: 1, dashSize: 1, // to be updated in the render loop gapSize: 1e10 // a big number, so only one dash is rendered } ); this.positions = new Float32Array(6); // 2个顶点,每个顶点3个坐标值 this.start = new THREE.Vector3(_start.x, _start.y, 0); this.end = new THREE.Vector3(_end.x, _end.y, 0); // 修正lineDistance数组长度为2 this.lineDistance = new Float32Array(2); this.lineDistance[0] = 0; this.lineDistance[1] = this.start.distanceTo(this.end); this.positions[0] = this.start.x; this.positions[1] = this.start.y; this.positions[2] = this.start.z; this.positions[3] = this.end.x; this.positions[4] = this.end.y; this.positions[5] = this.end.z; this.fraction = 0; this.isFinished = false; this.lineLength = this.lineDistance[1]; // 存储线条长度数值 this.growRate = 0.01; this.growMax = 1; this.threeBufferPosition = new THREE.BufferAttribute(this.positions, 3); this.geometry.setAttribute('position', this.threeBufferPosition); this.geometry.setAttribute('lineDistance', new THREE.BufferAttribute(this.lineDistance, 1)); this.line = new THREE.Line(this.geometry, this.material); scene.add(this.line); this.startcaster = new THREE.Raycaster(); this.endcaster = new THREE.Raycaster(); } update(_start,_end) { const positions = this.line.geometry.attributes.position.array; this.startcaster.setFromCamera(_start, camera); this.endcaster.setFromCamera(_end, camera); let start = new THREE.Vector3(_start.x, _start.y, 0); let end = new THREE.Vector3(_end.x, _end.y, 0); this.startcaster.ray.at(1, start); this.endcaster.ray.at(1, end); positions[0] = start.x; positions[1] = start.y; positions[2] = start.z; positions[3] = end.x; positions[4] = end.y; positions[5] = end.z; this.line.geometry.getAttribute('position').needsUpdate = true; // 更新lineDistance和线条长度 const lineLength = start.distanceTo(end); const lineDistanceAttr = this.line.geometry.getAttribute('lineDistance'); lineDistanceAttr.array[0] = 0; lineDistanceAttr.array[1] = lineLength; lineDistanceAttr.needsUpdate = true; this.lineLength = lineLength; } animate() { if(this.fraction < this.growMax) { this.fraction += this.growRate; this.line.material.dashSize = this.fraction * this.lineLength; } } }
内容的提问来源于stack exchange,提问作者goleon
相关产品推荐
相关产品推荐

