您只能需要一次 Canvas 上下文。以下所有请求都将返回null
,或者如果您将相同的选项传递给之前创建的相同上下文getContext()
.
现在,您链接到的页面没有通过preserveDrawingBuffer
创建上下文时的选项,这意味着为了能够从那里获取像素信息,您必须连接到与游戏循环发生的事件循环相同的事件循环中。
幸运的是,这个游戏确实使用了一个简单的requestAnimationFrame
循环,因此要连接到相同的事件循环,我们需要做的就是将代码包装在requestAnimationFrame
call.
由于回调是堆叠的,并且它们确实需要此类回调的下一帧来创建循环,因此我们可以确定我们的调用将在它们之后堆叠。
我现在意识到这可能并不明显,所以我将尝试进一步解释什么请求动画帧确实如此,以及我们如何确保我们的回调将在 Unity 的回调之后被调用。
requestAnimationFrame(fn)
pushes fn
回调到一堆回调中,这些回调将在浏览器执行其操作之前以先进先出的顺序同时调用绘制到屏幕上运营。这种情况偶尔会发生一次(通常每秒 60 次),发生在最近的事件循环结束时。
可以理解为一种setTimeout(fn , time_remaining_until_next_paint)
,主要区别是保证请求动画帧回调执行器将在事件循环结束时被调用,因此在该事件循环的其他 js 执行之后。
所以如果我们打电话requestAnimationFrame(fn)
在调用回调的同一事件循环中,我们的假time_remaining_until_next_paint
将会0
, and fn
将被推入堆栈的底部(后进,后出)。
并且打电话的时候requestAnimationFrame(fn)
从回调执行器本身内部,time_remaining_until_next_paint
周围会有一些东西16
, and fn
将在下一帧的第一个中被调用。
所以任何电话requestAnimationFrame(fn)
由外部制成请求动画帧的回调执行器保证在同一个事件循环中被调用requestAnimationFrame 供电循环,并在之后调用。
所以我们需要抓取这些像素,就是将调用包装到读取像素 in a 请求动画帧调用,并调用它afterUnity 的循环开始了。
var example = document.getElementById('#canvas');
var context = example.getContext('webgl2') || example.getContext('webgl');
var pixels = new Uint8Array(context.drawingBufferWidth * context.drawingBufferHeight * 4);
requestAnimationFrame(() => {
context.readPixels(0, 0, context.drawingBufferWidth, context.drawingBufferHeight, context.RGBA, context.UNSIGNED_BYTE, pixels);
// here `pixels` has the correct data
});