Skip to content

Instantly share code, notes, and snippets.

@maxatwork
Last active May 11, 2022 02:30
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maxatwork/016b9ec95e313626ec5472e226249ada to your computer and use it in GitHub Desktop.
Save maxatwork/016b9ec95e313626ec5472e226249ada to your computer and use it in GitHub Desktop.
Simple image processing shaders

Примеры можно попробовать в редакторе http://www.kickjs.org/tool/shader_editor/shader_editor.html

Значения uniform задаются на вкладке Uniforms (не забываем жать Update).

Вершинный шейдер

Общий для всех шейдеров:

precision highp float;

attribute vec3 vertex;
attribute vec2 uv1;

varying vec2 vUv;

uniform mat4 _mv; // в three.js по умолчанию это modelViewMatrix
uniform mat4 _mvProj; // в three.js по умолчанию это projectionMatrix

void main() {
    vUv = uv1;
    gl_Position = _mvProj * _mv * vec4(vertex, 1.0);
}

Фрагментные шейдеры

Простая текстура

https://goo.gl/Lk6mUe

precision highp float;

varying vec2 vUv;

uniform sampler2D tex;

void main(void)
{
    // просто берем цвет текселя по uv-координатам
    gl_FragColor = texture2D(tex, vUv);
}

Ч/б изображение (среднее по всем цветам)

https://goo.gl/zCqtL4

precision highp float;

varying vec2 vUv;

uniform sampler2D tex;

void main(void)
{
    // получаем цвет текселя по uv-координатам
    vec4 texel = texture2D(tex, vUv);
    
    // получаем яркость усредняя компоненты цвета
    float l = (texel.r + texel.g + texel.b)/3.0;
    
    // отдаем цвет, в котором в каждой компоненте
    // значение яркости
    gl_FragColor = vec4(l, l, l, texel.a);
}

Ч/б изображение (с учетом особенностей зрения)

https://goo.gl/AniDqG

precision highp float;

varying vec2 vUv;

uniform sampler2D tex;

void main(void)
{
    // получаем цвет текселя по uv-координатам
    vec4 texel = texture2D(tex, vUv);
    
    // коэффициенты вклада в яркость пиксела 
    // соответствующих компонент цвета
    vec3 luma = vec3(0.299, 0.587, 0.114);
    
    // вычисляем яркость
    // эквивалент texel.r*luma.r + texel.g*luma.g + texel.b*luma.b
    float l = dot(texel.rgb, luma); 
    
    // отдаем цвет, в котором в каждой компоненте
    // значение яркости
    gl_FragColor = vec4(l, l, l, texel.a);
}

Luminosity HiPass filter

Оставляет только яркие участки изображения и выкручивает контраст.

https://goo.gl/aXoyPw

precision highp float;

varying vec2 vUv;

uniform sampler2D tex;

uniform float defaultOpacity; // хорошее значение 1.0
uniform vec3 defaultColor; // хорошее значение vec3(0, 0, 0)
uniform float luminosityThreshold; // порог, хорошее значение для дефолтной текстуры 0.4
uniform float smoothWidth; // ширина плавного перехода, хорошее значение для дефолтной текстуры 0.2

void main(void)
{
    // получаем цвет текселя по uv-координатам
    vec4 texel = texture2D(tex, vUv);
    
    // получаем яркость фрагмента (аналогично ч/б)
    vec3 luma = vec3(0.299, 0.587, 0.114);
    float l = dot(texel.rgb, luma);
    
    // вычисляем коэффициент смешения (альфа)
    // если яркость меньше порога - 0.0
    // если яркость больше порога + ширина плавного перехода - 1.0
    // если в пределах полосы плавного перехода - интерполированное значение
    float alpha = smoothstep(luminosityThreshold, luminosityThreshold + smoothWidth, l);

    // смешиваем дефолтный цвет (черный) и цвет текселя
    vec4 outputColor = vec4(defaultColor.rgb, defaultOpacity);
    gl_FragColor = mix(outputColor, texel, alpha);
}

Fast Gaussian blur pass

Нужно два прохода, один размывает по горизонтали (direction = vec2(1, 0)), второй - полученный результат по вертикали (direction = vec2(0, 1)).

https://goo.gl/xynLN5

precision highp float;

varying vec2 vUv;

uniform sampler2D tex;

uniform vec2 texSize; // размеры текстуры
uniform vec2 direction; // направление размытия

// радиус размытия
#define KERNEL_RADIUS 20

float gaussianPdf(in float x, in float sigma) {
    return 0.39894 * exp(-0.5 * x * x / (sigma * sigma)) / sigma;
}

void main(void)
{
    float sigma = float(KERNEL_RADIUS);

    // диапазон uv-координат - 0.0-1.0, 
    // так что нам нужен шаг в 1.0/texSize 
    vec2 invSize = 1.0 / texSize;
    
    float weightSum = gaussianPdf(0.0, sigma);
    vec3 diffuseSum = texture2D(tex, vUv).rgb * weightSum;

    // для каждого текселя достаем значения соседних,
    // и добавляем их с соответствующими весами к текущему
    for(int i = 1; i < KERNEL_RADIUS; i++) {
        float x = float(i);
        float w = gaussianPdf(x, sigma);
        vec2 vUvOffset = direction * invSize * x;
        vec3 sample1 = texture2D(tex, vUv + vUvOffset).rgb;
        vec3 sample2 = texture2D(tex, vUv - vUvOffset).rgb;
        diffuseSum += (sample1 + sample2) * w;
        weightSum += 2.0 * w;
    }

    gl_FragColor = vec4(diffuseSum/weightSum, 1.0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment