Я пытаюсь перенести голову вокруг программ построения теней в GLSL, и я нашел некоторые полезные ресурсы и учебные руководства, но я продолжаю сталкиваться со стеной для чего-то, что должно быть фундаментальным и тривиальным: как моя программа построения теней фрагмента получает цвет текущего фрагмента?
Вы выбираете итоговый цвет путем высказывания gl_FragColor = whatever
, но по-видимому это - значение только для вывода. Как Вы получаете исходный цвет входа, таким образом, можно выполнить вычисления на нем? Это получено, чтобы быть в переменной где-нибудь, но если кто-либо там знает ее имя, они, кажется, не записали ее ни в каком учебном руководстве или документации, на которую я натыкался до сих пор, и она управляет мной стена.
Фрагментный шейдер получает 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;
}
будут передавать цвета так же, как если бы вы использовали конвейер с фиксированной функциональностью.
Если то, что вы называете «текущим значением фрагмента», является значением цвета пикселя, которое было в цели рендеринга до запуска вашего фрагментного шейдера, то нет, это недоступно.
Основная причина этого в том, что потенциально на момент запуска вашего фрагментного шейдера это еще не известно. Фрагментные шейдеры работают параллельно, потенциально (в зависимости от оборудования) влияя на один и тот же пиксель, а отдельный блок, считываемый из какого-то типа FIFO, обычно отвечает за их объединение позже. Это слияние называется «смешиванием» и еще не является частью программируемого конвейера. Это фиксированная функция, но у нее есть несколько разных способов комбинировать то, что сгенерировал ваш фрагментный шейдер, с предыдущим значением цвета пикселя.
Если вы хотите выполнить многопроходный рендеринг, то есть если вы выполнили рендеринг во фреймбуфер и хотите выполнить второй проход рендеринга, где вы используете предыдущий рендеринг, то ответ будет следующим:
Код шейдера для 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 взаимодействия. Это позволяет больше вычислительных мощностей, подобных процессору.
Вся суть вашего фрагментного шейдера состоит в том, чтобы решить, какой будет выходной цвет. Как вы это сделаете, зависит от того, что вы пытаетесь сделать.
Вы можете настроить все так, чтобы вы получали интерполированный цвет на основе вывода вершинного шейдера, но более распространенным подходом было бы выполнение поиска текстуры во фрагментном шейдере с использованием координат текстуры, переданных из интерполянты вершинных шейдеров. Затем вы должны изменить результат поиска текстуры в соответствии с выбранными вами расчетами освещения и всем остальным, что должен делать ваш шейдер, а затем записать его в gl_FragColor.
Вам нужно сэмплировать текстуру в текущих координатах пикселя, что-то вроде этого
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]. ху.
Удачи.