В чем разница между атрибутом, униформой и переменной в WebGL?

83

Есть ли аналогия, которую я могу придумать, сравнивая эти разные типы, или как они работают?

Кроме того, что означает униформа матрицы?

Скорпиус
источник

Ответы:

90

Скопировано прямо с http://www.lighthouse3d.com/tutorials/glsl-tutorial/data-types-and-variables/ . Фактический сайт содержит гораздо более подробную информацию, и его стоит проверить.

Квалификаторы переменных

Квалификаторы придают переменной особое значение. Доступны следующие квалификаторы:

  • const - Объявление константы времени компиляции.
  • attribute - Глобальные переменные, которые могут изменяться для каждой вершины, которые передаются из приложения OpenGL в вершинные шейдеры. Этот квалификатор можно использовать только в вершинных шейдерах. Для шейдера это переменная только для чтения. См. Раздел Атрибуты.
  • uniform - Глобальные переменные, которые могут изменяться для [...] примитива, которые передаются из приложения OpenGL шейдерам. Этот квалификатор можно использовать как в вершинных, так и в фрагментных шейдерах. Для шейдеров это переменная только для чтения. См. Раздел «Униформа».
  • варьирующийся - используется для интерполированных данных между вершинным шейдером и фрагментным шейдером. Доступно для записи в вершинном шейдере и только для чтения во фрагментном шейдере. См. Раздел «Варьирование».

Что касается аналогии, const и uniform похожи на глобальные переменные в C / C ++, одна постоянна, а другая может быть установлена. Атрибут - это переменная, которая сопровождает вершину, например координаты цвета или текстуры. Варьирующие переменные могут быть изменены вершинным шейдером, но не фрагментным шейдером, поэтому, по сути, они передают информацию по конвейеру.

Альфредо Хименес
источник
1
Просто чтобы немного расширить атрибуты: атрибут не обязательно должен быть атрибутом массива (атрибут массива необходим, если значение может быть различным для каждой вершины). Это также может быть постоянный атрибут вершины, и в этом случае значение распределяется между всеми вершинами. Фактически, атрибут массива должен быть активно включен gl.enableVertexAttribArray.
Роберт Монфера
Хорошо, что текст здесь, потому что веб-сайт мертв
ziyuang
Просто чтобы быть «этим парнем», но я не вижу на сайте ничего, что предполагало бы, что копирование здесь было законным.
gman
66
  • uniformявляются примитивными параметрами (постоянными в течение всего вызова отрисовки);
  • attributeпараметры для каждой вершины (обычно: позиции, нормали, цвета, UV, ...);
  • varyingпараметры для каждого фрагмента (или для каждого пикселя ): они варьируются от пикселей к пикселям.

Важно понимать, как varyingработает программирование собственных шейдеров.
Допустим, вы определяете переменный параметр vдля каждой вершины треугольника внутри вершинного шейдера . Когда этот изменяющийся параметр отправляется фрагментному шейдеру , его значение автоматически интерполируется в зависимости от положения пикселя для рисования.

На следующем изображении красный пиксель получил интерполированное значение изменяющегося параметра v. Вот почему мы называем их «разными».

переменный параметр билинейно интерполируется

Для простоты в приведенном выше примере используется билинейная интерполяция , которая предполагает, что все нарисованные пиксели находятся на одинаковом расстоянии от камеры. Для точного 3D-рендеринга графические устройства используют интерполяцию с коррекцией перспективы, которая учитывает глубину пикселя.

нееех
источник
2
Суть ответа верна, но помните, что для изменения выполняемая по умолчанию интерполяция называется интерполяцией с коррекцией перспективы, а не просто билинейной интерполяцией. Конечно, это можно изменить с помощью квалификатора интерполяции, noperspective чтобы получить простую билинейную интерполяцию, а не интерполяцию с правильной перспективой (определяется квалификатором по умолчанию:) smooth. См. Этот пример .
legends2k
Спасибо, я добавлю об этом примечание.
neeh
11

В чем разница между атрибутом, униформой и переменной в WebGL?

В OpenGL «программа» - это набор «шейдеров» (небольших программ), которые соединены друг с другом в конвейер.

// "program" contains a shader pipeline:
//   vertex shader -> other shaders -> fragment shader
//
const program = initShaders(gl, "vertex-shader", "fragment-shader");
gl.useProgram(program);

Шейдеры обрабатывают вершины (вершинный шейдер), геометрию (геометрический шейдер), тесселяцию (тесселяционный шейдер), фрагменты (пиксельный шейдер) и другие задачи пакетной обработки (вычисление шейдера), необходимые для растеризации 3D-модели.

Шейдеры OpenGL (WebGL) написаны на GLSL (текстовом языке шейдеров, скомпилированном на GPU).

// Note: As of 2017, WebGL only supports Vertex and Fragment shaders

<!-- Vertex Shader -->
<script id="shader-vs" type="x-shader/x-vertex">

  // <-- Receive from WebGL application
  uniform vec3 vertexVariableA;

  // attribute is supported in Vertex Shader only
  attribute vec3 vertexVariableB;

  // --> Pass to Fragment Shader
  varying vec3 variableC;

</script>

<!-- Fragment Shader -->
<script id="shader-fs" type="x-shader/x-fragment">

  // <-- Receive from WebGL application
  uniform vec3 fragmentVariableA;

  // <-- Receive from Vertex Shader
  varying vec3 variableC;

</script>

Помня об этих концепциях:

Шейдеры могут передавать данные следующему шейдеру в конвейере ( out, inout), а также могут принимать данные из приложения WebGL или предыдущего шейдера ( in).

  • Вершинные и фрагментные шейдеры (на самом деле любой шейдер) могут использовать uniformпеременную для получения данных из приложения WebGL.

    // Pass data from WebGL application to shader
    const uniformHandle = gl.glGetUniformLocation(program, "vertexVariableA");
    gl.glUniformMatrix4fv(uniformHandle, 1, false, [0.1, 0.2, 0.3], 0);
    
  • Vertex Shader также может получать данные из приложения WebGL с attributeпеременной, которую можно включать или отключать по мере необходимости.

    // Pass data from WebGL application to Vertex Shader
    const attributeHandle = gl.glGetAttribLocation(mProgram, "vertexVariableB");
    gl.glEnableVertexAttribArray(attributeHandle);
    gl.glVertexAttribPointer(attributeHandle, 3, gl.FLOAT, false, 0, 0);
    
  • Вершинный шейдер может передавать данные во фрагментный шейдер с помощью varyingпеременной. См. Код GLSL выше ( varying vec3 variableC;).

tfmontague
источник
1

Униформы - это еще один способ передачи данных из нашего приложения на CPU шейдерам на GPU, но униформы немного отличаются от атрибутов вершин. Во-первых, униформа глобальна. Глобальная, что означает, что универсальная переменная уникальна для каждого объекта программы шейдера и может быть доступна из любого шейдера на любом этапе программы шейдера. Во-вторых, какое бы значение вы ни установили для униформы, униформы сохранят свои значения до тех пор, пока они не будут сброшены или обновлены.

Мне нравится описание с https://learnopengl.com/Getting-started/Shaders , потому что слово per-primitive не интуитивно понятно

Лю Хао
источник