布局限定符比WebGL2中的getAttribLocation更好?

时间:2018-05-09 17:17:30

标签: opengl-es webgl webgl2

随着我对WebGL2的了解越来越多,我在着色器中遇到了这种新语法,您可以通过以下方式在着色器中设置locationlayout (location=0) in vec4 a_Position;。与使用传统attribute获取gl.getAttribLocation('a_Position');位置相比,这相比如何?我认为它更快?还有其他原因吗?另外,将位置设置为整数还是可以使用字符串更好吗?

1 个答案:

答案 0 :(得分:4)

这里有两个想法混淆

  1. 手动将位置分配给属性
  2. 在GLSL与JavaScript中分配属性位置
  3. 您为什么要分配位置?

    1. 您不必查找该位置,因为您已经知道了
    2. 您希望确保2个或更多着色器程序使用相同的位置,以便它们可以使用相同的属性。这也意味着单个顶点数组可以与两个着色器一起使用。如果未指定属性位置,则着色器可能会对同一数据使用不同的属性。换句话说,shaderprogram1可能使用属性3作为位置,而shaderprogram2可能使用属性1作为位置。
    3. 为什么要在GLSL中分配位置而不是在JavaScript中进行分配?

      您可以在GLSL

      中指定这样的位置
      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中这样做更常见。这对我来说似乎很糟糕,因为如果你遇到过冲突,你可能需要编辑10s或100s着色器。例如,您从

      开始
      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比调用它更快,但是你通常只应该在初始化时调用gl.getAttribLocation,这样它不会影响渲染速度,你通常只使用init的位置设置顶点数组的时间。

        

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

      地点是整数。您手动选择要使用的属性索引。如上所述,您可以使用替换,着色器生成,预处理器宏等...将某些类型的字符串转换为整数,但它们最终需要为整数,并且它们需要在GPU支持的属性数量范围内。你不能选择像9127这样的任意整数。只有0到N - 1,其中N是gl.getParameter(MAX_VERTEX_ATTRIBS)返回的值。注意在WebGL2

      中N将始终为> = 16