Frage

Beim Rendern einer Szene aus texturierten Polygonen möchte ich zwischen dem Rendern in den Originalfarben und einem „Graustufen“-Modus wechseln können.Ich habe versucht, dies mithilfe von Misch- und Farbmatrixoperationen zu erreichen.Nichts davon funktionierte (beim Mischen konnte ich kein glBlendFunc() finden, das etwas erreichte, das auch nur annähernd dem ähnelte, was ich wollte, und Farbmatrixoperationen ...werden hier besprochen).

Eine Lösung, die mir in den Sinn kommt (aber auch ziemlich teuer ist), besteht darin, jedes Bild des Bildschirms zu erfassen, die resultierende Textur in eine Graustufentextur umzuwandeln und diese stattdessen anzuzeigen ...(Wo ich Graustufen sagte, meinte ich eigentlich alles mit einer niedrigen Sättigung, aber ich vermute, dass es sich bei den meisten möglichen Lösungen nicht allzu sehr von Graustufen unterscheiden wird).

Welche anderen Optionen habe ich?

War es hilfreich?

Lösung

Der Standard-OpenGL-Framebuffer verwendet den RGB-Farbraum, der keine explizite Sättigung speichert. Sie benötigen einen Ansatz für die Sättigung zu extrahieren, zu modifizieren, und es wieder ändern zurück.

Mein früherer Vorschlag, der einfach die RGB-Vektorlänge verwendet, um für 0 in der Leuchtdichte nicht korrekt war, da sie nicht berücksichtigt hätten, Skalierung, ich entschuldige mich.

Kredit für den neuen kurzen Schnipsel geht an den normalen Benutzer „RTFM_FTW“ von ## opengl und ## opengl3 auf FreeNode / IRC, und es kann Sie die Sättigung ändern direkt ohne die teueren Rechen RGB-> HSV-> RGB-Konvertierung , das ist genau das, was Sie wollen. Obwohl der HSV-Code in Bezug auf Ihre Frage minderwertig ist, lasse ich es bleiben.

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

Wenn Sie mehr Kontrolle als nur die Sättigung, müssen Sie HSL oder HSV-Farbraum konvertieren. Wie unten gezeigt, indem ein GLSL Fragment-Shader verwendet wird.

Lesen Sie die OpenGL 3.0 und GLSL 1.30 Spezifikation auf http://www.opengl.org/registry lernen, wie GLSL v1.30 Funktion nutzen.

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

Andere Tipps

Wenn Sie sich gegen ein modern genug OpenGL arbeiten, würde ich sagen, Pixel-Shadern hier ist eine sehr geeignete Lösung. Entweder, indem sie in jedem Polygon Shading Einhaken wie sie machen, oder durch einen einzigen Vollbild-Quad in einem zweiten Durchgang zu tun, dass nur jedes Pixel liest, wandelt in Graustufen, und schreibt sie zurück. Es sei denn, Ihre Auflösung, Grafikhardware und Zielframerate ist irgendwie „extrem“, das sollte in diesen Tagen in den meisten Fällen machbar.

Für die meisten Desktops ist Render-To-Texture nicht mehr so ​​teuer, alle Compiz, Aero usw. und Effekte wie Bloom oder Tiefenschärfe, die in neueren Titeln zu sehen sind, hängen davon ab.

Eigentlich wandeln Sie die Bildschirmtextur nicht per se in Graustufen um, sondern zeichnen ein geröllgroßes Quad mit der Textur und einem Fragment-Shader, der die Werte in Graustufen umwandelt.

Eine andere Möglichkeit besteht darin, zwei Sätze von Fragment-Shadern für Ihre Dreiecke zu haben, einen, der nur das gl_FrontColor-Attribut kopiert, wie es die Pieline mit fester Funktion tun würde, und einen anderen, der Graustufenwerte in den Bildschirmpuffer schreibt.

Eine dritte Option könnten indizierte Farbmodi sein, wenn Sie eine Graustufenpalette festlegen. Dieser Modus ist jedoch möglicherweise veraltet und wird derzeit nur unzureichend unterstützt.Außerdem gehen viele Funktionen wie das Mischen verloren, wenn ich mich richtig erinnere.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top