Please show off what crt shaders can do!

Here’s one with mask on white areas,but picture is so dark https://pasteboard.co/IKQrtja.png

yes 1.0 for min and max scanlines beam values will do the job,but whites areas are darker unfortunately,that’s why i’m using aperture

1 Like

I’d leave those alone because it seems to do weird stuff to color when I mess with those; scanline_shape adjusts the minimum thickness.

If you check out CRT-Aperture without the reshade shader and set mask strength to 100 and use the same settings for everything else, you’ll see it’s nowhere near as dark. This shot also shows what the phosphors should look like at different intensities:

same thing in fake4K:

Should be bright enough if you max out the backlight.

EDIT: actually the two images (the one you posted and the fake4K one) are similar in overall brightness. The difference is that the highlights / bright phosphors are more intense with CRT-Aperture’s method. This more closely resembles what an actual CRT does.

If that’s the magenta checkerboard, I don’t hate it at that lower TVL (still not the biggest fan of it, but it looks marginally better. To me at least, still on mobile. XD)

It’s the magenta/green aperture grille… and it has to be viewed at correct scale or it will look terrible and not have the intended effect at all.

edit: ideally you’d be viewing this on a 4k display so that the mask maps to the subpixels correctly. Otherwise, there’s a shot I posted above that can be viewed correctly on a 1080p display.

1 Like

Ohh, and I completely understand what you’re saying but I’m not looking at the image as a whole for this opinion that I have, I’m zooming in to look at the phosphors (like a macro shot?). I do this whenever anyone posts screens on here, I’m just not a fan of how it looks close up (which would be an issue for me as I have a 32 inch screen that I view from about 4 - 4 1/2 feet away, and I can see Lottes/guests masks pretty noticeable at higher settings from this distance). This is my personal opinion that I’ve made by looking at it via mobile haven’t tried it on my computer yet but I will before I continue to complain about it anymore.

The magenta/green masks won’t work right at all unless viewed at the right resolution and scale.

The reason for using magenta/green is detailed in cgwg’s excellent write-up here.

The Lottes masks don’t take into account the LCD subpixel structure so the LCD subpixels wind up being spaced unevenly. This causes blue to be washed out(?) by red and it all turns into magenta/green (you can see this in a macro shot). The magenta/green mask keeps the LCD subpixels evenly spaced so blue doesn’t get washed out and it actually looks like RGB in a macro shot. It’s also closer to how a CRT actually works.

A bit of pixel bleed in the second shot. Also the scanlines look a bit wacky due to the aforementioned TN panel inversion artifacts. Second shot shows the colors more accurately (looks better the closer you get to normal viewing distance)

Just want to explain some later changes to crt-guest-dr-venom, more precisely scanline spike mitigation. It’s already working with the GLSL version and i’ll see what can be done with the slang one.

I think it looks much better now with scanline type 1&2.

Old behaviour can be achieved with setting the “Scanline Spike Removal” parameter to low values.

Cheers!

9 Likes

Could you explain the update a little? Mainly because viewing the image via mobile the only real difference I noticed is that the spike mitigation image was (softer?) at least that’s what I was seeing, at least mainly around (higher contrast?) areas I guess, I noticed it really well on black and white areas, wasn’t super noticeable in the face image but in the space invaders it was really visible in my opinion. You could also see it (slightly?) with the red lines, it had some interesting effects on the multi-color thing in the space invaders area, and its fairly noticeable in the text.

1 Like

Gaussian scanlines have some issues with stronger scanlines, for example “bright scanline spikes” happen when the horizontal sharpness is at preferred medium values.

Once you see it in action/PC screen it get’s quite obvious.

It was on my TODO/FIX list quite some time, it was annoying for me especially with games that use black backgrounds.

In general it should work out very well, since the solution works with different horizontal sharpness levels, maybe some substractive sharpness (like the default 0.05) should be used to avoid some situations.

Ofc., if it’s not so likeable, old behaviour can be used. :grin:

4 Likes

Honestly it’s pretty noticeable on mobile except that face lol. Haven’t tested on PC yet but I do enjoy the new look, kind of seems like another sharpness setting imo. It’s cool that it’s adjustable though.

Does it have any impact on performance or is the difference basically non-existent (basically just as fast, lol)?

It’s cool that the shader is still getting updates, do you have any other things on your to-do list(I understand that you’re busy and they wouldn’t be done in the immediate future)?

1 Like

The performance hit is a couple of %, nothing to worry about. There is still the fast version, which won’t get such updates.

About my further plans, maybe some day HDR support will be added, but the ways to use this technology properly are still quite unclear and maybe i’ll need some help/inspiration too.

Otherwise there is still room for a mask or a cool scanline function, but thats rather an exceptional turn of events and will be implemented only if turns out very cool and benefiting.

2 Likes
1 Like

Here’s an actual macro shot of a CRT. I think you’ll agree that it looks very similar to the shot I posted above, although that shot kind of resembles a cross between the aperture grille and slotmask examples in the link below, due to the lower TVL of the slotmask.

