Search code examples
javascriptthree.jscollada

why would THREE.ColladaLoader halt all activity on the site?


I am loading an animated .dae file, and I've used the 'onProgress' argument to see it's loading progress. The file loads to 74% in 2 seconds, but then the whole page is paused for 23 more seconds before the model actually loads (and all other activity pauses including css animations). I added a setInterval() to show the progress, but that also gets halted as soon as the loader reaches 74%. On page load, this is my code:

var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load('models/swing_dancing.dae', function(collada) {
    dae = collada.scene;
    dae.traverse(function(child) {
        if (child instanceof THREE.SkinnedMesh) {
            var animation = new THREE.Animation(child, child.geometry.animation);
            animation.play();
        }
    });

    dae.scale.x = dae.scale.y = dae.scale.z = 0.002;
    dae.updateMatrix();

    init();
    animate();

}, function(xhr) {
    console.log(('progress ' + xhr.loaded / xhr.total * 100) + '% loaded')
});

Any ideas? I'm building off of the example here and documentation here

enter image description here


Solution

  • That is because JS is single theaded and once the file is loaded, what is asynchronous, it starts to parse it and creates everything, what is called a "blocking" process, because it uses the one thread which is available for JS until it is done. Afterwards your animation is resumed. While such a process is running, the UI is frozen, or blocked. That happens because the processing time is much longer than the duration of a single frame (1000/60ms), so the browser cannot update the ui an all other animations.

    The only way out of it, is to split the parse and creation task into multiple smaller ones, which can be executed one by one each animation frame, or with a timeout. That way you running animation will gain some processing time in the meantime.

    To illustrate:

       ms | frame | task
    ------+-------+------------- 
        0 |   0   | update preload animation
    ..........................................
        n |   m   | update preload animation + start to process data from server
    ------------------------------------------
        h | m+1   | processing (parsing *dea, creating objects)
    ------------------------------------
     h+3s | m+2   | processing done, animation and UI updates continue
    

    So frame m+1 will be ~3 seconds long, but should be 100/6 ms, so that is why your animation is stuck.

    To show an animation WHILE the initialiaion is running you would need something like this each frame:

    frame n    update Animation, process subtask (<-- this must not take too long)
    frame n+1 .
    frame n+2 .
    frame n+3 .
    
    Until all substasks are executed