Как фрагментный шейдер может использовать значения цвета ранее визуализированного кадра?

Я учусь использовать шейдеры в OpenGL ES.

В качестве примера: вот мой шейдер фрагмента игровой площадки, который берет текущий видеокадр и делает его оттенками серого:

varying highp vec2 textureCoordinate;

uniform sampler2D videoFrame;

void main() {
    highp vec4 theColor = texture2D(videoFrame, textureCoordinate);
    highp float avrg = (theColor[0] + theColor[1] + theColor[2]) / 3.0;
    theColor[0] = avrg; // r
    theColor[1] = avrg; // g
    theColor[2] = avrg; // b
    gl_FragColor = theColor;
}

theColor представляет текущий пиксель. Было бы здорово также получить доступ к предыдущему пикселю по этой же координате.

Ради любопытства я хотел бы добавить или умножить цвет текущего пикселя на цвет пикселя в предыдущем кадре рендеринга.

Как я мог сохранить предыдущие пиксели и передать их моему фрагментному шейдеру, чтобы что-то с ними сделать?

Примечание. На iPhone это OpenGL ES 2.0.


person SecretService - not really    schedule 25.07.2011    source источник
comment
Как говорит Матиас Вальденегро ниже, вам необходимо выполнить рендеринг в FBO. Но когда вы это сделаете и визуализируете с помощью шейдера, он будет довольно ярким, вам следует разделить на три вместо двух, чтобы получить правильное среднее значение. Способ, который чаще используется при преобразовании в оттенки серого, использует взвешенную сумму компонентов цвета. См. mathworks.com/help/toolbox/images/ref/rgb2gray.html, какие веса подходят.   -  person Rickard    schedule 25.07.2011
comment
Спасибо за указание на это. Была опечатка в моем коде.   -  person SecretService - not really    schedule 25.07.2011
comment
И вам вообще не следует складывать и делить. Вам следует использовать внутреннюю функцию dot, которая отображается на инструкцию, которая выполняет как за один шаг, так и намного быстрее.   -  person Damon    schedule 25.07.2011
comment
Спасибо! Что именно вы подразумеваете под внутренней функцией точки? Вы можете указать на ресурс или пример?   -  person SecretService - not really    schedule 25.07.2011
comment
Я имею в виду dot(theColor.xyz, vec3(0.3333)). Скалярное произведение умножает два вектора, а затем складывает компоненты. Это именно то, что вы делаете, за исключением того, что это одна инструкция с одним циклом. См. точку   -  person Damon    schedule 25.07.2011
comment
@Damon: Это может быть одной инструкцией с одним циклом. Также может быть 3 инструкции (одно векторное умножение, два зависимых сложения). Однако, как бы то ни было, он все равно будет превосходить его код. Или, в худшем случае, не будет медленнее, так что он все равно должен это сделать.   -  person Nicol Bolas    schedule 26.07.2011


Ответы (2)


Вам нужно отрендерить предыдущий кадр в текстуру, используя объект фреймбуфера (FBO), затем вы можете прочитать эту текстуру в своем фрагментном шейдере.

person Dr. Snoopy    schedule 25.07.2011
comment
Можете ли вы привести несколько примеров или указать на хорошие ресурсы, посвященные этой теме? - person SecretService - not really; 25.07.2011

Внутренняя функция точки, на которую ссылается Дэймон, представляет собой программную реализацию математического скалярного произведения. Я не очень хорошо знаком с OpenGL, поэтому я не уверен, что такое точный вызов функции, но математически точечный продукт выглядит так:

Учитывая vector a и vector b, 'dot' product a 'dot' b дает скалярный результат c:

c = a.x * b.x + a.y * b.y + a.z * b.z

Большинство современного графического оборудования (и процессоров, если на то пошло) способны выполнять такие операции за один проход. В вашем конкретном случае вы можете легко вычислить свое среднее значение с помощью скалярного произведения, например:

highp vec4 = (1/3, 1/3, 1/3, 0) //or zero

Я всегда почему-то путаю 4-й компонент в однородных векторах и матрицах.

highp float avg = theColor DOT vec4

Это умножит каждый компонент theColor на 1/3 (и четвертый компонент на 0), а затем сложит их вместе.

person Cmdr. Awesome    schedule 28.07.2011