Question

Lors du rendu d'une scène de polygones texturés, je voudrais être en mesure de basculer entre le rendu des couleurs d'origine et un mode « niveaux de gris ». J'ai essayé d'y parvenir à l'aide de mélange et les opérations de la matrice couleur; rien de tout cela a fonctionné (avec le mélange, je ne pouvais pas trouver un glBlendFunc () qui a réalisé quelque chose qui ressemble à distance à ce que je voulais, et les opérations de matrice couleur ... sont discutés ici ).

Une solution qui vient à l'esprit (mais est aussi assez cher) est de capturer l'écran chaque image et convertir la texture résultante à un niveau de gris et afficher qu'au lieu ... (Si je l'ai dit en niveaux de gris, je voulais dire quoi que ce soit avec un faible saturation, mais je devine pour la plupart des solutions possibles, il ne différera pas tant que ça de niveaux de gris).

Quelles autres options dois-je?

Était-ce utile?

La solution

Le framebuffer par défaut OpenGL utilise la couleur espace RVB, qui ne stocke pas une saturation explicite. Vous avez besoin d'une approche pour extraire la saturation, la modifier et de modifier à nouveau.

Ma suggestion précédente qui a simplement utilisé la longueur du vecteur RVB pour représenter 0 en luminance est incorrecte, car il n'a pas pris en compte l'échelle, je présente mes excuses.

Crédit pour le nouveau court extrait va à l'utilisateur régulier « RTFM_FTW » de ## et ## opengl opengl3 sur freenode / IRC, et il vous permet de modifier la saturation directement sans calculer la coûteuse RVB-> HSV-> conversion RVB , ce qui est exactement ce que vous voulez. Bien que le code HSV est inférieur par rapport à votre question, je l'ai laissé rester.

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 vous voulez plus de contrôle que juste la saturation, vous devez convertir en HSL ou espace couleur HSV. Comme indiqué ci-dessous en utilisant un fragment shader GLSL.

Lire la spécification disponible sur OpenGL 3.0 et GLSL 1.30 http://www.opengl.org/registry pour apprendre à utiliser la fonctionnalité de 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);
}

Autres conseils

Si vous travaillez contre OpenGL moderne assez, je dirais que pixel shaders est une solution très appropriée ici. Soit en accrochant dans chaque polygone de l'ombrage qu'ils rendent, ou en faisant un seul quad plein écran dans un second passage qui lit seulement chaque pixel, convertit en niveaux de gris, et l'écrit en arrière. À moins que votre résolution, matériel graphique et framerate cible sont en quelque sorte « extrem », qui devrait être réalisable ces jours-ci dans la plupart des cas.

Pour la plupart Desktops Render-To-texture est pas plus cher, tous Compiz, aéro, etc et des effets tels que la floraison ou la profondeur de champ vu dans les titres récents en dépendent.

En fait, vous ne convertissez pas la texture de l'écran en tant que telle en niveaux de gris, vous voulez dessiner un quad scree taille avec la texture et un fragment shader transformant les valures en niveaux de gris.

Une autre option est d'avoir deux ensembles de shaders de fragments pour vos triangles, une copie simplement l'attribut gl_FrontColor comme pieline fonction fixe serait, et une autre qui écrit des valeurs de niveaux de gris dans la mémoire tampon de l'écran.

Une troisième option peut être indexé modes de couleur, si vous définissez Uup une palette en niveaux de gris, mais ce mode peut être dépréciée et mal pris en charge maintenant; De plus, vous perdez beaucoup de fonctionnalités telles que le mélange, si je me souviens bien.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top