Я пытаюсь воспроизвести уловку веб-дизайна, известную как "липкий эффект" (см. live здесь). Это метод применения SVG-фильтров к движущимся эллипсам для получения движения, похожего на капли. Процесс довольно простой:
- применить размытие по Гауссу
- увеличить контраст только альфа-канала
Комбинация этих двух элементов создает эффект капли.
Последний шаг (увеличение контрастности альфа-канала) обычно выполняется с помощью «цветового матричного фильтра».
Цветовая матрица состоит из 5 столбцов (RGBA + смещение) и 4 строк.
Значения в первых четырех столбцах умножаются на исходные значения красного, зеленого, синего и альфа-канала соответственно. Значение пятого столбца добавлено (смещение).
В CSS увеличить контраст альфа-канала так же просто, как вызвать фильтр SVG и указать значение контраста (здесь 18):
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="goo" />
Однако в обработке все немного сложнее. Я считаю (могу ошибаться) единственный способ применить фильтр цветовой матрицы - это создать его в шейдере. После нескольких попыток я придумал эти (очень простые) вершинные и фрагментные шейдеры для цветопередачи:
colorvert.glsl
uniform mat4 transform;
attribute vec4 position;
attribute vec4 color;
varying vec4 vertColor;
uniform vec4 o=vec4(0, 0, 0, -9);
uniform lowp mat4 colorMatrix = mat4(1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 60.0);
void main() {
gl_Position = transform * position;
vertColor = (color * colorMatrix) + o ;
}
colorfrag.glsl
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
varying vec4 vertColor;
void main() {
gl_FragColor = vertColor;
}
ПРОБЛЕМА:
Цветовая матрица работает частично: изменение значений RGB влияет на цвета, а изменение альфа-значений (последняя строка) - нет!
При попытке объединить шейдер с фильтром Гаусса нарисованный эллипс остается размытым даже после того, как я установил контраст альфа-канала на 60 (как в примере кода):
PShader colmat;
void setup() {
size(200, 200, P2D);
colmat = loadShader("colorfrag.glsl", "colorvert.glsl");
}
void draw() {
background(100);
shader(colmat);
noStroke();
fill(255, 30, 30);
ellipse(width/2, height/2, 40, 40);
filter(BLUR,6);
}
То же самое происходит, когда я реализую цветовую матрицу в @cansik's Gaussian blur шейдер (из библиотеки PostFX). Я вижу, как меняются цвета, но не альфа-контраст:
blurFrag.glsl
/ Adapted from:
// <a href="http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html" target="_blank" rel="nofollow">http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html</a>
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
#define PROCESSING_TEXTURE_SHADER
uniform sampler2D texture;
uniform vec4 o=vec4(0, 0, 0, 0);
uniform lowp mat4 colorMatrix = mat4(1, 0.0, 0.0, 0.0,
0.0, 1, 0.0, 0.0,
0.0, 0.0, 1, 0.0,
0, 0.0, 0.0, 60.0); //Alpha contrast set to 60
varying vec2 center;
// The inverse of the texture dimensions along X and Y
uniform vec2 texOffset;
varying vec4 vertColor;
varying vec4 vertTexCoord;
uniform int blurSize;
uniform int horizontalPass; // 0 or 1 to indicate vertical or horizontal pass
uniform float sigma; // The sigma value for the gaussian function: higher value means more blur
// A good value for 9x9 is around 3 to 5
// A good value for 7x7 is around 2.5 to 4
// A good value for 5x5 is around 2 to 3.5
// ... play around with this based on what you need <span class="Emoticon Emoticon1"><span>:)</span></span>
const float pi = 3.14159265;
void main() {
float numBlurPixelsPerSide = float(blurSize / 2);
vec2 blurMultiplyVec = 0 < horizontalPass ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
// Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889)
vec3 incrementalGaussian;
incrementalGaussian.x = 1.0 / (sqrt(2.0 * pi) * sigma);
incrementalGaussian.y = exp(-0.5 / (sigma * sigma));
incrementalGaussian.z = incrementalGaussian.y * incrementalGaussian.y;
vec4 avgValue = vec4(0.0, 0.0, 0.0, 0.0);
float coefficientSum = 0.0;
// Take the central sample first...
avgValue += texture2D(texture, vertTexCoord.st) * incrementalGaussian.x;
coefficientSum += incrementalGaussian.x;
incrementalGaussian.xy *= incrementalGaussian.yz;
// Go through the remaining 8 vertical samples (4 on each side of the center)
for (float i = 1.0; i <= numBlurPixelsPerSide; i++) {
avgValue += texture2D(texture, vertTexCoord.st - i * texOffset *
blurMultiplyVec) * incrementalGaussian.x;
avgValue += texture2D(texture, vertTexCoord.st + i * texOffset *
blurMultiplyVec) * incrementalGaussian.x;
coefficientSum += 2.0 * incrementalGaussian.x;
incrementalGaussian.xy *= incrementalGaussian.yz;
}
gl_FragColor = (avgValue / coefficientSum ) * colorMatrix;
}
Установка glBlendFunc
и включение glEnable(GL_BLEND)
в основном файле .pde также не устранила проблему.
sketch.pde
import ch.bildspur.postfx.builder.*;
import ch.bildspur.postfx.pass.*;
import ch.bildspur.postfx.*;
import processing.opengl.*;
import com.jogamp.opengl.*;
PostFX fx;
void setup() {
size(200, 200, P2D);
fx = new PostFX(this);
}
void draw() {
background(100);
GL gl = ((PJOGL)beginPGL()).gl.getGL();
gl.glEnable(GL.GL_BLEND);
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE);
gl.glDisable(GL.GL_DEPTH_TEST);
noStroke();
fill(255, 30, 30);
ellipse(width/2, height/2, 40, 40);
fx.render().blur(80, 14).compose();
}
Вопросы:
- Почему не работает контраст альфа-канала? Как заставить его работать?
- Что-то не так с тем, как я реализовал цветовую матрицу?
- Вы знаете, как лучше реализовать этот липкий эффект?
Любая помощь приветствуется !
Спасибо
GL_BLEND
включен, и только еслиglBlendFunc
использует альфа-канал и если используется исходный альфа-канал, вы должны иметь также альфа-буфер при создании пиксельного формата вашего контекста. Так что я держу пари, что ваше размытие вообще не использует альфа. Использование другого шейдера может означать разные макеты ввода / вывода и униформы, поэтому вы должны согласовать с ним код на стороне процессора, иначе шейдер не будет работать должным образом. Кстати, возможно, вы могли бы использовать Stencil для этого, чтобы как-то превратить размытое изображение в сплошное - person Spektre   schedule 13.04.2018glBlendFunc
и включить _ 2_ - person Rabbid76   schedule 13.04.2018