Подтвердить что ты не робот

Как получить текущий цвет фрагмента?

Я пытаюсь обмануть шейдеры в GLSL, и я нашел полезные ресурсы и учебные пособия, но я все время сталкиваюсь с стенами для чего-то, что должно быть фундаментальным и тривиальным: как извлекает мой шейдер фрагмента цвет текущего фрагмента?

Вы устанавливаете окончательный цвет, говоря gl_FragColor = whatever, но, видимо, это значение только для вывода. Как вы получаете исходный цвет ввода, чтобы вы могли выполнять вычисления на нем? Это должно быть где-то в переменной, но если кто-то там знает свое имя, они, похоже, не записали его ни в каком учебнике или документации, с которыми я столкнулся до сих пор, и это подталкивает меня к стене.

4b9b3361

Ответ 1

Шейдер фрагмента получает gl_Color и gl_SecondaryColor как атрибуты вершин. Он также получает четыре переменные: gl_FrontColor, gl_FrontSecondaryColor, gl_BackColor и gl_BackSecondaryColor, что он может записывать значения. Если вы хотите передать исходные цвета прямо, вы бы сделали что-то вроде:

gl_FrontColor = gl_Color;
gl_FrontSecondaryColor = gl_SecondaryColor;
gl_BackColor = gl_Color;
gl_BackSecondaryColor = gl_SecondaryColor;

Фиксированная функциональность в конвейере, следующей за вершинным шейдером, затем зажимает их до диапазона [0..1] и выясняет, обращена ли вершина лицевой стороной или обратная сторона. Затем он будет интерполировать выбранный (передний или задний) цвет, как обычно. Затем шейдер фрагмента получит выбранные, зажатые, интерполированные цвета как gl_Color и gl_SecondaryColor.

Например, если вы нарисовали стандартный "треугольник смерти", например:

glBegin(GL_TRIANGLES);
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f(-1.0f, 0.0f, -1.0f);
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f(1.0f, 0.0f, -1.0f);
    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3d(0.0, -1.0, -1.0);
glEnd();

Затем вершинный шейдер выглядит следующим образом:

void main(void) {
    gl_Position = ftransform();
    gl_FrontColor = gl_Color;
}

с помощью фрагментарного шейдера:

void main() {
    gl_FragColor = gl_Color;
}

передаст цвета, как если бы вы использовали конвейер с фиксированной функциональностью.

Ответ 2

Если вы хотите выполнить многопроходный рендеринг, т.е. если вы предоставили фреймбуру и хотите сделать второй рендер, в котором вы используете предыдущий рендеринг, чем ответ:

  • Перенесите первый проход текстуры
  • Свяжите эту текстуру для второго прохода
  • Доступ к выделенному пикселю в шейдере

Шейдерный код для 3.2:

uniform sampler2D mytex; // texture with the previous render pass

layout(pixel_center_integer) in vec4 gl_FragCoord;
// will give the screen position of the current fragment

void main()
{
  // convert fragment position to integers
  ivec2 screenpos = ivec2(gl_FragCoord.xy);
  // look up result from previous render pass in the texture
  vec4 color = texelFetch(mytex, screenpos, 0);
  // now use the value from the previous render pass ...
}

Другими методами обработки отображаемого изображения будут OpenCL с OpenGL → OpenCL interop. Это позволяет вычислить больше CPU.

Ответ 3

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

Основная причина заключается в том, что, возможно, во время выполнения вашего шейдера фрагментов пока неизвестно. Фрагментные шейдеры запускаются параллельно, потенциально (в зависимости от того, какое оборудование) влияет на один и тот же пиксель, а отдельный блок, считывающий из своего рода FIFO, обычно отвечает за объединение этих данных позже. Это слияние называется "Смешивание" и пока не является частью программируемого конвейера. Это фиксированная функция, но у нее есть несколько разных способов объединить то, что генерирует ваш шейдер фрагмента с предыдущим значением цвета пикселя.

Ответ 4

Вам нужно пробовать текстуру в текущих координатах пикселей, что-то вроде этого

vec4 pixel_color = texture2D(tex, gl_TexCoord[0].xy);

Обратите внимание, что, как я видел, текстура2D устарела в спецификации GLSL 4.00 - просто найдите аналогичные функции текстуры... fetch.

Также иногда лучше указывать собственные пиксельные координаты вместо gl_TexCoord [0].xy - в этом случае записывать вершинный шейдер примерно так:

varying vec2 texCoord;

void main(void)
{
   gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0 );
   texCoord = 0.5 * gl_Position.xy + vec2(0.5);     
}

И в шейдере фрагмента используйте эту переменную texCoord вместо gl_TexCoord [0].xy.

Удачи.

Ответ 5

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

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

Ответ 6

Конвейер GPU имеет доступ к базовой информации о пикселях сразу после запуска шейдеров. Если ваш материал прозрачный, этап смешивания конвейера объединяет все фрагменты.

Обычно объекты смешиваются в том порядке, в котором они добавляются в сцену, если только они не были упорядочены с помощью z-buffering algo. Сначала вы должны добавить свои непрозрачные объекты, а затем аккуратно добавить свои прозрачные объекты в том порядке, в котором они будут смешаны.

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

Настройка функций смешивания SRC и DST для прозрачных объектов дает вам доступ к предыдущей смеси разными способами.

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

введите описание изображения здесь
<Я > рис. 1 - Single Pass

Если вам действительно нужен multi pass (рисунок 2), тогда вы должны нацеливать выходы фреймбуфера на дополнительную текстуру, а не на экрана и скопируйте эту целевую текстуру на следующий проход и т.д., нацелив экран на последний проход. Для каждого прохода требуется как минимум два контекстных переключателя.

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

введите описание изображения здесь
<Я > рис. 2 - Multi Pass

Я прибегал к словесному описанию с диаграммами трубопроводов, чтобы избежать устаревания, поскольку язык шейдера (сленг/GLSL) может быть изменен.

Ответ 7

как-делать-я-получить по-ток-цвет-в-а-фрагмента

Некоторые говорят, что это невозможно, но я говорю, что это работает для меня:

//Toggle blending in one sense, while always disabling it in the other.   
void enableColorPassing(BOOL enable) {
 //This will toggle blending - and what gl_FragColor is set to upon shader execution
   enable ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
   //Tells gl - "When blending, change nothing" 
   glBlendFunc(GL_ONE, GL_ZERO); 
}

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

Ну, по крайней мере, это работает для меня.