Pregunta

Al renderizar una escena de polígonos texturizados, me gustaría ser capaz de cambiar entre la representación de los colores originales y un modo de "escala de grises". He estado tratando de lograr esto usando las operaciones de mezcla y el color de la matriz; Nada de eso funcionó (con la mezcla no pude encontrar un glBlendFunc () que logró algo remotamente parecido a lo que quería, y operaciones de la matriz de color ... se discuten aquí ).

Una solución que viene a la mente (pero también es bastante caro) es capturar la pantalla de cada cuadro y convertir la textura resultante a una escala de grises y mostrar que en vez ... (Donde dije en escala de grises que en realidad quería decir cualquier cosa con una baja saturación, pero supongo para la mayoría de las posibles soluciones que no diferirá mucho de todo lo que en escala de grises).

¿Qué otras opciones tengo?

¿Fue útil?

Solución

El uso de este dispositivo de OpenGL por defecto utiliza el espacio de color RGB, que no almacena una saturación explícita. Es necesario un enfoque para la extracción de la saturación, modificándolo, y cambiarlo de nuevo.

Mi sugerencia anterior, que simplemente utiliza la longitud del vector RGB para representar 0 en luminancia era incorrecto, ya que no tomó en cuenta la ampliación, me disculpo.

El crédito para el nuevo fragmento corto va al usuario regular "RTFM_FTW" de ## OpenGL y ## opengl3 en FreeNode / IRC, y que le permite modificar la saturación directamente sin computar el costoso RGB-> HSV-> conversión de RGB , que es exactamente lo que quiere. Aunque el código de HSV es inferior con respecto a su pregunta, dejar que se quede.

void main( void ) 
{ 
    vec3 R0 = texture2DRect( S, gl_TexCoord[0].st ).rgb;
    gl_FragColor = vec4( mix( vec3( dot( R0, vec3( 0.2125, 0.7154, 0.0721 ) ) ),
        R0, T ), gl_Color.a ); 
}

Si desea más control que sólo la saturación, es necesario convertir a HSL o HSV espacio de color. Como se muestra más abajo usando un shader fragmento GLSL.

Leer la especificación OpenGL 3.0 y GLSL 1.30 disponible en http://www.opengl.org/registry para aprender a utilizar la funcionalidad GLSL v1.30.

#version 130
#define RED 0
#define GREEN 1
#define BLUE 2

in vec4 vertexIn;
in vec4 colorIn;
in vec2 tcoordIn;
out vec4 pixel;
Sampler2D tex;
vec4 texel;
const float epsilon = 1e-6;

vec3 RGBtoHSV(vec3 color)
{
    /* hue, saturation and value are all in the range [0,1> here, as opposed to their
       normal ranges of: hue: [0,360>, sat: [0, 100] and value: [0, 256> */
    int sortindex[3] = {RED,GREEN,BLUE};
    float rgbArr[3] = float[3](color.r, color.g, color.b);

    float hue, saturation, value, diff;
    float minCol, maxCol;
    int minIndex, maxIndex;

    if(color.g < color.r)
        swap(sortindex[0], sortindex[1]);
    if(color.b < color.g)
        swap(sortindex[1], sortindex[2]);
    if(color.r < color.b)
        swap(sortindex[2], sortindex[0]);

    minIndex = sortindex[0];
    maxIndex = sortindex[2];
    minCol = rgbArr[minIndex];
    maxCol = rgbArr[maxIndex];

    diff = maxCol - minCol;

    /* Hue */
    if( diff < epsilon){
        hue = 0.0;
    }
    else if(maxIndex == RED){
        hue = ((1.0/6.0) * ( (color.g - color.b) / diff )) + 1.0;
        hue = fract(hue);
    }
    else if(maxIndex == GREEN){
        hue = ((1.0/6.0) * ( (color.b - color.r) / diff )) + (1.0/3.0);
    }
    else if(maxIndex == BLUE){
        hue = ((1.0/6.0) * ( (color.r - color.g) / diff )) + (2.0/3.0);        
    }

    /* Saturation */
    if(maxCol < epsilon)
        saturation = 0;
    else
        saturation = (maxCol - minCol) / maxCol;

    /* Value */
    value = maxCol;

    return vec3(hue, saturation, value);
}
vec3 HSVtoRGB(vec3 color)
{
    float f,p,q,t, hueRound;
    int hueIndex;
    float hue, saturation, value;
    vec3 result;

    /* just for clarity */
    hue = color.r;
    saturation = color.g;
    value = color.b;

    hueRound = floor(hue * 6.0);
    hueIndex = int(hueRound) % 6;
    f = (hue * 6.0) - hueRound;
    p = value * (1.0 - saturation);
    q = value * (1.0 - f*saturation);
    t = value * (1.0 - (1.0 - f)*saturation);

    switch(hueIndex)
    {
        case 0:
            result = vec3(value,t,p);
        break;
        case 1:
            result = vec3(q,value,p);
        break;
        case 2:
            result = vec3(p,value,t);
        break;
        case 3:
            result = vec3(p,q,value);
        break;
        case 4:
            result = vec3(t,p,value);
        break;
        default:
            result = vec3(value,p,q);
        break;
    }
    return result;
}
void main(void)
{
    vec4 srcColor;
    vec3 hsvColor;
    vec3 rgbColor;
    texel = Texture2D(tex, tcoordIn);
    srcColor = texel*colorIn;
    hsvColor = RGBtoHSV(srcColor.rgb);
    /* You can do further changes here, if you want. */
    hsvColor.g = 0; /* Set saturation to zero */
    rgbColor = HSVtoRGB(hsvColor);
    pixel = vec4(rgbColor.r, rgbColor.g, rgbColor.b, srcColor.a);
}

Otros consejos

Si está trabajando en contra de una moderna OpenGL-suficiente, diría shaders de píxeles es una solución muy adecuada aquí. Ya sea por enganchar en el sombreado de cada polígono, ya que hacen, o haciendo un solo cuádruple de pantalla completa en un segundo paso que acaba de leer cada píxel, convierte a escala de grises, y escribe de nuevo. A menos que su resolución, el hardware de gráficos, y la tasa de fotogramas de destino son de alguna manera "extrem", que debería ser factible en estos días en la mayoría de los casos.

Para la mayoría de sobremesa Render-A-textura no es tan caro más, todos compiz, aero, etc y efectos como la floración o la profundidad de campo visto en los últimos títulos dependen de él.

En realidad no convierte la textura pantalla de por sí a escala de grises, que se quiere dibujar un quad-pedregal tamaño con la textura y un shader fragmento de la transformación de los valures a escala de grises.

Otra opción es tener dos juegos de fragment shaders para sus triángulos, uno sólo copiar el atributo gl_FrontColor como el pieline función fija haría, y otro que escribe valores en escala de grises en el búfer de pantalla.

Una tercera opción podría ser indexado modos de color, si se establece Uup una paleta de escala de grises, pero que el modo podrían quedar obsoletas y mal apoyada por ahora; además se pierde una gran cantidad de funcionalidades como la mezcla, si no recuerdo mal.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top