【发布时间】:2018-04-12 22:15:51
【问题描述】:
我正在尝试复制一种称为“gooey effect”的网页设计技巧(现场观看here)。 这是一种在移动椭圆上应用 SVG 过滤器以获得类似斑点的运动的技术。这个过程相当简单:
- 应用高斯模糊
- 仅增加 Alpha 通道的对比度
两者结合产生斑点效果
最后一步(增加 Alpha 通道对比度)通常通过“颜色矩阵过滤器”完成。
一个颜色矩阵由 5 列(RGBA + 偏移)和 4 行组成。
前四列中的值分别与源红色、绿色、蓝色和 alpha 值相乘。第五列的值被添加(偏移)。
在 CSS 中,增加 alpha 通道对比度就像调用 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 值确实会影响颜色,但更改 alpha 值(最后一行)不会!
当尝试将着色器与高斯过滤器结合使用时,即使我将 Alpha 通道对比度设置为 60(如在 codepen 示例中),绘制的椭圆仍然保持模糊:
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 的高斯模糊 shader(来自 PostFX 库)中实现颜色矩阵时,也会发生同样的事情。我可以看到颜色在变化,但不是 alpha 对比度:
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;
}
在主 .pde 文件中设置 glBlendFunc 并启用 glEnable(GL_BLEND) 也不能解决问题。
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();
}
问题:
- 为什么 Alpha 通道对比度不起作用?我怎样才能让它发挥作用?
- 我实现颜色矩阵的方式有问题吗?
- 您知道实现这种粘性效果的更好方法吗?
任何帮助将不胜感激!
谢谢
【问题讨论】:
-
这仅解决了最后一个问题,但另一种选择是使用元球。
-
感谢您的建议,我已经编写了元球。我想尝试一种新的(更快的)方法。
-
好的!我以前没有使用过元球,但它们在待办事项列表中。刚刚添加,谢谢!
-
@solub 我不熟悉处理或您正在使用的包,但是:OpenGL 中的 Alpha 通道仅在启用
GL_BLEND且仅在glBlendFunc时使用使用 Alpha 通道,如果使用源 Alpha,那么在创建上下文的像素格式时,您还必须有 Alpha 缓冲区。所以我敢打赌,你的模糊根本没有使用 alpha。使用不同的着色器可能意味着不同的输入/输出布局和制服,因此您必须将 CPU 端代码与其匹配,否则着色器将无法正常工作。顺便说一句,也许您可以为此使用 Stencil 以某种方式将模糊图像变为实心图像 -
@solub 混合无法在片段着色器中启用。您必须设置
glBlendFunc并启用glEnable(GL_BLEND)
标签: glsl processing shader colormatrix colormatrixfilter