WebGL2 中的布局限定符比 getAttribLocation 有何优势?

How are layout qualifiers better than getAttribLocation in WebGL2?

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

这里有 2 个想法

  1. 手动为属性分配位置
  2. 在 GLSL 中分配属性位置与 JavaScript

为什么要分配位置?

  1. 你不需要查找位置,因为你已经知道了
  2. 您想确保 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;

稍后在另一个没有纹理坐标但有法线的着色器中执行此操作

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 方式,则无需编辑任何着色器。

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

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,这样它不会影响渲染速度,并且您通常只使用初始化时的位置设置顶点数组的时间。

is it better to set locations to integers or would you be able to use strings as well?

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

中 N 总是 >= 16