如何在切换标签后阻止Chrome处理(?)我的webgl绘图上下文?

时间:2017-06-26 21:40:12

标签: javascript google-chrome canvas html5-canvas webgl

我遇到了Chrome(当前)的意外问题。我有一个Web应用程序,它使用webGL画布进行一些基本的图像处理,然后将webGl画布复制到2D画布,以便保存图像数据。问题是,在切换标签后,webgl画布的绘图上下文似乎在Chrome中丢失了。在我尝试过的任何其他浏览器中都不会发生这种情况(FF,IE 11 / Edge,Safari)。

如果确实发生了这种情况,我希望Chrome也会触发webgl上下文丢失事件,但我从未得到过该事件。

这是一个非常简单的小提琴,展示了这个问题。

https://jsfiddle.net/JoeBlow/m14evgzj/

1)加载绘制到webgl画布的页面

2)切换到新标签页

3)切换回原始标签页

4)点击“复制图片”。

如果我重新初始化3d画布(重新加载所有内容并重新绘制),那么即使在切换选项卡后,一切都按预期工作,但我试图避免在窗口/视口上捕获模糊/焦点事件。

这是简化的代码:

window.canvasSource  = document.getElementById("source");
var canvasDestination = document.getElementById("destination");
var buttonCopy = document.getElementById("btnCopy");
var btnToggle = document.getElementById("btnToggle");
var btnClear = document.getElementById("btnClear");
var btnInit3d = document.getElementById('btnInit3d');

var canvasOptions = { preserveDrawingBuffer: true };

//var sourceContext = canvasSource.getContext("2d", options);
var destinationContext = canvasDestination.getContext("2d", canvasOptions);

window.canvasSource.addEventListener("webglcontextlost", function(event) {
console.log('context lost');
    event.preventDefault();
}, false);

window.canvasSource.addEventListener("webglcontextrestored", init3d, false);

btnToggle.addEventListener('click', function() {
    if (window.canvasSource.style.visibility != "hidden") {
      window.canvasSource.style['visibility']='hidden';
    }
  else {
   window.canvasSource.style['visibility'] = 'visible';
  }
});

btnCopy.addEventListener('click', function() {
    destinationContext.drawImage(window.canvasSource,0,0);
});

btnClear.addEventListener('click', function() {
    destinationContext.clearRect(0,0, 1500, 1500);
});

btnInit3d.addEventListener('click', function() {
    init3d();
});

function init3d() {
console.log('init3d()');
window.gl = window.canvasSource.getContext("webgl", canvasOptions);
var gl = window.gl;
if (gl==null)
 console.log("couldn't get webgl context");
else 
 console.log(gl);

gl.viewport(0, 0, window.canvasSource.width, window.canvasSource.height);
gl.clearColor(0, 0.5, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);

var v = document.getElementById("vertex").firstChild.nodeValue;
var f = document.getElementById("fragment").firstChild.nodeValue;

var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, v);
gl.compileShader(vs);

var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, f);
gl.compileShader(fs);

program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
}

init3d();

1 个答案:

答案 0 :(得分:2)

我想这个问题与this one有关。

显然,当标签模糊时,chrome会清除drawingBuffer,即使你确实告诉它不要这样做。

可能的解决方法是创建一个preserveDrawingBuffer对象。

2DContext不受此错误的影响,因此您可以创建一个屏幕外的2D上下文,而不是在您的wegbl启动时设置preserveDrawingBuffer,您将在每个新的draw上绘制webgl上下文。



var canvasSource = document.getElementById("source");
var canvasDestination = document.getElementById("destination");
var buttonCopy = document.getElementById("btnCopy");
//var btnToggle = document.getElementById("btnToggle");
var btnClear = document.getElementById("btnClear");
var btnInit3d = document.getElementById('btnInit3d');
var gl;

// we don't need to preserve the drawing buffer anymore
// since we'll do it manually
//var canvasOptions = { preserveDrawingBuffer: true};
var bufferContext = canvasSource.cloneNode().getContext('2d');
// 2D context don't have an preserveDrawingBuffer option
var destinationContext = canvasDestination.getContext("2d");

btnCopy.addEventListener('click', function() {
  var error = gl.getError();
  if (error) {
    console.log('Gl Error: ' + error);
  }
  // we draw the buffer canvas instead of the webgl one
  destinationContext.drawImage(bufferContext.canvas, 0, 0);
});

btnClear.addEventListener('click', function() {
  destinationContext.clearRect(0, 0, 1500, 1500);
});

function init3d() {
  gl = canvasSource.getContext("webgl");
  if (gl == null)
    console.log("couldn't get webgl context");

  gl.viewport(0, 0, canvasSource.width, canvasSource.height);
  gl.clearColor(0, 0.5, 0, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);
  // at each draw, save the webgl state
  bufferContext.drawImage(canvasSource, 0,0);
}

init3d();

<canvas id="source"> </canvas>
<canvas id="destination"> </canvas>
<div>
  <button id="btnCopy">Copy Image</button>
  <button id="btnClear">Clear Copy</button>
</div>
&#13;
&#13;
&#13;