Search code examples
javascriptthree.jscrashwebgltweenjs

Tween JS causing loss of WebGL Context


I am using Tween.js to update a lissajous curve within a Three.js render cycle. This works for the most part, however, after approximately 70 iterations WebGL seems to crash along with the error: CONTEXT_LOST_WEBGL: loseContext: context lost. This lack of stability is disconcerting, especially since it seems to require me to restart my browser sometimes to get WebGL to work again (no only on this pages, but other pages using WebGL too).

The lissajous curve is not very high vertice and uses no textures (which seems to be a cause in other WebGL context losses), so I am fairly sure this must be due to my implementation of Tween.js which handles the interpolation between figures (specifically the .onComplete callback).

Can anyone provide any pointers as to why this might be occurring? My alternative will be to HandleContextLoss as per the WebGL docs.

function tweenLandingLissaj(newLissaj) {

  var update = function() {
    lissajousCurve.fa = current.freqA;
    lissajousCurve.fb = current.freqB;
    lissajousCurve.fc = current.freqC;
    lissajousCurve.phaseX = current.phaseX;
    lissajousCurve.phaseY = current.phaseY;
    lissajousCurve.phaseZ = current.phaseZ;
    lissajousCurve.update();
  };

  var current = {
    freqA: lissajousCurve.fa,
    freqB: lissajousCurve.fb,
    freqC: lissajousCurve.fc,
    phaseX: lissajousCurve.phaseX,
    phaseY: lissajousCurve.phaseY,
    phaseZ: lissajousCurve.phaseZ
  };

  var tweenTo = new TWEEN.Tween(current);
  tweenTo.to({
    freqA: newLissaj.freqA,
    freqB: newLissaj.freqB,
    freqC: newLissaj.freqC,
    phaseX: newLissaj.phaseX,
    phaseY: newLissaj.phaseY,
    phaseZ: newLissaj.phaseZ
  }, 6000);
  tweenTo.onUpdate(update);
  tweenTo.onComplete(function() {
  
    tweenTo.to({
      freqA: Math.floor(Math.random() * 10) + 1,
      freqB: Math.floor(Math.random() * 10) + 1,
      freqC: Math.floor(Math.random() * 10) + 1,
      phaseX: Math.floor(Math.random() * 10) + 1,
      phaseY: Math.floor(Math.random() * 10) + 1,
      phaseZ: Math.floor(Math.random() * 10) + 1
    }, 6000);
    tweenTo.start();

  });

  tweenTo.start();

}


Solution

  • Never found the actual cause as to why Tween.js was cause losing of WebGL context. I suspect it was due to my use of the onComplete callback.

    I did, however, find a more elegant solution to achieve the effect I was after using the Tween.js library which doesn’t cause loss of context.

    By chaining two randomly generated tweens, I can create an infinitely generated lissajous curve w/o using the onComplete callback which was previously causing me issues.

    My solution can be found below for anyone who finds themselves in a similar situation:

    function tweenLandingLissaj(newLissaj) {
    
      var update = function() {
        lissajousCurve.fa = current.freqA;
        lissajousCurve.fb = current.freqB;
        lissajousCurve.fc = current.freqC;
        lissajousCurve.phaseX = current.phaseX;
        lissajousCurve.phaseY = current.phaseY;
        lissajousCurve.phaseZ = current.phaseZ;
        lissajousCurve.update();
      };
    
      var current = {
        freqA: lissajousCurve.fa,
        freqB: lissajousCurve.fb,
        freqC: lissajousCurve.fc,
        phaseX: lissajousCurve.phaseX,
        phaseY: lissajousCurve.phaseY,
        phaseZ: lissajousCurve.phaseZ
      };
    
      var tweenTo = new TWEEN.Tween(current);
      tweenTo.to({
        freqA: Math.floor(Math.random() * 10) + 1,
        freqB: Math.floor(Math.random() * 10) + 1,
        freqC: Math.floor(Math.random() * 10) + 1,
        phaseX: Math.floor(Math.random() * 10) + 1,
        phaseY: Math.floor(Math.random() * 10) + 1,
        phaseZ: Math.floor(Math.random() * 10) + 1
      }, 10000);
      tweenTo.onUpdate(update);
    
      var tweenBack = new TWEEN.Tween(current);
      tweenBack.to({
        freqA: Math.floor(Math.random() * 10) + 1,
        freqB: Math.floor(Math.random() * 10) + 1,
        freqC: Math.floor(Math.random() * 10) + 1,
        phaseX: Math.floor(Math.random() * 10) + 1,
        phaseY: Math.floor(Math.random() * 10) + 1,
        phaseZ: Math.floor(Math.random() * 10) + 1
      }, 10000);
      tweenBack.onUpdate(update);
    
      tweenTo.chain(tweenBack);
      tweenBack.chain(tweenTo);
    
      tweenTo.start();
    
    }