¿Cómo sabe el sombreador de fragmentos qué variable usar para el color de un píxel?

82

Veo muchos sombreadores de fragmentos diferentes,

#version 130

out vec4 flatColor;

void main(void)
{
    flatColor = vec4(0.0,1.0,0.0,0.5);
}

Y todos usan una variable diferente para el "color de salida" (en este caso flatColor). Entonces, ¿cómo sabe OpenGL lo que estás intentando hacer?

Supongo que esto funciona porque flatColores la única variable definida como out, pero puedes agregar más outvariables, ¿no? ¿O simplemente se estrellaría?


En realidad, como prueba, acabo de ejecutar esto:

#version 330

in vec2 TexCoord0;

uniform sampler2D TexSampler;

out vec4 x;
out vec4 y;

void main()
{
    y = texture2D(TexSampler, TexCoord0.xy);
}

Funcionó bien ya sea que use xo y.


Además, tenemos un archivo gl_FragColor. ¿Cuál es la diferencia y por qué la gente suele insistir en utilizar sus propias variables?

mpen
fuente

Respuestas:

142

Además, tenemos un gl_FragColor predefinido.

Empecemos por esto. No, no tienes el predefinido gl_FragColor. Eso se eliminó del núcleo de OpenGL 3.1 y superior. A menos que esté usando compatibilidad (en cuyo caso, sus sombreadores 3.30 deberían decir #version 330 compatibilityen la parte superior), nunca debe usar esto.

Ahora, volvamos a las salidas del sombreador de fragmentos definidos por el usuario. Pero primero, una breve analogía.

¿Recuerdas cómo, en los sombreadores de vértices, tienes entradas? Y estas entradas representan vértice índices de atributos, los números se pasan a glVertexAttribPointery glEnableVertexAttribArrayy así sucesivamente? Usted configura qué entrada extrae de qué atributo. En GLSL 3.30, usa esta sintaxis:

layout(location = 2) in color;

Esto establece que la colorentrada del sombreador de vértices provenga de la ubicación del atributo 2. Antes de 3.30 (o sin ARB_explicit_attrib_location), tendría que configurar esto explícitamente glBindAttrbLocationantes de vincular o consultar el programa para el índice de atributo con glGetAttribLocation. Si no proporciona explícitamente una ubicación de atributo, GLSL asignará una ubicación de manera arbitraria (es decir, de una manera definida por la implementación).

Configurarlo en el sombreador es casi siempre la mejor opción.

En cualquier caso, las salidas del sombreador de fragmentos funcionan casi exactamente de la misma manera. Los sombreadores de fragmentos pueden escribir en varios colores de salida , que a su vez se asignan a varios búferes en el búfer de marco . Por lo tanto, debe indicar qué salida va a qué color de salida de fragmento.

Este proceso comienza con el valor de ubicación de salida del fragmento. Está configurado de manera muy similar a las ubicaciones de entrada del sombreador de vértices:

layout(location = 1) out secColor;

También están las funciones API glBindFragDataLocationy glGetFragDataLocation, que son análogas a glBindAttribLocationy glGetAttribLocation.

Si no realiza ninguna asignación explícita, las implementaciones generalmente asignarán una de sus variables de salida a la ubicación 0. Sin embargo, el estándar OpenGL no requiere este comportamiento, por lo que tampoco debe depender de él.

Ahora, para ser justos, su programa debería haber fallado al vincular cuando utilizó dos salidas que no obtuvieron diferentes ubicaciones de salida. Lo que probablemente sucedió fue que su compilador optimizó el que no escribió, por lo que se olvidó de él cuando llegó el momento de verificar los errores del vinculador.

Nicol Bolas
fuente
4
Ojalá pudiera dar más de +1. Espectacular respuesta. Me preguntaba cómo funcionaban las ubicaciones de salida de fragmentos. :)
kevintodisco
Ahh ... ¿así que lo desaprobaron gl_FragColora favor de darle más flexibilidad para elegir en qué búfer escribir? Tiene sentido. ¡Gracias de nuevo!
mpen
3
@Mark: "Desaprovechamiento" significa que "aún puede usarlo, pero es posible que se elimine en versiones posteriores". "Eliminado" significa eliminado . Hay una diferencia. Lo que se marcó en desuso en GL 3.0 se eliminó en 3.1 (excepto por un par de cosas).
Nicol Bolas
3
@NicolBolas: "GL 3.3 y superior (eso es un cambio de versiones anteriores) los asignará a todos a la ubicación 0". Me pregunto dónde está garantizado esto por la especificación. 3.3 dice "Cuando un programa está vinculado, cualquier variable que varíe sin un enlace especificado [...] o establecido explícitamente dentro del texto del sombreador se vinculará automáticamente a los colores e índices de fragmentos por el GL. Todas estas asignaciones usarán índices de color de cero.". La última oración no está presente en 3.2. Sin embargo, el índice no se refiere al número de color, sino solo al índice de mezcla de fuente dual (que se agregó en 3.3).
derhass
1
Gracias @NicolBolas, ¡gran respuesta! Así que todavía no lo he entendido completamente, y solo quiero hacerlo "sin dudarlo". En nuestros sombreadores, siempre especificamos layout (location = 0) out vec4 outColorcuándo se dibuja en lo que está vinculado (la mayoría de las veces "la pantalla" y no un FBO). Entonces, de manera predeterminada, si no hemos vinculado un FBO (u otro búfer) usando glDrawBuffers, y lo especificamos location = 0, ¿siempre se dibujará correctamente en la pantalla?
AzP
9

Me gustaría especificar esto para OpenGLES 3.1 que usa el enlace GLSL_ES_3.10 :

§4.4.2

Si solo hay una salida [en el sombreador de fragmentos], no es necesario especificar la ubicación, en cuyo caso el valor predeterminado es cero.

Lorenzo Belli
fuente