Search code examples
javascriptreactjsd3.jscanvasthree.js

THREE JS - Rendering on canvas inside of loop not updating canvas


I've got the below code, which takes in a number of scans. I know this to always be 2880. The canvas should split an entire 360° into 2880 sectors. The loop in the code below will always run from 0 to 2880, and in each loop, a bunch of (maybe several hundred) 2px coloured points are rendered in that sector, emanating from the centre of the canvas outward. The loop moves fast, before I upgraded the THREE package, this loop could render in c. 15 seconds.

The picture draws correctly, but what confuses me is the fact that the call to THREE's render message happens inside of the loop, yet the picture draws nothing until the last iteration of the loop is complete and then all 2880 sectors appear at once, which isn't the effect I'm going for.

Can anyone advise what I might be missing? It's a 2-D non-interactable image.

Stuff I've tried:-

  • setTimeout(null, 1000) after the .render() method to make it wait before executing the next iteration of the loop
  • Considered making it a recursive function with the next iteration of the loop inside of the above setTimeout
  • Reversing the THREE upgrade as an absolute last resort.

Stuff I've considered:-

  • Is the loop running two fast for the frame rate or not giving the screen enough time to update?
  • Limitation of THREEJs?
const drawReflectivityMap = (scans, reflectivityData, azimuthData, scene, renderer, totalScans, currentScan, cameraPosition, camera, reflectivityColours) => {
    currentCamera = camera;
    currentRenderer = renderer;

    for (let i = 0; i < scans; i++) {
        console.log('Drawing Reflectivity ' + i);
        var reflectivity = reflectivityData[i];
        var azimuth = utils.radians(azimuthData[i]);
        var sinMultiplier = Math.sin(azimuth);
        var cosMultiplier = Math.cos(azimuth);

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

        var dataSet = {
            x: x,
            y: y,
            reflectivity: reflectivity
        };

        var reflectivityColourScale = d3.scaleQuantize().domain([-32.0, 94.5]).range(reflectivityColours);
        var pointsMaterial = new THREE.PointsMaterial({
            size: 2,
            vertexColors: true,
            sizeAttenuation: false
        });

        // x co-ordinate points for each point in this arc
        var x = dataSet.x;

        // y co-ordinate points for each point in this arc
        var y = dataSet.y;

        // Reflectivity (rainfall) intensity values for each point in this arc
        var reflectivity = dataSet.reflectivity;

        var geometry = new THREE.BufferGeometry();
        var pointsGraph = [];
        var coloursGraph = [];

        x.forEach(function (index, i) {
            if (reflectivity.MomentDataValues[i] > -33) {
                geometry = new THREE.BufferGeometry();

                var dataPointColour = new THREE.Color(reflectivityColourScale(reflectivity.MomentDataValues[i]));

                pointsGraph.push(x[i], y[i], 0);
                coloursGraph.push(dataPointColour.r, dataPointColour.g, dataPointColour.b);
            }
        });

        var pointsGraphArray = new Float32Array(pointsGraph);
        var coloursGraphArray = new Float32Array(coloursGraph);

        geometry.setAttribute('position', new THREE.BufferAttribute(pointsGraphArray, 3));
        geometry.setAttribute('color', new THREE.BufferAttribute(coloursGraphArray, 3));

        var pointsMap = new THREE.Points(geometry, pointsMaterial);
        scene.add(pointsMap);
        renderScene(scene, cameraPosition, renderer);
    }
}

function renderScene(scene, cameraPosition,renderer) {
    currentCamera.position.z = cameraPosition;
    currentRenderer.render(scene, currentCamera);
    requestAnimationFrame(renderScene);
}

Solution

  • for (let i = 0; i < scans; i++) {
      setTimeout(() => {
        // Your code goes here
      }, i * 100)
    }