Установка векторов в шейдерах, как это работает? OpenGL GLSL

Я пытаюсь понять, как работают вершинные и фрагментные шейдеры в OpenGL ES 2.0.

Мои шейдеры выглядят так:

вершинный шейдер:

// source code for the vertex shader
attribute vec4 vPosition
attribute vec2 a_texCoord;
varying vec2 v_texCoord;

void main() {
    gl_Position = vPosition;
    v_texCoord = a_texCoord;
}

фрагментный шейдер:

// source code for the fragment shader
precision mediump float;
uniform sampler2D s_texture;
varying vec2 v_texCoord;

void main() {
    gl_FragColor = texture2D(s_texture, v_texCoord);
}

Программа, использующая эти шейдеры, рисует простой двухмерный прямоугольник с текстурой (изображением). Сначала он передает вершины прямоугольника и координаты текстуры вершинному шейдеру с атрибутами. Затем вершинный шейдер передает текстурные координаты в зависимости от фрагментного шейдера.

Что меня смущает, так это то, что векторы vPosition, a_texCoord и v_texCoord могут сохранить только 1 точку, но должны сохранить 4 разных точки. Я где-то читал, что вершинный шейдер будет вызываться для каждой вершины. Означает ли это, что вершинный и фрагментный шейдеры будут обрабатываться 4 раза для каждого изображения, которое я хочу нарисовать? Когда я определяю атрибуты (glVertexAttribPointer), я использую массив с 4 точками, как шейдеры могут сохранить 4 точки в переменной, которая может хранить только 1 точку?

Хочу использовать униформу вместо атрибутов, читаю лучше. Также мне не нужна переменная. Я бы хотел, чтобы это было так:

вершинный шейдер:

// source code for the vertex shader
uniform vec4 vPosition;

void main() {
    gl_Position = vPosition;
}

фрагментный шейдер:

// source code for the fragment shader
precision mediump float;
uniform sampler2D s_texture;
uniform vec2 v_texCoord;

void main() {
    gl_FragColor = texture2D(s_texture, v_texCoord);
}

Это возможно? Могу ли я передать шейдерам все необходимые баллы? Это хорошая идея?


person Alexanus    schedule 02.03.2015    source источник


Ответы (1)


Нет, вы не можете хранить данные для каждой вершины в униформе. Униформа предназначена для каждого вызова отрисовки, а атрибут вершины предназначен для каждой вершины. Единственный способ использовать положение вершины с униформой - это нарисовать точку, поскольку она использует только 1 координату.

Итак, насчет вершин и обработки: Да, если вы рисуете с 4 вершинами, будет как минимум 4 вызова вершинного шейдера для обработки этих вершин. Вам не о чем беспокоиться, представьте, что при рисовании изображения размером 100x100 с использованием 4 вершин будет 4 вызова вершинного шейдера и 10000 (100x100) вызовов фрагментного шейдера. Это то, для чего предназначен графический процессор, он делает это чрезвычайно эффективно.

Вы можете посмотреть некоторые полные диаграммы конвейеров openGL, чтобы лучше все понять, но просто чтобы дать вам представление о том, что происходит, когда вы вызываете openGL для рисования:

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

Опять же, в этом конвейере гораздо больше, чем я описал, но они наиболее интересны для вопросов, которые вы задаете.

Постарайтесь понять, что шейдеры - это всего лишь часть длинного фиксированного конвейера, который теперь можно переопределить, вы не должны спрашивать себя, сколько раз они вызываются, по крайней мере, не для такой простой операции, как та, которую вы выполняете. Если вам нужно оптимизировать количество этих вызовов, вам, скорее всего, потребуется оптимизировать процессор. Например, если вы рисуете несколько тысяч больших прямоугольников, перекрывающих друг друга, вы можете подумать об алгоритме уменьшения размера, необходимого для рисования прямоугольника, который в основном перекрывается другими, или даже не рисовать его вообще, если он полностью перекрывается.

Итак, чтобы понять, что происходит с шейдерами, которые вы опубликовали: если вы рисуете текстурированный прямоугольник, у вас будет 4 или 6 вызовов вершинного шейдера (6 с использованием двух треугольников). Вершинный шейдер получит все включенные атрибуты, которые в вашем случае являются координатами положения и текстуры. С этими двумя значениями ничего не делается, а передается вперед. Затем положение автоматизировано (вам не нужен другой изменяющийся параметр для его передачи), но координата текстуры назначается изменяющемуся свойству, которое вы назвали v_texCoord. Это означает, что координата текстуры будет интерполироваться для каждого пикселя, который будет отрисовываться, и эти значения затем будут получены во фрагментном шейдере. Это причина, по которой вы действительно можете видеть нарисованную текстуру, поскольку каждый пиксель имеет другой цвет, взятый из текстуры с другой интерполированной координатой, полученной фрагментным шейдером. Таким образом, замена атрибута на униформу нарушит все это, никаких интерполяций не произойдет, и все ваши пиксели будут выглядеть точно так же.

person Matic Oblak    schedule 02.03.2015
comment
Большое спасибо за этот подробный ответ - person Alexanus; 02.03.2015