有效地迭代片段着色器中的相邻像素

问题描述 投票:0回答:1

For context:

我正在使用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思考和编码。

The actual, more general question:

我对glsl和opengl完全不熟悉。有没有办法让这种迭代更有效地通过相邻的像素,而没有这么多的texture()读取?

也许使用矩阵? IDK!

c++ opengl glsl opengl-3
1个回答
0
投票

这是解决此问题的非常低效的方法。尝试在着色器中避免条件(如果是)和循环(for)。我建议加载或生成单个纹理,然后使用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)) ;
}

然后在你的Frag Shader中,

float _P = gl_FragCoord.y - _Position.y / _Height ;
_FragColor = _GetGradientColor (_P) ;

Shader Output

当然这一切都可以优化一点,这只会产生一个2色渐变,而你看起来需要几种颜色。谷歌快速搜索“线性梯度发生器”可以为您提供更好的选择。我还应该注意这个简单的例子不适用于带有“洞”的形状,但可以修改它。如果着色器数学太重,则选择带alpha蒙版选项的纹理。

© www.soinside.com 2019 - 2024. All rights reserved.