简体   繁体   English

通过片段着色器中的相邻像素进行有效迭代

[英]Efficiently iterate trough neighbouring pixels in fragment shader

For context: 对于上下文:

I'm working on a generative 2D animation with OpenFrameworks. 我正在使用OpenFrameworks进行生成2D动画。 I'm trying to implement a shader shifts the fills some shapes with a color, depending on the orientation of the shapes edges. 我正在尝试使用颜色来实现着色器移动填充某些形状,具体取决于形状边缘的方向。

Basically it takes an image like this one: 基本上它需要像这样的图像: 输入

and spits out something like this: 并吐出这样的东西: 产量

Note that it intentionally only takes the color from the left side of the shape. 请注意,它有意只从形状的左侧获取颜色。

Right now my fragment shader looks like this: 现在我的片段着色器看起来像这样:

#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);
}

the mask sampler is just a black and white version of the second image that I use to avoid calculating pixels outside of the shapes. mask采样器只是第二个图像的黑白版本,我用它来避免计算形状外的像素。

The shader I have works but it is slow and I feel like I'm not using proper GPU thinking and coding. 我有效的着色器,但它很慢,我觉得我没有使用正确的GPU思考和编码。

The actual, more general question: 实际的,更一般的问题:

I'm totally new to glsl and opengl. 我对glsl和opengl完全不熟悉。 Is there a way to make this kind of iteration trough neighbouring pixels more efficiently and without having this many texture() reads? 有没有办法让这种迭代更有效地通过相邻像素,而没有这么多的texture()读取?

Maybe using matrices? 也许使用矩阵? IDK! IDK!

This is a highly inefficient way to approach this problem. 这是解决此问题的非常低效的方法。 Try to avoid conditionals (if's) and loops (for's) in your shader. 尝试在着色器中避免条件(如果是)和循环(for)。 I would suggest loading or generating a single texture, and then using an alpha mask to create the shape you need. 我建议加载或生成单个纹理,然后使用alpha蒙版创建所需的形状。 The texture could remain constant, while the 2 or 8-bit mask could be generated per frame. 纹理可以保持不变,而每帧可以生成2或8位掩码。

An alternative method would be to use a few uniforms and upload "per-line" data in an array: 另一种方法是使用一些制服并在数组中上传“每行”数据:

#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) ;
}

Or, without sampling a texture at all, you could generate a linear gradient function and sample the color from it using the Y coordinate: 或者,根本不对纹理进行采样,您可以生成线性渐变函数,并使用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)) ;
}

Then in your Frag Shader, 然后在你的Frag Shader中,

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

Shader Output 着色器输出

Of course this all could be optimised a bit, and this only generates a 2-color gradient whereas it looks like you're needing several colors. 当然这一切都可以优化一点,这只会产生一个2色渐变,而你看起来需要几种颜色。 A quick Google search for "linear gradient generator" can land you some nicer alternatives. 谷歌快速搜索“线性梯度发生器”可以为您提供更好的选择。 I should also note this simple example will not work for shapes with 'holes' in them, but it can be revised to do so. 我还应该注意这个简单的例子不适用于带有“洞”的形状,但可以修改它。 If the shader math gets too heavy, then choose the texture with alpha mask option. 如果着色器数学太重,则选择带alpha蒙版选项的纹理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM