Фрагмент шейдера OpenGL ES 2.0 для размытия идет медленно и низкого качества - PullRequest
6 голосов
/ 04 декабря 2010

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

Есть идеи о том, как что-то улучшить?

Пример вывода:

alt text

uniform sampler2D texture;
varying mediump vec2 fragTexCoord;
varying mediump vec3 eyespaceNormal;

varying highp float blurAmount;

void main(void)
{
    highp vec2 gaussFilter[7];
    gaussFilter[0] = vec2(-3.0, 0.015625);
    gaussFilter[1] = vec2(-2.0, 0.09375);
    gaussFilter[2] = vec2(-1.0, 0.234375);
    gaussFilter[3] = vec2(0.0, 0.3125);
    gaussFilter[4] = vec2(1.0, 0.234375);
    gaussFilter[5] = vec2(2.0, 0.09375);
    gaussFilter[6] = vec2(3.0, 0.015625);

    highp float blurSize = blurAmount * 1.0;

    /////////////////////////////////////////////////
    // 7x1 gaussian blur fragment shader
    /////////////////////////////////////////////////

    highp vec4 color = vec4(0,0,0,1);

    for( int i = 0; i < 7; i++ )
    {
        color += texture2D( texture, vec2( fragTexCoord.x+gaussFilter[i].x*blurSize, fragTexCoord.y+gaussFilter[i].x*blurSize ) )*gaussFilter[i].y;
    }

    gl_FragColor = color;
}

Редактировать: размытие рамки может бытьпутьВот версия шейдера для размытия в рамке:

highp vec4 color = vec4(0,0,0,1);

color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y - 4.0*blurAmount)) * 0.05;
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y - 3.0*blurAmount)) * 0.09;
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y - 2.0*blurAmount)) * 0.12;
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y - blurAmount)) * 0.15;
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y)) * 0.16;
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y + blurAmount)) * 0.15;
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y + 2.0*blurAmount)) * 0.12;
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y + 3.0*blurAmount)) * 0.09;
color += texture2D(texture, vec2(fragTexCoord.x, fragTexCoord.y + 4.0*blurAmount)) * 0.05;

gl_FragColor = color;

Вот вывод для размытия в рамке (обратите внимание, что это только горизонтальное размытие, но этого может быть достаточно для того, что я хочу): alt text

Ответы [ 3 ]

10 голосов
/ 05 декабря 2010

Этот шейдер должен запускаться дважды, чтобы он работал, то, что вы называете blurSize, должно быть vec2, а значение должно быть vec2(0, 1.0/height) для размытия по вертикали и vec2(1.0/width, 0) для размытия по горизонтали.

См. http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=240334

Идея создания двухпроходного размытия заключается в том, что оно значительно сократит количество поисков текстур и, возможно, увеличит скорость. Двухпроходное размытие с размером ядра 7x7 потребует 14 текстурных поисков, но если это сделать во вложенном цикле, вам потребуется 49 текстурных поисков.

3 голосов
/ 10 декабря 2010

Выполнение двух или более проходов размытия в поле улучшает качество почти до гауссова размытия, сохраняя при этом производительность относительно высокой. И размывать коробку можно относительно легко. Посмотрите на http://web.archive.org/web/20060718054020/http://www.acm.uiuc.edu/siggraph/workshops/wjarosz_convolution_2001.pdf

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

1 голос
/ 04 декабря 2010

Не ясно, что именно делает ваш код. Вы используете texture2D, который предлагает 2D-фильтр. Тем не менее, ваша матрица свертки имеет одно измерение, и вы делаете цикл только один раз. Я могу ошибаться, но кажется, что вы применяете размытие по диагонали. Если предполагается, что это 2D-фильтр, то вам потребуется два (вложенных) цикла для x и y соответственно, чтобы покрыть 2D-область.

А насчет переменной blurSize - ее название немного вводит в заблуждение. Размер размытия зависит от вашей матрицы свертки. Ваша 7 пикселей в ширину. Это определяет размер. Переменная больше похожа на «силу» размытия, которая может только ослабить эффект матрицы свертки. Если задано слишком высокое значение, возникнут артефакты.

Я не эксперт и не написал ни одного пиксельного шейдера, кроме "hello world" mandelbrot. Если я не ошибаюсь, то шейдер размытия - один из худших для ускорения. Большинство размытостей в реальном времени, которые я видел, были box-blurs . Попробуйте перенести некоторый код отсюда: gameDev thread .

...