glsl片段着色器颜色添加逻辑

Posted

技术标签:

【中文标题】glsl片段着色器颜色添加逻辑【英文标题】:glsl fragment shader color addition logic 【发布时间】:2020-11-20 06:45:00 【问题描述】:

我正在尝试将过滤器应用于 WebGL 中的纹理,但我无法理解在片段着色器中颜色是如何叠加的。

比如说我有这个,像这样将红色和黑色加在一起:

vec3 red = vec3(1., 0., 0.);
color.rgb = vec3(0., 0., 0.) + red;    

gl_FragColor = color;

它像我期望的那样输出红色。在红色通道上,我们有 0. + 1. = 1.

但是当对我当前的纹理颜色应用相同的逻辑时,alpha 通道 = 1。

vec3 red = vec3(1., 0., 0.);
color.rgb = texture.rgb + red;    

gl_FragColor = color;

我在之前和之后得到这个:

黑色仍然是黑色,它会使白色区域着色,这是怎么回事?为什么不遵循同样的逻辑?

如何对图像进行着色,以便黑色成为我想要的颜色,而其他一切都是所述颜色的较浅变体。

这是完整的片段着色器代码:

precision mediump float;

uniform sampler2D u_image;
uniform vec2 u_resolution;
uniform vec2 u_position;
uniform vec2 u_pointer;
uniform vec2 u_tex_size;
uniform float u_zoom;
uniform float u_mask_amplitude;
uniform float u_mask_top;
uniform float u_mask_bottom;

// the texCoords passed in from the this.vertex shader.
varying vec2 v_texCoord;

// scale from center
float scale(float a) 
    return a / (1. / u_zoom) - (.5 / (1. / u_zoom));


vec4 toGrayscale(in vec4 color)
    float average = (color.r + color.g + color.b) / 3.0;
    return vec4(average, average, average, 1.0);


vec4 colorize(in vec4 grayscale, in vec4 color)
    return grayscale * color ;


float luminance(vec3 rgb)
    // Algorithm from Chapter 10 of Graphics Shaders.
    const vec3 W = vec3(0.2125, 0.7154, 0.0721);
    return dot(rgb, W);


float dist(vec2 a, vec2 b)
    float x = a.x - b.x;
    x = x * u_resolution.x / u_resolution.y;
    float y = a.y - b.y;
    return sqrt((x * x) + (y * y));


void main() 
    
    // Look up a color from the texture.
    vec4 color = texture2D(u_image, v_texCoord);
    
    float x = v_texCoord.x;
    float y = v_texCoord.y;
    
    
    // map position
    x = x + (u_position.x) / 3.;
    y = y + u_position.y;
    
    
    // repeat & scaling
    float repeat_x = mod((x * 3.0), 1.0);
    
    
    // texture
    color = texture2D(u_image, vec2(repeat_x, y));
    
    
    // mask_offset
    
    vec2 pointer = (u_pointer + u_resolution / 2.) / u_resolution - 1.;
    float tex_offset = u_tex_size.x / u_resolution.x;
    
    
    pointer = pointer / u_zoom;
    pointer.x = pointer.x + u_position.x * tex_offset;
    pointer.y = pointer.y + u_position.y;
    
    vec2 text_coor = vec2((x * 3.) - 1.5, y - .5);
    
    
    text_coor.x = text_coor.x * tex_offset;
    // text_coor.y = text_coor.y * tex_offset;
    
    
    
    
    
    
    // should invert
    
    float PI = 3.1415926535897932384626433832795;
    
    float mask_top = u_mask_top / u_resolution.y;
    float mask_bottom = u_mask_bottom / u_resolution.y;
    
    mask_top = mask_top - .5; // .5 is center
    mask_bottom = mask_bottom - .5; // .5 is center
    
    float width = 10000./u_resolution.x;
    float amplitude = u_mask_amplitude;
    
    bool top = scale(v_texCoord.y) + mask_top > sin(scale(v_texCoord.x) * width - (PI / 2.)) * amplitude;
    bool bottom = scale(v_texCoord.y) + mask_bottom < sin(scale(v_texCoord.x) * width - (PI / 2.)) * amplitude;
    bool invert = top && bottom;
    
    
    
    
    //
    
    float dist = dist(pointer, text_coor) * 1.5;
    if(!invert) dist = dist / 3.;
    
    color.r = color.r + dist * u_zoom;
    color.g = color.g + dist * u_zoom;
    color.b = color.b + dist * u_zoom;
    
    
    // greyscale
    
    float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
    color = vec4(vec3(gray), 1.0);
    
    
    
    // invert
    
    if(invert)
        
        vec3 filter = vec3(0., 0.1215686275, 0.2039215686);
        color.rgb = 1. - color.rgb; // invert
        color.rgb = color.rgb + filter;
        
    
    
    gl_FragColor = color;
    

【问题讨论】:

您在问题中发布的代码中未显示其他事情。添加更多代码。 还有很多事情要做,这是完整的片段着色器代码gist.github.com/saminton/b5e9d2ab650e161aa021bca9854227e4 它主要是位置操作,唯一与颜色有关的部分是在我转换为灰度并在尝试应用过滤器之前反转纹理颜色的最后部分 哦,还有掩蔽效果,实际上我认为这可能是问题所在。如果我有一个 color.r = .5 的颜色,并且我将颜色乘以 4,那么 color.r = 2。还是会在 color.r = 1 处停止。我读到颜色从 0 变为 1,所以我假设它会在 1 点停止。 除非您写入浮点纹理,否则它将在输出 1 处停止。 【参考方案1】:

我已经弄清楚发生了什么。我有一个径向蒙版效果,我在应用颜色过滤器之前将纹理乘以一个值,如下所示:

color.r = color.r + dist * u_zoom, 1.;
color.g = color.g + dist * u_zoom, 1.;
color.b = color.b + dist * u_zoom, 1.;

结果是每个通道的值可以大于或小于 1。所以当我去添加过滤器时,即使屏幕上的颜色显示为黑色,它的值必须更小,所以添加 .2 到 - .5 例如保持黑色。

【讨论】:

以上是关于glsl片段着色器颜色添加逻辑的主要内容,如果未能解决你的问题,请参考以下文章

片段着色器中设置的颜色未显示 GLSL 1.30

GLSL 问题:一个程序中有多个着色器

GLSL:使用片段着色器进行对象翻译

带有片段着色器的 GLSL 仅渲染黑色 GL_POINTS

GLSL/C++:自定义着色器的默认行为

顶点着色器的绘制操作