Есть ли быстрый способ усреднить цвета из нескольких фреймбуферов в WebGL/Javascript?

Я очень новичок в теме WebGL. Что я хочу сделать, так это вычислить средний цвет 6 различных буферов кадра, как показано ниже на картинке. Теперь думаю, как лучше поступить? я пытался сделать

gl.readPixels(0, 0, 256, 256, gl.RGBA, gl.UNSIGNED_BYTE, pixelValues);

но это кажется очень медленным ... Есть ли способ, которым это может произойти на видеокарте?

введите здесь описание изображения

this is how the FBO is set up - I have this from a tutorial:

...

person timkado    schedule 13.12.2012    source источник


Ответы (2)


У вас есть два варианта

  1. Напишите фрагментный шейдер, который запускается один раз для каждой строки (для каждой текстуры) путем рендеринга четырехугольника (1 x высота текстуры), проходит по всем пикселям в строке и усредняет их. Повторите этот процесс для усредненных строк, и вы получите среднее значение всего изображения. Это называется сокращением потока.
  2. Вызовите glGenerateMipMap на своих FBO, а затем получите доступ к MIP-карте самого высокого уровня ( получить параметры этого mipmap с помощью glGetTexLevelParameter). Теперь вы можете использовать либо метод ReadPixels для значительно уменьшенного и усредненного мип-изображения, либо использовать GLSL, и это должно быть намного быстрее.
person Ani    schedule 13.12.2012
comment
Отлично! Большое спасибо. Я посмотрю на это. - person timkado; 13.12.2012
comment
Не могли бы вы привести пример, как получить наименьший мипмап из FBO? - person timkado; 14.12.2012
comment
Вы можете просто вызвать glGetTexImage(GL_TEXTURE_2D, ‹уровень, полученный из glGetTexLevelParameter›, ‹format ex:GL_RGBA›, ‹type ex: GL_UNSIGNED_SHORT›, pixelValues) (opengl.org/sdk/docs/man/xhtml/glGetTexImage.xml) - person Ani; 14.12.2012
comment
Вопрос про WebGL. В WebGL нет ни glGetTexImage, ни glGetTexLevelParameter. - person gman; 14.12.2012
comment
Ах, мой плохой - я думал об OpenGL, а не об OpenGL ES, на котором построен WebGL. - person Ani; 14.12.2012

С верхней части моей головы

  1. Сделать 6 фбос.
  2. Убедитесь, что каждый fbo сделан с прикрепленной текстурой, а не с буфером рендеринга.
  3. Рендеринг 6 сцен на 6 fbos
  4. Для каждой текстуры вызовите gl.generateMipmap(...)
  5. Напишите шейдер, который берет 6 текстур и усредняет их, используя texture2D с опцией смещения. Установите смещение на количество уровней в ваших текстурах. Это говорит графическому процессору использовать наименьший уровень.
  6. Рендерите единичный квадрат с этим шейдером в 1 пиксель fbo (или 1 пиксель в вашем заднем буфере).
  7. Вызовите gl.readpixels для этого 1 пикселя.

Я думаю, что шейдер будет выглядеть примерно так

--фрагментный шейдер--

precision mediump float;

uniform sampler2D u_textures[6];
uniform float u_bias;

void main() {
   // since we know we are rendering only with the last mip
   // then there is only 1 texel.
   vec2 center = vec2(0.5, 0.5);
   vec4 sum = 
     texture2D(u_textures[0], center, u_bias) +
     texture2D(u_textures[1], center, u_bias) +
     texture2D(u_textures[2], center, u_bias) +
     texture2D(u_textures[3], center, u_bias) +
     texture2D(u_textures[4], center, u_bias) +
     texture2D(u_textures[5], center, u_bias);
   gl_FragColor = sum / 6.0;
}
person gman    schedule 14.12.2012
comment
Одно изменение, которое вы можете сделать, это не использовать 6 FBO — вы можете установить 6 текстур на разные текстурные блоки и сначала усреднить их по пикселям, а ЗАТЕМ выполнить четырехъядерный рендеринг 1x1 пикселя для FBO. Таким образом, все, что вам нужно, это два FBO. - person Ani; 14.12.2012