You can’t get results this accurate without the magenta/green masks; blue and red will turn into magenta when you try to take a macro shot (blue won’t be strong enough).

Here are some more macro shots for reference:

2 Likes

Hey @BlockABoots I haven’t posted the new version of the bezel reflection yet, but it’s coming this weekend :slight_smile:

4 Likes

This would be a breakthrough for CRT emulation. As of right now, no currently available display is bright enough to do full-strength masks and scanlines AND black frame insertion, so you’re always compromising on one thing or another. If we can fake SDR content as HDR content then we’d have all the brightness we need for all the CRT effects. No one seems to know how to make this work, though. Maybe a bounty is in order…

If you want to maintain CRT-like brightness, you need a minimum of 800 nits if you want BFI @ 120 Hz and full strength mask and scanlines- that would leave you with about 100 nits. If you want to do the slotmask, you need to start with 1600 nits(!), so that might still be out of reach for even the brightest displays currently available. You’d have to reduce the slotmask strength while using BFI and scanlines.

2 Likes

Fragment program for pre-bloom processing

uniform float Exposure;
 uniform sampler2D SrcColor;
 uniform sampler2D SrcHDR;
 
 varying vec2 texCoord;
 
 const vec4 gloomStart = vec4(0.95,0.95,0.95,0.95);
 
 float sqr(float x) { return x*x; }
 vec4 sqr(vec4 x) { return x*x; }
 
 vec4 expand_Hdr(vec4 color)
 {
    return color*(sqr(color.a*2.0)+1.0);
 }
  
 void main(void)
 {
    vec4 color  = texture2D(SrcColor,texCoord);
    gl_FragColor = expand_Hdr(color*Exposure)-gloomStart;
 }

Fragment program for final composition stage

uniform float Exposure;
 uniform sampler2D SrcColor;
 uniform sampler2D SrcHDR1;
 uniform sampler2D SrcHDR2;
 uniform sampler2D SrcHDR3;
 uniform sampler2D SrcHDR4;
 uniform sampler2D Measure;
 
 uniform vec4 MipMix;
 
 float gloomIntensity=1.0;
 
 varying vec2 texCoord;
 
 float sqr(float x) { return x*x; }
 vec4 sqr(vec4 x) { return x*x; }
 
 vec4 expand_Hdr(vec4 color)
 {
    return color*(sqr(color.a*2.0)+1.0);
 }
 
 void main(void)
 {
    vec4 color  = texture2D(SrcColor,texCoord);
    vec4 gloom  = mat4(
       texture2D(SrcHDR1,texCoord),
       texture2D(SrcHDR2,texCoord),
       texture2D(SrcHDR3,texCoord),
       texture2D(SrcHDR4,texCoord) ) * MipMix;
    gl_FragColor = (expand_Hdr(color*Exposure)+gloom*16.0*gloomIntensity)*Exposure;
 }

Vertex/Fragment program for rendered objects

Vertex program

uniform vec3 LightDir;
 uniform vec4 vViewPosition;
 uniform mat4 matViewProjection;
 
 varying vec2 texCoord;
 varying vec3 normal;
 varying vec3 lightDirInTangent;
 varying vec3 viewDirInTangent;
 
 attribute vec3 rm_Tangent;
 attribute vec3 rm_Binormal;
 
 void main(void)
 {
    texCoord = gl_MultiTexCoord0.xy;
    
    mat3 tangentMat = mat3(rm_Tangent,
                           rm_Binormal,
                           gl_Normal);
    lightDirInTangent = normalize(LightDir) * tangentMat;
    viewDirInTangent  = normalize(vViewPosition-gl_Position).xyz * tangentMat;
    
    gl_Position = ftransform();
 }

Fragment program

uniform sampler2D BumpMap;
 uniform sampler2D ObjectMap;
 uniform sampler2D SpecMap;
 
 uniform float Shininess;
 uniform float SpecularIntensity;
 
 varying vec2 texCoord;
 varying vec3 lightDirInTangent;
 varying vec3 viewDirInTangent;
 
 void main(void)
 {
    vec3  n_lightDirInTangent = -normalize(lightDirInTangent);
    vec3  n_viewDirInTangent = normalize(viewDirInTangent);
    vec3  bump     = normalize(texture2D(BumpMap,texCoord).xyz * 2.0 - 1.0);
    float lighting = dot(bump,n_lightDirInTangent);
    float blighting= n_lightDirInTangent.z;
    float specular = dot(-reflect(n_lightDirInTangent,bump),n_viewDirInTangent);
    
    vec4 texColor = texture2D(ObjectMap,texCoord);
    vec4 specColor = texture2D(SpecMap, texCoord); 
    vec4 color = texColor * lighting 
               + float(lighting>0.0)*float(blighting>0.0) 
                 * SpecularIntensity*pow(specular,Shininess)*specColor;
    gl_FragColor = vec4(color.xyz*0.5,0.414);
 }

