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

THREE.js循环内渲染Canvas无法实时更新问题求助

解决方案

核心问题分析

同步for循环会阻塞浏览器事件循环,导致UI渲染线程被挂起——哪怕循环内调用了render,所有渲染操作都会被排队,直到整个循环执行完毕才会一次性显示结果。另外renderScene里的无限递归requestAnimationFrame会和循环内的渲染请求冲突,进一步加剧了渲染延迟。

具体修复步骤

  1. 异步分帧处理:将同步循环改为基于requestAnimationFrame的异步递归处理,每帧处理一个扇区,给浏览器留出渲染时间。
  2. 优化资源创建:把重复创建的PointsMaterial、颜色比例尺移到循环外部,避免不必要的内存开销和性能损耗。
  3. 调整渲染逻辑:移除renderScene的无限递归,改为按需触发渲染,确保每次添加扇区后立即更新画布。

修改后的代码示例

// 把重复创建的资源移到外部,避免循环内重复实例化
const reflectivityColourScale = d3.scaleQuantize().domain([-32.0, 94.5]).range(reflectivityColours);
const pointsMaterial = new THREE.PointsMaterial({
    size: 2,
    vertexColors: true,
    sizeAttenuation: false
});

const drawReflectivityMap = (scans, reflectivityData, azimuthData, scene, renderer, cameraPosition, camera) => {
    let currentScanIndex = 0;
    const currentCamera = camera;
    const currentRenderer = renderer;

    // 异步处理单个扇区的函数
    const processScan = () => {
        if (currentScanIndex >= scans) return; // 终止条件

        console.log('Drawing Reflectivity ' + currentScanIndex);
        const reflectivity = reflectivityData[currentScanIndex];
        const azimuth = utils.radians(azimuthData[currentScanIndex]);
        const sinMultiplier = Math.sin(azimuth);
        const cosMultiplier = Math.cos(azimuth);

        const initialRange = mikeUtilities.addRange(
            mikeUtilities.multiplyRange(mikeUtilities.createRange(0, reflectivity.GateCount, 1), reflectivity.GateSize),
            reflectivity.FirstGate
        );
        const x = utils.multiplyRange(initialRange, sinMultiplier);
        const y = utils.multiplyRange(initialRange, cosMultiplier);

        const pointsGraph = [];
        const coloursGraph = [];

        x.forEach((_, i) => {
            if (reflectivity.MomentDataValues[i] > -33) {
                const dataPointColour = new THREE.Color(reflectivityColourScale(reflectivity.MomentDataValues[i]));
                pointsGraph.push(x[i], y[i], 0);
                coloursGraph.push(dataPointColour.r, dataPointColour.g, dataPointColour.b);
            }
        });

        const geometry = new THREE.BufferGeometry();
        geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(pointsGraph), 3));
        geometry.setAttribute('color', new THREE.BufferAttribute(new Float32Array(coloursGraph), 3));

        const pointsMap = new THREE.Points(geometry, pointsMaterial);
        scene.add(pointsMap);

        // 触发一次渲染
        currentCamera.position.z = cameraPosition;
        currentRenderer.render(scene, currentCamera);

        currentScanIndex++;
        // 调度下一帧处理下一个扇区
        requestAnimationFrame(processScan);
    };

    // 启动异步处理
    requestAnimationFrame(processScan);
};

额外优化建议

  • 如果2880个扇区逐个处理速度太慢,可以每次处理多个扇区(比如一次处理10个),平衡渲染流畅度和总耗时。
  • 可以添加进度提示,比如更新DOM显示当前渲染的扇区数量,提升用户体验。

内容的提问来源于stack exchange,提问作者Mike Upjohn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 06:55:13