2010-04-29 8 views
29

Estoy tratando de entender los sombreadores en GLSL, y he encontrado algunos recursos útiles y tutoriales, pero sigo corriendo hacia una pared por algo que debería ser fundamental y trivial: ¿cómo recupera mi sombreador de fragmentos el color del fragmento actual?¿Cómo obtengo el color actual de un fragmento?

Establece el color final diciendo gl_FragColor = whatever, pero aparentemente es un valor de solo salida. ¿Cómo se obtiene el color original de la entrada para que pueda realizar cálculos sobre ella? Eso tiene que ser una variable en alguna parte, pero si alguien conoce su nombre, parece que no lo han grabado en ningún tutorial o documentación con la que haya tropezado hasta ahora, y eso me está volviendo loco.

+0

"Color original de la entrada": ¿se refiere a las propiedades del material asignadas a su fragmento (textura, color difuso ...)? – DamienD

Respuesta

14

El sombreador de fragmentos recibe gl_Color y gl_SecondaryColor como atributos de vértice. También obtiene cuatro variables variables: gl_FrontColor, gl_FrontSecondaryColor, gl_BackColor y gl_BackSecondaryColor a las que puede escribir valores. Si desea pasar los colores originales directamente a través de, usted haría algo como:

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

funcionalidad fija en la tubería tras el vertex shader luego sujetar estos para el rango [0..1], y la figura si el vértice está orientado hacia el frente o hacia atrás. Luego, interpolará el color elegido (frontal o posterior) como siempre. El sombreador de fragmentos recibirá entonces los colores elegidos, pinzados e interpolados como gl_Color y gl_SecondaryColor.

Por ejemplo, si se dibujara el estándar "triángulo de la muerte" como:

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(); 

A continuación, un vertex shader así:

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

con un fragment shader así:

void main() { 
    gl_FragColor = gl_Color; 
} 

transmitirá los colores, como si estuviera utilizando la tubería de funcionalidad fija.

+25

La mayoría de todo lo que hace está en desuso después de la versión 120. De hecho, no solo las advertencias, sino también los errores. Tampoco funcionará con OpenGL ES 2.0 (también desaparecerá en 4.x?) – user697111

3

El punto entero de su sombreador de fragmentos es decidir cuál es el color de salida. Cómo lo haces depende de lo que estás tratando de hacer.

Puede optar por configurar las cosas para que obtenga un color interpolado basado en la salida del sombreador de vértices, pero un enfoque más común sería realizar una búsqueda de textura en el sombreador de fragmentos utilizando coordenadas de textura pasadas en el vertex shader interpolants. Luego modificaría el resultado de la búsqueda de textura de acuerdo con los cálculos de iluminación elegidos y cualquier otra cosa que su sombreador debe hacer y luego lo escribirá en gl_FragColor.

6

Si lo que está llamando "valor actual del fragmento" es el valor del color del píxel que estaba en el destino del renderizado antes de que se ejecute el sombreador de fragmentos, entonces no, no está disponible.

La razón principal de esto es que potencialmente, en el momento en que se ejecuta el sombreador de fragmentos, aún no se conoce. Los sombreadores de fragmentos se ejecutan en paralelo, potencialmente (dependiendo de qué hardware) afectan al mismo píxel, y un bloque separado, leyendo de algún tipo de FIFO, generalmente es responsable de combinarlos más adelante. Esa fusión se llama "Mezcla", y aún no es parte de la tubería programable. Es una función fija, pero tiene varias formas diferentes de combinar lo que generó el sombreador de fragmentos con el valor de color anterior del píxel.

12

Si desea hacer el procesamiento de pasadas múltiples, es decir,si ha prestado al uso de este dispositivo y quieren a un segundo paso hacer que el que utiliza la prestación anterior que la respuesta es:

  1. Render la primera pasada a una textura
  2. Enlazar esta textura para el segundo pase
  3. acceso al píxel privously dictada en el shader

código para Shader 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 ... 
} 

Otro método para procesar una imagen renderizada sería OpenCL con OpenGL -> OpenCL interoperabilidad. Esto permite más CPU como cálculo.

4

Es necesario muestrear la textura en las coordenadas de píxeles actuales, algo como esto

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

Nota, - como he visto Texture2D está en desuso en GLSL 4.00 especificaciones - sólo tiene que buscar textura similar ... ir a buscar funciones .

También a veces es mejor proporcionar su propia coordenadas de píxeles en lugar de gl_TexCoord [0] .XY - en caso de que el vértice de escritura shader algo como:

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);  
}

y en uso de sombreado fragmento de esa variable en lugar de TexCoord gl_TexCoord [0] .xy.

Buena suerte.

-3

cómo-do-i-conseguir-la-corriente color-of-a-fragmento

Algunos dicen que no se puede hacer, pero me dicen que esto funciona para mí:

//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); 
} 

Después de esa llamada, gl_FragColor igualará el color claro del búfer de color la primera vez que el sombreador se ejecuta en cada píxel, y la salida de cada ejecución será la nueva entrada en cada ejecución sucesiva.

Bueno, al menos funciona para mí.

+5

-1: Para "me funciona" no tiene sentido sin siquiera molestarse en decir qué hardware realmente está usando. Además, para endosar un comportamiento indefinido sin molestarse en decir qué hardware estás usando, hace esto. –

1

La tubería de GPU tiene acceso a la información de píxeles subyacente inmediatamente después de se ejecutan los sombreadores. Si su material es transparente, la etapa de fusión de la tubería combinará todos los fragmentos.

Generalmente los objetos se mezclan en el orden en que se agregan a una escena, a menos que hayan sido ordenados por un z-buffering algo. Primero debe agregar sus objetos opacos, luego agregue cuidadosamente sus objetos transparentes en el orden en que se mezclarán.

Por ejemplo, si desea una superposición de HUD en su escena, debe simplemente crear un cuadrante de pantalla con una textura transparente adecuada y agregarlo a su escena al final.

La configuración de las funciones de fusión SRC y DST para objetos transparentes le da acceso a la combinación anterior de muchas maneras diferentes.

Puede usar la propiedad alfa del color de salida aquí para crear una mezcla realmente elegante. Esta es la forma más eficiente de acceder a las salidas del framebuffer (píxeles), ya que funciona en una sola pasada (Fig. 1) de la tubería de la GPU.

enter image description here
Fig. 1 - de una sola pasada

Si realmente necesita multi pass (Fig. 2), entonces usted debe dirigirse a las salidas de framebuffer a una unidad de textura adicional en lugar de la pantalla, y copie esta textura objetivo en la próxima pasada, y así sucesivamente, apuntando a la pantalla en el pase final. Cada pase requiere al menos dos conmutadores de contexto.

La copia adicional y la conmutación de contexto degradarán severamente el rendimiento de la representación. Tenga en cuenta que las tuberías de GPU de subprocesos múltiples no son de mucha ayuda aquí, ya que el paso múltiple se serializa intrínsecamente.

enter image description here
Fig. 2 - Multi Pass

he recurrido a una descripción verbal con los diagramas de tuberías para evitar la desaprobación, ya que el lenguaje de sombreado (argot/GLSL) está sujeta a cambios.

Cuestiones relacionadas