Fragment programs for first separable convolution stage

Horizontal

uniform sampler2D Src;
 
 varying vec2 texCoord;
 
 const float texDimension = 512.0;
 const float texScaler =  1.0/texDimension;
 const float texOffset = -0.5/texDimension;
 
 void main(void)
 {
    vec4 color = vec4(0.0,0.0,0.0,0.0);
    
    const float gauss0 = 1.0/32.0;
    const float gauss1 = 5.0/32.0;
    const float gauss2 =15.0/32.0;
    const float gauss3 =22.0/32.0;
    const float gauss4 =15.0/32.0;
    const float gauss5 = 5.0/32.0;
    const float gauss6 = 1.0/32.0;   
    
    vec4 gaussFilter[7];
    gaussFilter[0]  = vec4( -3.0*texScaler , 0.0, 0.0, gauss0); 
    gaussFilter[1]  = vec4( -2.0*texScaler , 0.0, 0.0, gauss1); 
    gaussFilter[2]  = vec4( -1.0*texScaler , 0.0, 0.0, gauss2); 
    gaussFilter[3]  = vec4(  0.0*texScaler , 0.0, 0.0, gauss3);
    gaussFilter[4]  = vec4( +1.0*texScaler , 0.0, 0.0, gauss4);
    gaussFilter[5]  = vec4( +2.0*texScaler , 0.0, 0.0, gauss5);
    gaussFilter[6]  = vec4( +3.0*texScaler , 0.0, 0.0, gauss6);
   
    int i;
    for (i=0;i<7;i++)
       color += texture2D(Src, texCoord + gaussFilter[i].xy) * gaussFilter[i].w;
    
    gl_FragColor = color*0.5;
 }

Vertical

uniform sampler2D Src; 
 
 varying vec2 texCoord;
 
 const float texDimension = 512.0;
 const float texScaler =  1.0/texDimension;
 const float texOffset = -0.5/texDimension;
 
 void main(void)
 {
    vec4 color = vec4(0.0,0.0,0.0,0.0);
    
    const float gauss0 = 1.0/32.0;
    const float gauss1 = 5.0/32.0;
    const float gauss2 =15.0/32.0;
    const float gauss3 =22.0/32.0;
    const float gauss4 =15.0/32.0;
    const float gauss5 = 5.0/32.0;
    const float gauss6 = 1.0/32.0;   
   
    vec4 gaussFilter[7];
    gaussFilter[0]  = vec4( -3.0*texScaler , 0.0, 0.0, gauss0).yxzw;
    gaussFilter[1]  = vec4( -2.0*texScaler , 0.0, 0.0, gauss1).yxzw;
    gaussFilter[2]  = vec4( -1.0*texScaler , 0.0, 0.0, gauss2).yxzw;
    gaussFilter[3]  = vec4(  0.0*texScaler , 0.0, 0.0, gauss3).yxzw;
    gaussFilter[4]  = vec4( +1.0*texScaler , 0.0, 0.0, gauss4).yxzw;
    gaussFilter[5]  = vec4( +2.0*texScaler , 0.0, 0.0, gauss5).yxzw;
    gaussFilter[6]  = vec4( +3.0*texScaler , 0.0, 0.0, gauss6).yxzw;
   
    for (int i=0;i<7;i++)
       color += texture2D(Src, texCoord + gaussFilter[i].xy) * gaussFilter[i].w;
    
    gl_FragColor = color*0.5;
 }

Convolution matrix for second separable convolution stage

const float gauss0 = 1.0/32.0;
   const float gauss1 = 5.0/32.0;
   const float gauss2 =15.0/32.0;
   const float gauss3 =22.0/32.0;
   const float gauss4 =15.0/32.0;
   const float gauss5 = 5.0/32.0;
   const float gauss6 = 1.0/32.0;

Convolution matrix for third separable convolution stage

const float gauss0 = 1.0/32.0;
   const float gauss1 = 5.0/32.0;
   const float gauss2 =15.0/32.0;
   const float gauss3 =22.0/32.0;
   const float gauss4 =15.0/32.0;
   const float gauss5 = 5.0/32.0;
   const float gauss6 = 1.0/32.0;

Convolution matrix for fourth separable convolution stage

const float gauss0 = 1.0/18.0;
   const float gauss1 = 2.0/18.0;
   const float gauss2 = 4.0/18.0;
   const float gauss3 = 4.0/18.0;
   const float gauss4 = 4.0/18.0;
   const float gauss5 = 2.0/18.0;
   const float gauss6 = 1.0/18.0;

Should help some coders here (i hope).

1 Like

all completely over my head but looks like you found some great resources there!

The reflection shader is the only reason i’m checking this thread every day, lol.

2 Likes

I mainly check it for that, along with to see if hunterk or guest.r is doing something new.

On that note the scanline spike mitigation is pretty nice, and I’m also looking forward to the red (smear, blur thing?) by hunterk.

I do check it for specific users shader chains.

8 posts were split to a new topic: New CRT shader from Guest