В WebGL каковы различия между атрибутом, униформой и переменной?
Есть ли аналогия, которую я могу придумать при сравнении этих разных типов или как это работает?
Кроме того, что означает унифицирование матрицы?
Ответы
Ответ 1
Скопировано непосредственно из http://www.lighthouse3d.com/tutorials/glsl-tutorial/data-types-and-variables/. Фактический сайт имеет гораздо более подробную информацию, и было бы полезно проверить.
Переменные квалификаторы
Квалификаторы дают особое значение переменной. Следующие доступны квалификаторы:
- const - объявление имеет постоянную времени компиляции.
- attribute - глобальные переменные, которые могут меняться на вершину, которые передаются из приложения OpenGL в вершинные шейдеры. Этот определитель может использоваться только в вершинных шейдерах. Для шейдера это переменная только для чтения. См. Раздел "Атрибут".
- uniform - глобальные переменные, которые могут изменяться на примитив [...], которые передаются из OpenGL приложение к шейдерам. Этот определитель может использоваться в обеих вершинах и фрагментарные шейдеры. Для шейдеров это переменная только для чтения. См. Раздел "Униформа".
- variable - используется для интерполированных данных между вершинным шейдером и шейдером фрагментов. Доступно для записи в вершинном шейдере и только для чтения в шейдере фрагментов. См. Раздел Varying.
Что касается аналогии, const и равномерность подобны глобальным переменным в C/С++, одна константа, а другая может быть задана. Атрибут - это переменная, которая сопровождает вершину, например, цветные или текстурные координаты. Переменные переменных могут быть изменены вершинным шейдером, но не фрагментарным шейдером, поэтому по сути они передают информацию по конвейеру.
Ответ 2
uniform
являются параметрами для каждого примитива (постоянными во время всего вызова отрисовки);
attribute
- это параметры для каждой вершины (обычно: положения, нормали, цвета, UV,...);
varying
- это параметры на фрагмент (или на пиксель): они различаются от пикселя к пикселю.
Важно понять, как varying
работает для программирования ваших собственных шейдеров.
Допустим, вы определяете переменный параметр v
для каждой вершины треangularьника внутри вершинного шейдера. Когда этот изменяемый параметр отправляется фрагментному шейдеру, его значение автоматически интерполируется в зависимости от положения пикселя для рисования.
На следующем изображении красный пиксель получил интерполированное значение переменного параметра v
. Вот почему мы называем их "разными".
![varying parameter being bilinearly interpolated]()
Для простоты в приведенном выше примере используется билинейная интерполяция, которая предполагает, что все нарисованные пиксели имеют одинаковое расстояние от камеры. Для точного 3D-рендеринга графические устройства используют корректную в перспективе интерполяцию, которая учитывает глубину пикселя.
Ответ 3
В OpenGL "программа" представляет собой набор "шейдеров" (меньших программ), которые связаны друг с другом в конвейере.
// "program" contains a shader pipeline:
// vertex shader -> other shaders -> fragment shader
//
var program = initShaders(gl, "vertex-shader", "fragment-shader");
gl.useProgram(program);
Вершины процесса шейдеров (вершинный шейдер), геометрия (геометрический шейдер), тесселяция (тесселяционный шейдер), фрагменты (пиксельный шейдер) и другие задачи пакетного процесса (вычислительный шейдер), необходимые для растеризации трехмерной модели.
Шиндеры 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
).
-
Шейдеры Vertex и Fragment (любой шейдер действительно) могут использовать переменную uniform
для приема данных из приложения WebGL.
// Pass data from WebGL application to shader
var 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
var attributeHandle = gl.glGetAttribLocation(mProgram, "vertexVariableB");
gl.glEnableVertexAttribArray(attributeHandle);
gl.glVertexAttribPointer(attributeHandle, 3, gl.FLOAT, false, 0, 0);
-
Vertex Shader может передавать данные в шейдер фрагмента с использованием переменной varying
. См. Выше код GLSL (varying vec3 variableC;
).
Ответ 4
Униформы - это еще один способ передачи данных из нашего приложения на ЦП в шейдеры на GPU, но униформы немного отличаются по сравнению с атрибутами вершин. Прежде всего, униформа носит глобальный характер. Глобальный, означающий, что единообразная переменная является уникальной для каждого объекта программы шейдера и может быть доступна из любого шейдера на любом этапе программы шейдера. Во-вторых, независимо от того, что вы установили для унифицированного значения, униформы будут сохранять свои значения, пока они не будут сброшены или обновлены
Мне нравится описание из https://learnopengl.com/Getting-started/Shaders, потому что слово per-примитив не является интуитивным