Hey! May be it will be interesting. I started to play in PS1 and got extremely bad graphics, and found that there is no shader/filtering solution
So, I created my using previous shader, I hope it will be useful, you could use some idea or part of code
The problem in emulation of CRT platforms - actually graphics looks more natural on CRT tv cause there is some analog noise. Also, CRT and LCD colors are different, different brighness levels and CRT 0-255 is not equal to LCD 0-255, on LCD black is very black and white is very white. Also, you could use blur + noise to emulate CRT,
Difference from real life
Window is too bright
Screenshots comparison
You can tune this shader for you purposes. Also, OpenGL2 does not have time variable so you cant create eternal good noise, but you could create noise using pixel coordinates. I added colors after
LITTLE text coordinate color correction and if color on some position changes, noise changes
You could change some values for platform to reduce/increase blur level
gpuPeteOGL2.slf
Code:
//patched by Danila Zabiaka - white black noise
#define white 236.0
#define black 20.0
#define noise 15.0
#define offset -25.0
#define red -0.0
#define green -0.0
#define blue -0.2
#define satoffset 5.0 //5 as start point. sat=satoffset-5.0, 6 means 1.1
float pseudoNoise(vec2 co)
{
return fract(sin(dot(vec2(co.x+0.513,co.y+0.4124) ,vec2(12.9898,78.233))) * 43758.5453);// *fract(sin(dot(vec2(co.x+4.231,co.y+3.143) ,vec2(12.9898,78.233)*2.0)) * 43758.5453); //pseudo random number generator
}
vec3 czm_saturation(vec3 rgb, float adjustment)
{
// Algorithm from Chapter 16 of OpenGL Shading Language
const vec3 W = vec3(0.2125, 0.7154, 0.0721);
vec3 intensity = vec3(dot(rgb, W));
return mix(intensity, rgb, adjustment);
}
uniform sampler2D OGL2Texture;
const vec3 RGBtoY = vec3(0.299, 0.587, 0.114);
const vec3 RGBtoI = vec3(0.596,-0.275,-0.321);
const vec3 RGBtoQ = vec3(0.212,-0.523, 0.311);
const vec3 YIQtoR = vec3(1.0, 0.95568806036115671171, 0.61985809445637075388);
const vec3 YIQtoG = vec3(1.0,-0.27158179694405859326,-0.64687381613840131330);
const vec3 YIQtoB = vec3(1.0,-1.10817732668266195230, 1.70506455991918171490);
void main()
{
vec3 c0, c1;
c0 = (texture2D(OGL2Texture,gl_TexCoord[0].xy).rgb +
(texture2D(OGL2Texture,gl_TexCoord[0].zy).rgb) * 0.25 +
(texture2D(OGL2Texture,gl_TexCoord[0].xw).rgb) * 0.25 +
texture2D(OGL2Texture,gl_TexCoord[1].xy).rgb +
(texture2D(OGL2Texture,gl_TexCoord[1].zy).rgb) * 0.25 +
(texture2D(OGL2Texture,gl_TexCoord[1].xw).rgb) * 0.25 +
texture2D(OGL2Texture,gl_TexCoord[2].xy).rgb +
(texture2D(OGL2Texture,gl_TexCoord[2].zy).rgb) * 0.25 +
(texture2D(OGL2Texture,gl_TexCoord[2].xw).rgb) * 0.25 +
texture2D(OGL2Texture,gl_TexCoord[3].xy).rgb +
(texture2D(OGL2Texture,gl_TexCoord[3].zy).rgb) * 0.25 +
(texture2D(OGL2Texture,gl_TexCoord[3].xw).rgb) * 0.25 ) / 6.0;
c1 = vec3(pow(dot(c0, RGBtoY), 1.2), dot(c0, RGBtoI) * 1.2, dot(c0, RGBtoQ) * 1.2);
gl_FragColor = vec4(dot(c1, YIQtoR), dot(c1, YIQtoG), dot(c1, YIQtoB), 0.0);
gl_FragColor.xyz = czm_saturation(gl_FragColor.xyz, 1.0+(satoffset-5.0)/10.0);
gl_FragColor = gl_FragColor *white/255.0+black/255.0-gl_FragColor*black/255.0 +(pseudoNoise(gl_TexCoord[0].xy))*1.0/255.0;
gl_FragColor = gl_FragColor +(pseudoNoise(vec2(gl_FragColor.x+gl_FragColor.z,gl_FragColor.y+gl_FragColor.z))-0.5)*noise/255.0;
// gl_FragColor = gl_FragColor +(pseudoNoise(vec2(gl_FragColor.x,gl_FragColor.x))-0.5)*noise/255.0;
gl_FragColor.x = gl_FragColor.x*(1.0+red);
gl_FragColor.y=gl_FragColor.y*(1.0+green);
gl_FragColor.z=gl_FragColor.z*(1.0+blue);
}
And gpuPeteOGL2.slv
Code:
uniform vec4 OGL2Param;
#define soffset 0.00031
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0]=gl_MultiTexCoord0.xyxy+vec4(-0.5,-0.5,-1.5,-1.5) * (OGL2Param.xyxy+soffset);
gl_TexCoord[1]=gl_MultiTexCoord0.xyxy+vec4( 0.5,-0.5, 1.5,-1.5) * (OGL2Param.xyxy+soffset);
gl_TexCoord[2]=gl_MultiTexCoord0.xyxy+vec4(-0.5, 0.5,-1.5, 1.5) * (OGL2Param.xyxy+soffset);
gl_TexCoord[3]=gl_MultiTexCoord0.xyxy+vec4( 0.5, 0.5, 1.5, 1.5) * (OGL2Param.xyxy+soffset);
}
^_^