Domanda

Quando il rendering di una scena di poligoni con texture, mi piacerebbe essere in grado di passare tra il rendering nei colori originali e una modalità "scala di grigi". Ho cercato di ottenere questo utilizzando le operazioni di fusione e di matrice di colore; niente di tutto ciò ha funzionato (con la miscelazione non ho potuto trovare un glBlendFunc (), che ha raggiunto qualcosa di lontanamente simile a quello che volevo, e le operazioni di matrice colore ... sono discussi qui ).

Una soluzione che viene in mente (ma è anche piuttosto costoso) è quello di catturare la schermata di ogni fotogramma e convertire la texture risultante a uno in scala di grigi e visualizzare che invece ... (Dove ho detto in scala di grigi che in realtà dire nulla con un bassa saturazione, ma sto cercando di indovinare per la maggior parte delle possibili soluzioni che non differirà più di tanto dalla scala di grigi).

Quali altre opzioni ho?

È stato utile?

Soluzione

Il framebuffer predefinita OpenGL utilizza lo spazio colore RGB, che non memorizza una saturazione esplicito. Avete bisogno di un approccio per estrarre la saturazione, modificandolo, e cambiare di nuovo.

Il mio suggerimento precedente che ha usato semplicemente la lunghezza del vettore RGB per rappresentare 0 di luminosità è stato corretto, in quanto non ha preso in considerazione il ridimensionamento, mi scuso.

Credito per il nuovo breve frammento va per l'utente normale "RTFM_FTW" dal ## OpenGL e ## opengl3 su FreeNode / IRC, e consente di modificare la saturazione direttamente senza calcolare la costosa RGB-> HSV> conversione RGB , che è esattamente quello che vuoi. Anche se il codice HSV è inferiore rispetto alla tua domanda, ho lasciato stare.

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

Se si desidera un maggiore controllo non solo la saturazione, è necessario convertire a HSL o HSV spazio colore. Come mostrato di seguito utilizzando uno shader frammento GLSL.

Leggi le specifiche OpenGL 3.0 e GLSL 1.30 disponibile su http://www.opengl.org/registry per imparare a utilizzare la funzionalità 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);
}

Altri suggerimenti

Se si sta lavorando contro un'OpenGL moderno-abbastanza, direi shader pixel è una soluzione molto adatto qui. Sia agganciando in ombreggiatura di ogni poligono come rendono, o facendo un singolo quad a schermo intero in un secondo passaggio che legge semplicemente ogni pixel, converte in scala di grigi, e lo scrive indietro. A meno che la risoluzione, hardware grafico, e framerate di destinazione sono in qualche modo "Extrem", che dovrebbe essere fattibile in questi giorni nella maggior parte dei casi.

Per la maggior parte dei desktop render-to-texture non è costoso più, tutti compiz, aero, ecc e effetti come fioritura o la profondità di campo visto negli ultimi titoli da esso dipendono.

In realtà non si converte la consistenza schermo per sé in scala di grigi, si vorrebbe disegnare un quad ghiaioni dimensioni con la texture e shader frammento trasformare le valures in scala di grigi.

Un'altra opzione è quella di avere due set di shader frammento per i vostri triangoli, uno semplicemente copiando l'attributo gl_FrontColor come pieline funzione fissa sarebbe, e un altro che scrive i valori in scala di grigi per il buffer dello schermo.

Una terza opzione potrebbe essere indicizzato modalità colore, se si imposta UUP una tavolozza in scala di grigi, ma che la modalità potrebbe essere deprecato e mal supportato da ora; più si perde un sacco di funzionalità come la miscelazione, se non ricordo male.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top