GLSL中的片段着色器颜色插值?

4
我需要将范围在0到1之间的标量值映射到颜色。它将从绿色到红色(从0到1)使用纹理坐标进行线性插值。
我对OpenGL和GLSL不熟悉,目前我已经发现我需要在HTML标签中写入颜色值。
gl_FragColor

这是一个四维向量。我不确定如何通过一个从0到1.0范围内变化的标量值来计算gl_FragColor的R、G和B通道(它将从绿色变为红色,在0.5时将为白色)。


你是在使用一维纹理,还是从二维以上的UV中取标量值? - user652038
2D纹理中的每个像素都会给出0到1之间的值。 - ammar26
好的,那么坐标与问题无关。 - user652038
我正在从2D纹理像素中获取标量值。 - ammar26
很遗憾,那真的没有意义。你声称有一个从0到1的单一纹理坐标(到目前为止这是有意义的),但是接着你提到了一个二维纹理... 你需要两个坐标才能从二维纹理中查找一个值,除非你假设另一个坐标是恒定的(在这种情况下,一维纹理会更有意义)。 - Andon M. Coleman
我有一个二维纹理(我肯定需要两个坐标来查找它),在使用这两个坐标后得到的标量值范围从0到1。我正在使用该标量值在颜色之间进行插值。 - ammar26
3个回答

4
#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纹理。


1
永远不要在fs中分支,这是绝对可以避免的。即使在最现代的硬件上,4个块的碎片也会被评估,并且所有在它们中任何一个中被采取的分支都会强制gpu为每个碎片评估它们,无论是否需要。此外,这一切都关乎连贯性。靠近另一个的碎片应尽可能“连贯”(采取相同的分支),因为这可能导致只运行必要的分支。 - RecursiveExceptionException
为了解决避免分支的问题,我们应该始终使用像mixstepsmoothstep等函数,因为它们即使分支尽可能一致,也比分支更快。当然,也有一些特殊情况不适用于这个建议,但总体而言,这个建议非常有价值。 - RecursiveExceptionException

3

如果您在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);

2

您不需要担心手动夹紧,因为gl_FragColor在0-1之间被夹紧。

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

没错,只要颜色缓冲区具有标准化格式,它就可以被简化。我之前没有想到过这一点。 - Reto Koradi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接