【问题标题】:Color interpolation in Fragment Shader GLSL?片段着色器 GLSL 中的颜色插值?
【发布时间】:2014-07-26 15:02:48
【问题描述】:

我需要将标量值映射到范围为 0 到 1 的颜色。它将使用纹理坐标从绿色变为红色(从 0 到 1)线性插值(范围也从 0 到 1)

我是 OpenGL 和 GLSL 的新手,到目前为止我发现我需要在

中写入颜色值
gl_FragColor

这是一个维度为 4 的向量。我不确定如何仅通过一个范围为 0 到 1.0 的标量值来计算 gl_FragColor 的 R、G 和 B 通道(它将从 GREEN 到 RED 和 0.5它将是白色的)

【问题讨论】:

  • 您是在使用 1D 纹理,还是从 >= 2D UV 中获取标量?
  • 2D 纹理中的每个像素都给出从 0 到 1 的值
  • 好的。那么坐标与问题无关。
  • 我从 2D 纹理像素获取标量值
  • 不幸的是,这真的没有意义。您声称有一个从 0 到 1 的单个纹理坐标(到目前为止这是有道理的),但随后您提到了 2D 纹理......您需要两个坐标来从 2D 纹理中查找值,除非您假设另一个是恒定的(在这种情况下,一维纹理会更有意义).

标签: opengl glsl shader fragment-shader gpu


【解决方案1】:
#version 120

...

float remap( float minval, float maxval, float curval )
{
    return ( curval - minval ) / ( maxval - minval );
} 

...

const vec4 GREEN = vec4( 0.0, 1.0, 0.0, 1.0 );
const vec4 WHITE = vec4( 1.0, 1.0, 1.0, 1.0 );
const vec4 RED   = vec4( 1.0, 0.0, 0.0, 1.0 );

float u = <whatever, grabbed from a uniform?>;
u = clamp( u, 0.0, 1.0 );
if( u < 0.5 )
    gl_FragColor = mix( GREEN, WHITE, remap( 0.0, 0.5, u ) );
else
    gl_FragColor = mix( WHITE, RED, remap( 0.5, 1.0, u ) );

或者您可以对 3 像素的 1D 纹理进行采样。

【讨论】:

  • 永远不要在 fs 中分支并不是绝对可以避免的。即使在最现代的硬件上,片段也是以 4 个块为一组进行评估的,并且所有分支或其中任何一个都强制 gpu 为每个片段评估它们,无论是否需要。此外,这一切都与连贯性有关。靠近另一个的片段应该尽可能“连贯”(采用相同的分支),因为这可能会导致只运行必要的分支。
  • 为了解决避免分支的问题,应该始终使用mixstepsmoothstep 等函数,因为即使分支尽可能连贯,它们也会更快。当然,在某些极端情况下这是不正确的,但一般来说,这个建议是值得的。
【解决方案2】:

如果您在 0 到 1 范围内的值被命名为 val

if (val < 0.5)
{
    gl_FragColor = vec4(2.0 * val, 1.0, 2.0 * val, 1.0);
}
else
{
    gl_FragColor = vec4(1.0, 2.0 * (1.0 - val), 2.0 * (1.0 - val), 1.0);
}

或者如果你想避免分支语句:

gl_FragColor = vec4(min(2.0 * val, 1.0),
                    min(2.0 * (1.0 - val), 1.0), 
                    2.0 * min(val, 1.0 - val),
                    1.0);

不确定这是否真的会更快。正如@Jessy 所指出的,如果颜色缓冲区具有标准化格式,则可以简化此操作,因为在这种情况下,输出颜色会自动限制在 [0, 1] 范围内,因此不需要进行一些 min 调用:

gl_FragColor = vec4(2.0 * val,
                    2.0 * (1.0 - val), 
                    2.0 * min(val, 1.0 - val),
                    1.0);

【讨论】:

    【解决方案3】:

    您不必担心手动钳制,因为 gl_FragColor 被钳制在 0-1 之间。

    float red = 2. * texel;
    float green = 2. - red;
    gl_FragColor = vec4(red, green, min(red, green), 1.);
    

    【讨论】:

    • 没错,至少只要颜色缓冲区具有标准化格式,就可以简化。我没想到。
    猜你喜欢
    • 1970-01-01
    • 2020-12-05
    • 2020-11-20
    • 2013-08-01
    • 2011-10-04
    • 2017-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多