GLSL 通道选择

ske*_*ogy 3 shader glsl

我有一个 GLSL 着色器,它从输入纹理的通道之一(例如 R)读取数据,然后写入输出纹理中的同一通道。该通道必须由用户选择。

我现在能想到的是只使用 int 制服和大量的 if 语句:

uniform sampler2D uTexture;
uniform int uChannelId;
varying vec2 vUv;

void main() {

    //read in data from texture
    vec4 t = texture2D(uTexture, vUv);
    float data;
    if (uChannelId == 0) {
        data = t.r;
    } else if (uChannelId == 1) {
        data = t.g;
    } else if (uChannelId == 2) {
        data = t.b;
    } else {
        data = t.a;
    }

    //process the data...
    float result = data * 2;  //for example

    //write out
    if (uChannelId == 0) {
        gl_FragColor = vec4(result, t.g, t.b, t.a);
    } else if (uChannelId == 1) {
        gl_FragColor = vec4(t.r, result, t.b, t.a);
    } else if (uChannelId == 2) {
        gl_FragColor = vec4(t.r, t.g, result, t.a);
    } else {
        gl_FragColor = vec4(t.r, t.g, t.b, result);
    }

}
Run Code Online (Sandbox Code Playgroud)

有什么方法可以做类似字典访问之类的事情吗t[uChannelId]

或者也许我应该有同一个着色器的 4 个不同版本,每个版本处理不同的通道,这样我就可以避免所有的 if 语句?

做这个的最好方式是什么?

编辑:更具体地说,我正在使用 WebGL (Three.js)

der*_*ass 5

有这样一种方法,就像你在问题中实际写的一样简单。只需使用t[channelId]. 引用GLSL 规范(来自版本 3.30,第 5.5 节,但也适用于其他版本):

数组下标语法也可以应用于向量以提供数字索引。所以在

vec4 pos;

pos[2]指pos的第三个元素,相当于pos.z。这允许将变量索引到向量中,以及访问组件的通用方式。任何整数表达式都可以用作下标。第一个组件的索引为零。使用值为负或大于或等于向量大小的常量积分表达式读取或写入向量是非法的。当使用非常量表达式进行索引时,如果索引为负数或者大于或等于向量的大小,则行为未定义。

请注意,对于代码的第一部分,您使用它来访问纹理的特定通道。您还可以使用ARB_texture_swizzle功能。在这种情况下,您只需使用固定通道(例如 )r来在着色器中进行访问,然后混合实际纹理通道,以便您想要访问的任何通道都变为r

更新:由于目标平台是 webgl,这些建议不可用。然而,一个简单的解决方案是使用vec4统一的值uChannelID,对于所选组件使用 1.0,对于所有其他组件使用 0.0。假设这个变量被称为uChannelSel. 您可以data=dot(t, uChannelSel)在第一部分和gl_FragColor=(vec4(1.0)-uChannelSel) * t + uChannelSel*result第二部分中使用。