Как квалификаторы макета лучше, чем getAttribLocation в WebGL2? - PullRequest
0 голосов
/ 09 мая 2018

Поскольку я узнаю больше о WebGL2, я столкнулся с этим новым синтаксисом в шейдерах, где вы устанавливаете location внутри шейдеров через: layout (location=0) in vec4 a_Position;. Как это можно сравнить с получением attribute местоположения с традиционным gl.getAttribLocation('a_Position');. Я полагаю, это быстрее? Любые другие причины? Кроме того, лучше ли указывать местоположения целыми числами или вы также можете использовать строки?

1 Ответ

0 голосов
/ 10 мая 2018

Здесь объединены 2 идеи

  1. Назначение местоположений атрибутам вручную
  2. Назначение местоположений атрибутов в GLSL против JavaScript

Почему вы хотите назначить местоположения?

  1. Тогда вам не нужно искать это местоположение, поскольку вы уже знаете его
  2. Вы хотите убедиться, что две или более шейдерных программ используют одинаковые местоположения, чтобы они могли использовать одинаковые атрибуты. Это также означает, что один массив вершин может использоваться с обоими шейдерами. Если вы не назначите расположение атрибута, шейдеры могут использовать разные атрибуты для одних и тех же данных. Другими словами, shaderprogram1 может использовать атрибут 3 для позиции, а shaderprogram2 может использовать атрибут 1 для позиции.

Почему вы хотите назначать местоположения в 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 это более распространено. Это кажется мне плохим, потому что если вы когда-нибудь столкнулись с конфликтом, вам, возможно, придется редактировать 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 быстрее, чем вызывать его, но обычно вы должны вызывать gl.getAttribLocation только во время инициализации, чтобы это не влияло на скорость рендеринга, и вы обычно используете местоположения только во время инициализации при настройке массивы вершин.

лучше ли указывать местоположения целыми числами или вы также можете использовать строки?

Местоположения являются целыми числами. Вы вручную выбираете, какой индекс атрибута использовать. Как и выше, вы можете использовать подстановки, генерацию шейдеров, макросы препроцессора и т. Д. ... для преобразования некоторого типа строки в целое число, но в конечном итоге они должны быть целыми числами, и они должны находиться в диапазоне от числа атрибутов, поддерживаемых вашим GPU. Вы не можете выбрать произвольное целое число, например 9127. Только от 0 до N - 1, где N - это значение, возвращаемое gl.getParameter(MAX_VERTEX_ATTRIBS). Примечание N всегда будет> = 16 в WebGL2

...