我正在使用OpenFrameworks制作2D动画。 我正在尝试实现一个着色器,以根据形状边缘的方向移动用颜色填充的某些形状。
基本上,它需要像这样的图像:
并吐出类似以下内容:
请注意,它只是故意从形状的左侧获取颜色。
现在我的片段着色器看起来像这样:
#version 150
out vec4 outputColor;
uniform sampler2DRect fbo;
uniform sampler2DRect mask;
vec2 point;
vec4 col;
float x,i;
float delta = 200;
vec4 extrudeColor()
{
x = gl_FragCoord.x > delta ? gl_FragCoord.x - delta : 0;
for(i = gl_FragCoord.x; i > x; i--)
{
point = vec2(i, gl_FragCoord.y);
if(texture(fbo, point) != vec4(0,0,0,0)){
col = texture(fbo, point);
return vec4(col.r, col.g, col.b, (i-x)/delta);
}
}
return vec4(0,0,0,1);
}
void main()
{
outputColor = texture(mask, gl_FragCoord.xy) == vec4(1,1,1,1) && texture(fbo, gl_FragCoord.xy) == vec4(0,0,0,0) ? extrudeColor() : vec4(0,0,0,0);
}
mask
采样器只是第二张图像的黑白版本,我用它来避免计算形状之外的像素。
我拥有的着色器可以工作,但是速度很慢,我感觉我没有使用正确的GPU思想和编码。
我对glsl和opengl完全陌生。有没有一种方法可以使这种迭代更有效地通过相邻像素,而无需进行如此多的texture()
读取?
也许使用矩阵? IDK!
答案 0 :(得分:0)
这是解决此问题的效率极低的方法。尽量避免在着色器中出现条件(如果是)和循环(对于)。我建议加载或生成单个纹理,然后使用Alpha蒙版创建所需的形状。纹理可以保持恒定,而每帧可以生成2或8位掩码。
另一种方法是使用一些制服并将“每行”数据上传到数组中:
#version 440 core
uniform sampler2D _Texture ; // The texture to draw
uniform vec2 _Position ; // The 'object' position (screen coordinate)
uniform int _RowOffset ; // The offset in the 'object' to start drawing
uniform int _RowLength ; // The length of the 'row' to draw
uniform int _Height ; // The height of the 'object' to draw
in vec2 _TexCoord ; // The texture coordinate passed from Vertex shader
out vec4 _FragColor ; // The output color (gl_FragColor deprecated)
void main () {
if (gl_FragCoord.x < (_Position.x + _RowOffset)) discard ;
if (gl_FragCoord.x > (_Position.x + _RowOffset + _RowLength)) discard ;
_FragColor = texture2D (_Texture, _TexCoord.st) ;
}
或者,根本不对纹理进行采样,您可以生成线性渐变函数并使用Y坐标对颜色进行采样:
const vec4 _Red = vec4 (1, 0, 0, 1) ;
const vec4 _Green vec4 (0, 1, 0, 0) ;
vec4 _GetGradientColor (float _P /* Percentage */) {
float _R = (_Red.r * _P + _Green.r * (1 - _P) / 2 ;
float _G = (_Red.g * _P + _Green.g * (1 - _P) / 2 ;
float _B = (_Red.b * _P + _Green.b * (1 - _P) / 2 ;
float _A = (_Red.a * _P + _Green.a * (1 - _P) / 2 ;
return (vec4 (_R, _G, _B, _A)) ;
}
然后在片段着色器中
float _P = gl_FragCoord.y - _Position.y / _Height ;
_FragColor = _GetGradientColor (_P) ;
当然,可以对所有这些进行优化,并且仅生成2色渐变,而您似乎需要多种颜色。 Google快速搜索“线性梯度生成器”可以为您提供一些更好的选择。我还应该注意,这个简单的示例不适用于其中带有“孔”的形状,但可以对其进行修改以做到这一点。如果着色器数学运算太重,则选择带有Alpha蒙版的纹理选项。