ich versuche gerade für ein Open Source Projekt einen Effektfilter zu schreiben und Delphi schmeisst da ein paar kleinere Steine in den Weg. Das kleinere Problem ist, die Anzeige unter Windows zu Testzwecken auf DX9 zu stellen. Dafür musste ich in FMX.Context.DX11 die RegisterContext Funktion deaktivieren. Da es nur zum Testen des Shaders ist, ist das okay. Leider gibt es keinen anderen Weg das zu realisieren, denn GlobalUseDXInDX9Mode ist dafür nicht angedacht.
Mit der Hilfe von Zudomon habe ich gestern einen Pixelshader für ps_2_a (DX9) erstellt.
// sRGB to Linear.
// Assuing using sRGB typed textures this should not be needed.
float ToLinear1(float c){return(c<=0.04045)?c/12.92:pow(abs((c+0.055)/1.055),2.4);}
float3 ToLinear(float3 c){return float3(ToLinear1(c.r),ToLinear1(c.g),ToLinear1(c.b));}
// Linear to sRGB.
// Assuing using sRGB typed textures this should not be needed.
float ToSrgb1(float c){return(c<0.0031308?c*12.92:1.055*pow(abs(c),0.41666)-0.055);}
float3 ToSrgb(float3 c){return float3(ToSrgb1(c.r),ToSrgb1(c.g),ToSrgb1(c.b));}
// Nearest emulated sample given floating point position and texel offset.
// Also zero's off screen.
float3 Fetch(float2 pos,float2 off){
//pos=(floor(pos*screen_size+off)+float2(0.5,0.5))/screen_size;
if (max(abs(pos.x-0.5), abs(pos.y-0.5)) > 0.5) { return float3(0.0, 0.0, 0.0);}
return ToLinear(1.2 * tex2D(s0,pos).rgb);}
// Distortion of scanlines, and end of screen alpha.
float2 Warp(float2 pos){
pos=pos*2.0-1.0;
pos*=float2(1.0+(pos.y*pos.y)*warp.x,1.0+(pos.x*pos.x)*warp.y);
return pos*0.5+0.5;}
Dieser basiert auf Lottes GLSL CRT Pixelfilter und die Idee ist dabei eine CRT Anzeige zu simulieren. Das ganze funktioniert zumindest mit DX9 recht gut. Ich kann die Werte für den Shader übergeben und er stellt das ganze auch (siehe Anhang) korrektet dar.
// sRGB to Linear.
// Assuing using sRGB typed textures this should not be needed.
float ToLinear1(float c){return(c<=0.04045)?c/12.92:pow(abs((c+0.055)/1.055),2.4);}
float3 ToLinear(float3 c){return float3(ToLinear1(c.r),ToLinear1(c.g),ToLinear1(c.b));}
// Linear to sRGB.
// Assuing using sRGB typed textures this should not be needed.
float ToSrgb1(float c){return(c<0.0031308?c*12.92:1.055*pow(abs(c),0.41666)-0.055);}
float3 ToSrgb(float3 c){return float3(ToSrgb1(c.r),ToSrgb1(c.g),ToSrgb1(c.b));}
// Nearest emulated sample given floating point position and texel offset.
// Also zero's off screen.
float3 Fetch(float2 pos,float2 off){
//pos=(floor(pos*screen_size+off)+float2(0.5,0.5))/screen_size;
if (max(abs(pos.x-0.5), abs(pos.y-0.5)) > 0.5) { return float3(0.0, 0.0, 0.0);}
return ToLinear(1.2 * GTexture.Sample(s0,pos).rgb);}
// Distortion of scanlines, and end of screen alpha.
float2 Warp(float2 pos){
pos=pos*2.0-1.0;
pos*=float2(1.0+(pos.y*pos.y)*warp.x,1.0+(pos.x*pos.x)*warp.y);
return pos*0.5+0.5;}
Nachtrag: Der Shader oben scheint zu gehen, aber die Werte in dem Register sind alle 0.
Ich übergebe bei DX9 die Werte so:
[TContextShaderVariable.Create('Input', TContextShaderVariableKind.Texture, 0, 0),
TContextShaderVariable.Create('C0', TContextShaderVariableKind.Float, 0, 1),
TContextShaderVariable.Create('C1', TContextShaderVariableKind.Float, 1, 1)]
und genauso bei DX11. Das scheint aber nicht ganz korrekt, zumindest glaube ich das.
Ist auch nicht korrekt:
, [TContextShaderVariable.Create('Input', TContextShaderVariableKind.Texture, 0, 0),
TContextShaderVariable.Create('C0', TContextShaderVariableKind.Float, 0, 16),
TContextShaderVariable.Create('C1', TContextShaderVariableKind.Float, 16, 16)]
),
Damit gehts
Geändert von CHackbart (23. Mai 2018 um 13:06 Uhr)
Anbei mal der komplette Quellcode des Projekts. Die DX9 und DX11 Pixelshader funktionieren in Kombination mit dem TCRTFilter. Einfach den Effekt einem FMX Objekt zuweisen und schon wird die Anzeige "aufgehübscht".
Was aber nicht funktioniert ist, die Übergabe der Parameter an den GLSL Shader. Wenn ich die Werte in den GLSL Pixelshader manuell eintrage, erscheint auch ein Bild unter Mac, aber irgend etwas funktioniert bei der Übergabe der Variablen nicht richtig.
Vielleicht hat ja jemand eine Idee?
Wie gesagt unter Windows läuft der Filter prima. Wäre halt auch schon, wenn er unter OSX ebenso Gänge.
Christian
PS: Der beiliegende Quellcode ist public domain.
Sorry das ich mich so spät erst zurück melde und Super das Du es geschafft hast, das freut mich sehr! Ich schnupper da doch glatt mal rein und schau mir die Aufhübschung aus der Nähe an
edit
Wenn Dein Shader aus einem klaren Bild eine Art Arcade-Bild herstellen sollte, mit gebogenem Display und dunkle Scanlines, Hut ab, perfekt umgesetzt!
Ja das geht mittlerweile sogar richtig gut. Ich habe noch eine TMaterialSource Klasse erstellt, damit man das auch auf einem 3d Objekt nutzen kann. Das Problem übrigens war, dass ich Float benutzt habe, richtig ist aber TContextShaderVariableKind.Matrix, dann klappt es auch unter GLSL.
Anbei mal der "finale" Code des Effektfilters. Das ganze sieht nach mehr aus, als es ist. Der Großteil ist dem Pixelshader -> Array of Byte Code geschuldet.
Geändert von CHackbart (23. Mai 2018 um 20:49 Uhr)
Falls Du etwas in Richtung Spiele machen möchtest, ich bin gerade dabei mir das DelphiArcadeGames Beispiel-Paket zu laden, soll wohl FMX für alle OS sein. Vielleicht ist ja was brauchbares dabei?! Ich schau es mir jedenfalls mal an.
Für Spiele ist der nicht gedacht. Vor knapp 20 Jahren (junge bin ich alt), habe ich einen ZX Spectrum Emulator für DOS geschrieben. Den gibt es im Quellcode noch irgendwo unter worldofspectrum.org oder zophar.net.
Vor einiger Zeit wollte ich den Code portieren und unter MacOS bzw. iOS und Android zum laufen kriegen. Nun schaut ein 320x256 Bild etwas komisch auf einem 4k Display aus und da lag es nahe die Anzeige aufzuhübschen.
Ich habe jetzt einen eigenen Shader erstellt der auf allen Plattformen läuft und ziemlich genügsam ist. Auf dem Mac schaut da so aus, wie im Anhang.
Christian
PS: Aber du kannst da natürlich den Effekt auch für Arcade-Spiele nutzen.