You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 14:26:02