CGA-Shader
CGA (Color Graphics Adapter) wurde 1981 eingeführt und war die erste Farbgrafikkarte von IBM für den IBM PC, die einen De-facto-Standard für Computerbildschirme etablierte. Je nach Auflösung können 4 bis 16 Farben angezeigt werden. Im folgenden Beispiel habe ich mich auf acht Farben beschränkt, ihr könnt es aber gerne erweitern oder auf vier Farben reduzieren.
Zur Erinnerung: Bei den Post-Processing-Effekten arbeiten wir nur mit dem Fragment-Shader. Hier der Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
varying vec2 v_vTexcoord; varying vec4 v_vColour; void main() { vec4 col = texture2D(gm_BaseTexture, v_vTexcoord); // Konvertiere die Farbe in CGA-Farben vec4 cga_col; if (col.r < 0.5 && col.g < 0.5 && col.b < 0.5) { cga_col = vec4(0.0, 0.0, 0.0, 1.0); // Schwarz } else if (col.r >= 0.5 && col.g < 0.5 && col.b < 0.5) { cga_col = vec4(0.0, 1.0, 1.0, 1.0); // Cyan } else if (col.r < 0.5 && col.g >= 0.5 && col.b < 0.5) { cga_col = vec4(1.0, 0.0, 1.0, 1.0); // Magenta } else if (col.r >= 0.5 && col.g >= 0.5 && col.b < 0.5) { cga_col = vec4(1.0, 1.0, 0.0, 1.0); // Gelb } else if (col.r < 0.5 && col.g < 0.5 && col.b >= 0.5) { cga_col = vec4(0.0, 0.0, 1.0, 1.0); // Dunkelblau } else if (col.r >= 0.5 && col.g < 0.5 && col.b >= 0.5) { cga_col = vec4(1.0, 0.0, 1.0, 1.0); // Hellblau } else if (col.r < 0.5 && col.g >= 0.5 && col.b >= 0.5) { cga_col = vec4(0.0, 1.0, 0.0, 1.0); // Grün } else if (col.r >= 0.5 && col.g >= 0.5 && col.b >= 0.5) { cga_col = vec4(1.0, 1.0, 1.0, 1.0); // Weiß } gl_FragColor = cga_col; } |
Dieser Shader konvertiert jede Farbe in eine der acht Farben, basierend auf der Farbzusammensetzung von Rot, Grün und Blau. Wenn die Farbe nicht genau einer der CGA-Farben entspricht, wird sie auf die am nächsten liegende CGA-Farbe abgebildet.
Sowohl Create- wie auch Draw-GUI-Event entsprechen der o. g. Vorlage. Ihr müsst lediglich den Namen des Shaders austauschen.
Pixel-Shader
Wir wollen den Bildschirm verpixelt anzeigen? Kein Problem.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
varying vec2 v_vTexcoord; varying vec4 v_vColour; uniform vec2 resolution; uniform float pixelSize; void main() { vec2 uv = gl_FragCoord.xy / resolution.xy; // Normierte Texturkoordinaten für den aktuellen Fragment-Pixel vec2 pixelSizeUV = vec2(pixelSize) / resolution.xy; // Normierte Pixelgröße für den Retro-Pixel-Look vec2 roundedUV = floor(uv / pixelSizeUV) * pixelSizeUV * 0.5; // Berechnung der gerundeten Texturkoordinaten für das Retro-Pixel-Raster vec4 col = texture2D(gm_BaseTexture, roundedUV); // Textur-Farbwert für die gerundeten Texturkoordinaten gl_FragColor = col; // Ausgabe der Texturfarbe für das aktuelle Fragment-Pixel } |
Hier werden in main()
die normierten Texturkoordinaten uv
für das aktuelle Fragment-Pixel sowie die normierte Pixelgröße pixelSizeUV
berechnet. Dann werden die gerundeten Texturkoordinaten roundedUV
für das Retro-Pixel-Raster ermittelt. Schließlich wird der Textur-Farbwert col
für die gerundeten Texturkoordinaten berechnet und als Farbausgabe für das aktuelle Fragment-Pixel verwendet.
Pixel-Shader von Set 1. Irgendwann erkennt man nichts mehr.
Da wir die Variablen pixelSize
und resolution
haben, müssen wir unsere Events noch anpassen.
Create-Event
1 2 3 |
uni_pixelate = shader_get_uniform(sh_pixelate, "pixelSize"); uni_resolution = shader_get_uniform(sh_pixelate, "resolution"); val_pixelate = 8; |
Wir beginnen mit einem Wert von 8. Wie bereits beschrieben, kann man den perfekten Wert bspw. per Mausrad ermitteln.
Beim zweiten Set ist die Grafik ohnehin schon sehr feingranular
Draw GUI
1 2 3 4 5 6 7 8 |
if (shader_is_compiled(sh_pixelate)) { shader_set(sh_pixelate); shader_set_uniform_f(uni_pixelate, val_pixelate); shader_set_uniform_f(uni_resolution,resX, resY); draw_surface(surf, 0, 0); shader_reset(); } |