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

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

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

30
задан Mason Wheeler 29 April 2010 в 21:25
поделиться

5 ответов

Фрагментный шейдер получает 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;
}

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

14
ответ дан 28 November 2019 в 00:14
поделиться

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

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

7
ответ дан 28 November 2019 в 00:14
поделиться

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

  1. Рендеринг первого прохода в текстуру
  2. Привязать эту текстуру ко второму проходу
  3. Доступ к пикселю, отрисованному в тайне, в шейдере

Код шейдера для 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 взаимодействия. Это позволяет больше вычислительных мощностей, подобных процессору.

12
ответ дан 28 November 2019 в 00:14
поделиться

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

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

3
ответ дан 28 November 2019 в 00:14
поделиться

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

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

Примечание, как я видел, текстура2D устарела в спецификации GLSL 4.00 - просто ищите похожую текстуру... функции извлечения.

Также иногда лучше указать собственные пиксельные координаты вместо 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]. ху.

Удачи.

4
ответ дан 28 November 2019 в 00:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: