#javascript #opengl-es #webgl #twgl.js
#javascript #opengl-es #webgl #twgl.js
Вопрос:
Я работаю с обработкой изображений в WebGL и столкнулся с проблемой, которую, похоже, не могу решить. Я мало работал с GL, и у меня такое чувство, что я неправильно понимаю что-то фундаментальное и простое.
Моя цель — имитировать слои. Изначально я настраивал каждый слой, используя разные контексты, а затем скомпилировал каждый в окончательный отрисованный холст, но создание текстуры из холста при каждом рендеринге происходило медленно. Затем я использовал Uint8Array
для каждого слоя, который содержит данные изображения, и это было намного быстрее, но привело к проблеме, с которой я столкнулся сейчас.
Проблема в том, когда я добавляю более 8 слоев. Если у меня есть 8 слоев и добавить еще один, то первый слой кажется пустым — слой становится пустым. Я попытался перейти от Uint8Array
к использованию текстуры для каждого слоя, но проблема все еще сохраняется.
При необходимости я могу предоставить несколько фрагментов кода, но в нескольких файлах много кода, и это немного запутанно, поскольку я пытался это решить. Слои компилируются с использованием двух фреймбуферов для прорисовки взад и вперед, а шейдер обрабатывает математику.
Восемь слоев, рендеринг правильный:
Редактировать: Вот некоторый код, и я забыл упомянуть, что я использую вспомогательную библиотеку twgl.
Сначала я настраиваю текстуру слоя:
this.renderTexture = twgl.createTexture(gl, {
width: this.width,
height: this.height,
target: gl.TEXTURE_2D,
min: gl.NEAREST,
max: gl.NEAREST,
wrap: gl.CLAMP_TO_EDGE
});
Я рисую что-то (например, изображение) в framebuffer, а затем обновляю текстуру соответствующего слоя:
gl.readPixels(0, 0, this.width, this.height, gl.RGBA, gl.UNSIGNED_BYTE, this.buf8);
twgl.setTextureFromArray(gl, this.renderTexture, this.buf8, {
width: this.width,
height: this.height
});
И, наконец, я превращаю каждый слой в один:
// create two buffers to ping pong
var blendedFramebufferInfo = [
twgl.createFramebufferInfo(gl, [{
src: $this.layers.length === 1 ? null : bottomLayer.buf8,
width: gl.canvas.width,
height: gl.canvas.height,
target: gl.TEXTURE_2D,
format: gl.RGBA,
min: gl.NEAREST,
max: gl.NEAREST,
wrap: gl.CLAMP_TO_EDGE
}], gl.canvas.width, gl.canvas.height),
twgl.createFramebufferInfo(gl, [{
width: gl.canvas.width,
height: gl.canvas.height,
target: gl.TEXTURE_2D,
format: gl.RGBA,
min: gl.NEAREST,
max: gl.NEAREST,
wrap: gl.CLAMP_TO_EDGE
}], gl.canvas.width, gl.canvas.height)
];
var layers = [...],
activeBuffer = 1;
while (layer = layers.shift()) {
// bind to either buffer or canvas
twgl.bindFramebufferInfo(gl, layers.length ? blendedFramebufferInfo[activeBuffer] : null);
// set proper program
var programInfo = $this.setBlendProgram(layer.blendMode());
// set uniforms
twgl.setUniforms(programInfo, {
u_dst: blendedFramebufferInfo[activeBuffer ? 0 : 1].attachments[0],
u_src: layer.renderTexture
});
// draw
gl.drawArrays(gl.TRIANGLES, 0, 6);
// draw to other texture next time around
activeBuffer = activeBuffer ? 0 : 1;
}
Комментарии:
1. Можно посмотреть какой-нибудь код и ваши шейдеры? Трудно точно понять, что у вас происходит здесь на уровне API.
2. Добавлен соответствующий код. Шейдеры очень простые, с четырьмя вершинами и копирующим фрагментом, так что это определенно работает нормально.
3. Если проще объяснить, как это должно быть сделано без twgl, это совершенно нормально. Я бы предпочел даже не использовать библиотеку, но, как я уже сказал, я не слишком много работал с webgl, и его использование показалось мне более простым.
4. Вам нужно вызвать
gl.readPixels
? Не могли бы вы просто отобразить текстуру напрямую (прикрепите ее к фреймбуферу). Это будет намного быстрее. Что касается причины сбоя на 8 слоях, из кода, который вы опубликовали до сих пор, ничего не ясно. Можете ли вы привести рабочий пример в вопросе?5. Я думаю, что, возможно, я слишком усложнил свой код. Я собираюсь попытаться упростить вещи, и я опубликую здесь ответ с обновлением.