Вы можете запросить контекст холста только один раз. Все последующие запросы будут либо возвращать null
, либо тот же контекст, который был создан ранее, если вы передали те же параметры в getContext()
.
Теперь одна страница, на которую вы ссылались, не прошла опцию preserveDrawingBuffer
при создании их контекста, что означает, что для того, чтобы иметь возможность получать информацию о пикселях оттуда, вам придется подключиться в том же цикле событий как игровой цикл.
К счастью, в этой точной игре используется простой цикл requestAnimationFrame
, поэтому для подключения к одному и тому же циклу событий все, что нам нужно, - это также обернуть наш код в вызов requestAnimationFrame
.
Поскольку обратные вызовы составлены и им требуется следующий кадр из одного такого обратного вызова для создания цикла, мы можем быть уверены, что наш вызов будет сложен после их.
Теперь я понимаю, что это может быть неочевидно, поэтому я попытаюсь объяснить, что делает requestAnimationFrame , и как мы можем быть уверены, что наш обратный вызов будет вызван после Unity.
requestAnimationFrame(fn)
помещает fn
обратный вызов в стек обратных вызовов, которые будут вызываться одновременно в порядке «первым пришел - первым вышел», незадолго до того, как браузер выполнит рисование на экране операции. Это происходит время от времени (обычно 60 раз в секунду), в конце ближайшего цикла событий.
Это можно понимать как разновидность setTimeout(fn , time_remaining_until_next_paint)
, с основным отличием в том, что гарантируется, что requestAnimationFrame исполнитель обратного вызова будет вызван в конце цикла события и, следовательно, после другого js выполнения этого события цикл. * +1025 *
Так что, если бы мы вызывали requestAnimationFrame(fn)
в том же цикле событий, что и тот, куда будут вызываться обратные вызовы, наша фальшивая time_remaining_until_next_paint
будет 0
, а fn
окажется в нижней части нашего стека (последний в последний раз)
И при вызове requestAnimationFrame(fn)
изнутри самого исполнителя обратных вызовов, time_remaining_until_next_paint
будет что-то около 16
, и fn
будет вызван среди первых в следующем кадре.
Таким образом, любые вызовы requestAnimationFrame(fn)
, сделанные извне исполнителя обратных вызовов requestAnimationFrame , гарантированно будут вызываться в том же цикле событий, что и активный цикл запроса requestAnimationFrame , и позвать после.
Таким образом, все, что нам нужно, чтобы захватить эти пиксели, это заключить вызов в readPixels в вызове requestAnimationFrame и вызвать его после цикла Unity, запущенного .
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
});