代码之家  ›  专栏  ›  技术社区  ›  Detuned

在WebGL2中,布局限定符如何优于getAttribLocation?

  •  0
  • Detuned  · 技术社区  · 8 年前

    随着我对WebGL2的进一步了解,我在您设置的着色器中遇到了这种新语法 location 着色器内部通过: layout (location=0) in vec4 a_Position; .这与获得 attribute 位置与传统 gl.getAttribLocation('a_Position'); .我想是更快吧?还有其他原因吗?另外,将位置设置为整数更好吗,还是也可以使用字符串?

    1 回复  |  直到 8 年前
        1
  •  11
  •   gman    5 年前

    这里有两个想法

    1. 手动将位置指定给属性
    2. 在GLSL与JavaScript中指定属性位置

    为什么要分配位置?

    1. 既然你已经知道了位置,那么你就不必去查它了
    2. 要确保两个或多个着色器程序使用相同的位置,以便它们可以使用相同的属性。这也意味着一个顶点阵列可以与两个着色器一起使用。如果未指定属性位置,则着色器可能会对同一数据使用不同的属性。换句话说,shaderprogram1可能使用属性3表示位置,shaderprogram2可能使用属性1表示位置。

    为什么要在GLSL中分配位置,而不是在JavaScript中分配位置?

    您可以在GLSL ES 3.0(非GLSL ES 1.0)中指定这样的位置

    layout (location=0) in vec4 a_Position;
    

    您还可以像这样在JavaScript中分配位置

    // **BEFORE** calling gl.linkProgram
    gl.bindAttribLocation(program, 0, "a_Position");
    

    在我看来,用JavaScript做这件事似乎更加枯燥(不要重复)。事实上,如果使用一致的命名,则可以通过在调用之前为常用名称绑定位置来为所有着色器设置所有位置 gl.linkProgram 。使用JavaScript进行此操作的另一个小优势是它与GLSL ES 1.0和WebGL1兼容。

    我有一种感觉,虽然在GLSL中这样做更常见。这对我来说很糟糕,因为如果遇到冲突,可能需要编辑10或100个着色器。例如,您从

    layout (location=0) in vec4 a_Position;
    layout (location=1) in vec2 a_Texcoord;
    

    稍后,在另一个没有texcoord但具有法线的着色器中,可以执行此操作

    layout (location=0) in vec4 a_Position;
    layout (location=1) in vec3 a_Normal;
    

    然后很久以后,添加一个需要所有3个

    layout (location=0) in vec4 a_Position;
    layout (location=1) in vec2 a_Texcoord;
    layout (location=2) in vec3 a_Normal;
    

    如果希望能够使用所有3个具有相同数据的着色器,则必须编辑前2个着色器。如果使用JavaScript方式,则不必编辑任何着色器。

    当然,另一种方法是生成常见的着色器。然后可以注入位置

    const someShader = `
    layout (location=$POSITION_LOC) in vec4 a_Position;
    layout (location=$NORMAL_LOC) in vec2 a_Texcoord;
    layout (location=$TEXCOORD_LOC) in vec3 a_Normal;
    ...
    `;
    
    const substitutions = {
      POSITION_LOC: 0,
      NORMAL_LOC: 1,
      TEXCOORD_LOC: 2,
    };
    const subRE = /\$([A-Z0-9_]+)/ig;
    
    function replaceStuff(subs, str) {
      return str.replace(subRE, (match, group0) => {
        return subs[group0];
      });
    }
    
    ...
    
    gl.shaderSource(prog, replaceStuff(substitutions, someShader));
    

    或者注入预处理器宏来定义它们。

    const commonHeader = `
    #define A_POSITION_LOC 0
    #define A_NORMAL_LOC 1
    #define A_TEXCOORD_LOC 2
    `;
    
    const someShader = `
    layout (location=A_POSITION_LOC) in vec4 a_Position;
    layout (location=A_NORMAL_LOC) in vec2 a_Texcoord;
    layout (location=A_TEXCOORD_LOC) in vec3 a_Normal;
    ...
    `;
    
    gl.shaderSource(prog, commonHeader + someShader);
    

    速度快吗?是的,但可能不多,不打电话 gl.getAttribLocation 比打电话快,但通常只应打电话 德国劳埃德船级社。getAttribLocation 因此不会影响渲染速度,并且在设置顶点阵列时通常只使用初始时间的位置。

    是将位置设置为整数更好,还是也可以使用字符串?

    位置是整数。您正在手动选择要使用的属性索引。如上所述,您可以使用替换、着色器生成、预处理器宏等。。。将某种类型的字符串转换为整数,但它们最终必须是整数,并且必须在GPU支持的属性数范围内。不能选择像9127这样的任意整数。仅0到N-1,其中N是返回的值 gl.getParameter(MAX_VERTEX_ATTRIBS) 。注意N始终为>=16英寸WebGL2