New CRT shader from Guest + CRT Guest Advanced updates

I’ll let the advanced features for guest’s. If it’s a new mask, you could include inside hunter’s include masks file and crt-hyllian will apply accordingly.

I try to keep crt-hyllian running fullspeed on PS3 using 5x scale. And it’s at the limit. For example, crt-geom only run fullspeed on PS3 using 4x scaling, the same with easymode or lottes. So, that’s my limit when I tweak crt-hyllian. It must be very light.

3 Likes

@guest.r

I think RBG is common enough that it’s worth including blue-yellow and RBGX as mask options. This is more complicated, but maybe there could be a toggle switch for RGB and RBG subpixels which automatically switches the mask colors…?

2 Likes

I think this was already discussed, and it turn out, that the magenta-green mask has even subpixel spacing even on RBG displays.

On RGB it goes like this: xox oxo xox oxo -> oxoxoxoxoxoxox

On RBG it goes like this: xxo oox xxo oox -> xxxoooxxxoooxxx

It’s different, but cannot say it’s better or worse. :grinning: Same with mask 5, mask 7 is BW. I think the only mask in question is new mask8, which is specially for 4k RGB. Might add a ‘mask 9’, since shuffling the channels doesn’t do the trick here. But i really don’t know how common the RBG setups are with 4k, maybe they are getting obsolete on PC screens, uncommonly used on TV’s. Tricky to find out.

3 Likes

Does anyone know how the green/magenta masks work on an oled? Maybe @c9f5fdda06 knows?

:thinking:

Ah yes I remember this now, thanks for reminding me :sweat_smile:

We can also use RGB aperture grille with RBG pixels. Looks like this

RXXXXGXBXRXXXXGXBX

Also, mask 8 can work at 1080p, but it’s like a 19” TV (270 TVL) at that resolution. Depends on what you’re going for.

1 Like

Depends on the subpixel structure, if it has the white subpixel then the subpixel masks won’t ever work as intended. That said, naive tiling looks much better at 4K than at 1080p. At 8K / retina resolution it’s no longer an issue.

2 Likes

Hey, thanks for this great shader!

Playing around with it to get something like a dedither + ntsc color while keeping as much details as possible.
I’m getting close to that but I’ve just noticed a dark tint turning completely black with LUT color set to 3:

The same spot with LUT 2 (blue rocks are fine now):

3 Likes

I’ll try with a stronger color transplantation in the dark spectrum. 10.0/255.0 should pick up some problematic colors. If there are some ‘problem causing’ color altering passes before, the problems can become visible.

2 Likes

No offense but I’ve gutted the LUTs in my branch, in favor of grade, but I also micromanage tf out of all aspects of the settings lol.

1 Like

Yeah, grade is a piece of work. But i like the LUT’s nevertheless, also connected with some sentiments. :face_with_monocle:

Meanwhile, i’m liking the new options with relevant games. The catch is that high initial blur allowance produces natural bloom with ‘CRT gamma’. Needs some mask ‘makeup’ and it looks lot better.

Also newest version works better with low color count games as the previous version.

4 Likes

Completely understand, just was stating my preference lol.

Bloom looks fairly controlled in that shot, very nice.

1 Like

Is the bloom in that shot intentional bloom or a side effect of something else?

Some bloom was added. But it’s rather a fast setup. Brightboost would also do. Bloom, in general, has mostly two components in linear space. First is plain brightness increase, the other is spatial. Very high blur increases the second.

1 Like

GDV Shader update.

Notable changes:

  • now a prominent metric is used to measure the color differences for the ‘smart edge’ effect
  • automatic switching between aliased and anti-aliased modes at horizontal sharpness 2.8->2.6 with the mentioned effect.
  • new menu parameter organization -> main reason to switch to new version :grin:
  • LUT 3 colors patched in the dark spectrum, need some feedback though (@Tatsuya79).

Download link:

https://mega.nz/file/49BAGTiR#nZi1v7OVh7v80PQcQpOiKid52_OynEyoX9sjH5NXQuo

Feedback, as always, is welcome. :upside_down_face:

12 Likes

The problem is still there on LUT 3 with that blue color.

Nice new presentation!

3 Likes

Thanks. :grinning:

Could you try this pre-shaders-afterglow.slang file ? It does a quirky transplantation. I like LUT3, but it has broken low’s and pre-processing manages to find more inconsistencies. Maybe i’ll just ask here if someone has a better suggestions for LUT 3 (size 32, gamma friendly, no 'bad sectors :wink:).

#version 450
 

layout(push_constant) uniform Push
{
   vec4 SourceSize;
   vec4 OriginalSize;
   vec4 OutputSize;
   uint FrameCount;
   float TNTC;
   float CP, CS;
   float WP;
   float wp_saturation;
   float AS, sat;
} params;

#pragma parameter AS "          Afterglow Strength" 0.07 0.0 0.50 0.01
#define AS params.AS

#pragma parameter sat "          Afterglow saturation" 0.10 0.0 1.0 0.01
#define sat params.sat

#pragma parameter bogus_color "[ COLOR TWEAKS ]:" 0.0 0.0 1.0 1.0

#pragma parameter TNTC "          LUT Colors" 0.0 0.0 3.0 1.0
#define TNTC params.TNTC

#pragma parameter CP "          CRT Color Profile" 0.0 -1.0 5.0 1.0 
#pragma parameter CS "          Color Space: sRGB, DCI, Adobe, Rec.2020" 0.0 0.0 3.0 1.0 

#define CP params.CP
#define CS params.CS
 
#pragma parameter WP "          Color Temperature %" 0.0 -100.0 100.0 5.0 
#pragma parameter wp_saturation "          Saturation Adjustment" 1.0 0.0 2.0 0.05 

#define WP params.WP
#define wp_saturation params.wp_saturation

layout(std140, set = 0, binding = 0) uniform UBO
{
   mat4 MVP;
} global;

#pragma stage vertex
layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 vTexCoord;

void main()
{
   gl_Position = global.MVP * Position;
   vTexCoord = TexCoord;
}

#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D StockPass;
layout(set = 0, binding = 3) uniform sampler2D AfterglowPass;
layout(set = 0, binding = 4) uniform sampler2D SamplerLUT1;
layout(set = 0, binding = 5) uniform sampler2D SamplerLUT2;
layout(set = 0, binding = 6) uniform sampler2D SamplerLUT3;
layout(set = 0, binding = 7) uniform sampler2D OriginalHistory0;

#define LUT_Size 32.0
#define COMPAT_TEXTURE(c,d) texture(c,d)


// Color profile matrices

const mat3 Profile0 = 
mat3(
 0.412391,  0.212639,  0.019331,
 0.357584,  0.715169,  0.119195,
 0.180481,  0.072192,  0.950532
);

const mat3 Profile1 = 
mat3(
 0.430554,  0.222004,  0.020182,
 0.341550,  0.706655,  0.129553,
 0.178352,  0.071341,  0.939322
);

const mat3 Profile2 = 
mat3(
 0.396686,  0.210299,  0.006131,
 0.372504,  0.713766,  0.115356,
 0.181266,  0.075936,  0.967571
);

const mat3 Profile3 = 
mat3(
 0.393521,  0.212376,  0.018739,
 0.365258,  0.701060,  0.111934,
 0.191677,  0.086564,  0.958385
);

const mat3 Profile4 = 
mat3(
 0.392258,  0.209410,  0.016061,
 0.351135,  0.725680,  0.093636,
 0.166603,  0.064910,  0.850324
);

const mat3 Profile5 = 
mat3(
 0.377923,  0.195679,  0.010514,
 0.317366,  0.722319,  0.097826,
 0.207738,  0.082002,  1.076960
);

const mat3 ToSRGB = 
mat3(
 3.240970, -0.969244,  0.055630,
-1.537383,  1.875968, -0.203977,
-0.498611,  0.041555,  1.056972
);

const mat3 ToDCI = 
mat3(
 2.725394,  -0.795168,   0.041242,
-1.018003,   1.689732,  -0.087639,
-0.440163,   0.022647,   1.100929
);

const mat3 ToAdobe = 
mat3(
 2.041588, -0.969244,  0.013444,
-0.565007,  1.875968, -0.11836,
-0.344731,  0.041555,  1.015175
);

const mat3 ToREC = 
mat3(
 1.716651, -0.666684,  0.017640,
-0.355671,  1.616481, -0.042771,
-0.253366,  0.015769,  0.942103
); 

// Color temperature matrices

const mat3 D65_to_D55 = mat3 (
           0.4850339153,  0.2500956126,  0.0227359648,
           0.3488957224,  0.6977914447,  0.1162985741,
           0.1302823568,  0.0521129427,  0.6861537456);


const mat3 D65_to_D93 = mat3 (
           0.3683017655,  0.1899055978,  0.0172641453,
           0.3555467892,  0.7110935785,  0.1185155964,
           0.2475020592,  0.0990008237,  1.3035108450);

// This shouldn't be necessary but it seems some undefined values can
// creep in and each GPU vendor handles that differently. This keeps
// all values within a safe range
vec4 mixfix(vec4 a, vec4 b, float c)
{
	return (a.z < 1.0) ? mix(a, b, c) : a;
}


void main()
{
   vec4 imgColor = COMPAT_TEXTURE(StockPass, vTexCoord.xy);
   vec4 imgColop = COMPAT_TEXTURE(OriginalHistory0, vTexCoord.xy);   
   vec4 aftglow = COMPAT_TEXTURE(AfterglowPass, vTexCoord.xy);
   
   float w = 1.0-aftglow.w;

   float l = length(aftglow.rgb);
   aftglow.rgb = AS*w*normalize(pow(aftglow.rgb + 0.01, vec3(sat)))*l;
   
   vec3 color = imgColor.rgb;
   
   if (int(TNTC) == 3 && (imgColor.r < 11.0/255.0 || imgColor.g < 11.0/255.0 || imgColor.b < 11.0/255.0)) imgColor.rgb = imgColop.rgb;
   
   if (int(TNTC) == 0)
   {
      color.rgb = imgColor.rgb;
   }
   else
   {
      float red = ( imgColor.r * (LUT_Size - 1.0) + 0.499999 ) / (LUT_Size * LUT_Size);
      float green = ( imgColor.g * (LUT_Size - 1.0) + 0.499999 ) / LUT_Size;
      float blue1 = (floor( imgColor.b  * (LUT_Size - 1.0) ) / LUT_Size) + red;
      float blue2 = (ceil( imgColor.b  * (LUT_Size - 1.0) ) / LUT_Size) + red;
      float mixer = clamp(max((imgColor.b - blue1) / (blue2 - blue1), 0.0), 0.0, 32.0);
      vec4 color1, color2, res;
      if (int(TNTC) == 1)
      {
         color1 = COMPAT_TEXTURE( SamplerLUT1, vec2( blue1, green ));
         color2 = COMPAT_TEXTURE( SamplerLUT1, vec2( blue2, green ));
         res = mixfix(color1, color2, mixer);
         float mx = max(res.r,max(res.g,res.b));
         float l = mix(length(imgColor.rgb), length(res.rgb), max(mx-0.5,0.0));
         res.rgb = mix(imgColor.rgb, res.rgb, clamp(25.0*(mx-0.02),0.0,1.0));
         res.rgb = normalize(res.rgb+1e-9)*l;
      }
      else if (int(TNTC) == 2)
      {
         color1 = COMPAT_TEXTURE( SamplerLUT2, vec2( blue1, green ));
         color2 = COMPAT_TEXTURE( SamplerLUT2, vec2( blue2, green ));
         res = mixfix(color1, color2, mixer);
         float l = mix(length(imgColor.rgb), length(res.rgb), 0.4);
         res.rgb = normalize(res.rgb + 1e-9)*l;
      }	
      else if (int(TNTC) == 3)
      {
         color1 = COMPAT_TEXTURE( SamplerLUT3, vec2( blue1, green ));
         color2 = COMPAT_TEXTURE( SamplerLUT3, vec2( blue2, green ));
         res = mixfix(color1, color2, mixer);
         res.rgb = pow(res.rgb, vec3(1.0/1.20));
         
         if ( max(max(imgColor.r, imgColor.g),imgColor.b) < 11.0/255.0) res.rgb = imgColor.rgb;
		 
         float l = length(imgColor.rgb);
         res.rgb = normalize(res.rgb + 1e-9)*l;
      }	
      
      color = mix(imgColor.rgb, res.rgb, min(TNTC,1.0));
   }

	vec3 c = clamp(color, 0.0, 1.0);
	
	float p;
	mat3 m_out;
	
	if (CS == 0.0) { p = 2.4; m_out =  ToSRGB; } else
	if (CS == 1.0) { p = 2.6; m_out =  ToDCI;  } else
	if (CS == 2.0) { p = 2.2; m_out =  ToAdobe;} else
	if (CS == 3.0) { p = 2.4; m_out =  ToREC;  }
	
	color = pow(c, vec3(p));
	
	mat3 m_in = Profile0;

	if (CP == 0.0) { m_in = Profile0; } else	
	if (CP == 1.0) { m_in = Profile1; } else
	if (CP == 2.0) { m_in = Profile2; } else
	if (CP == 3.0) { m_in = Profile3; } else
	if (CP == 4.0) { m_in = Profile4; } else
	if (CP == 5.0) { m_in = Profile5; }
	
	color = m_in*color;
	color = m_out*color;

	color = clamp(color, 0.0, 1.0);

	color = pow(color, vec3(1.0/p));	
	
	if (CP == -1.0) color = c;
	
	vec3 scolor1 = normalize(pow(color + 0.000000001, vec3(wp_saturation)))*length(color);
	float luma = dot(color, vec3(0.2126, 0.7152, 0.0722));
	vec3 scolor2 = mix(vec3(luma), color, wp_saturation);
	color = (wp_saturation > 1.0) ? scolor1 : scolor2;
   
	p = 2.2;
	
	color = pow(color, vec3(p)); 
 
	color = clamp(color, 0.0, 1.0); 
	
	vec3 warmer = D65_to_D55*color;
	warmer = ToSRGB*warmer;
	
	vec3 cooler = D65_to_D93*color;
	cooler = ToSRGB*cooler;
	
	float m = abs(WP)/100.0;
	
	vec3 comp = (WP < 0.0) ? cooler : warmer;
	
	color = mix(color, comp, m);
	color = pow(max(color, 0.0), vec3(1.0/p));
	
	color = color + aftglow.rgb;
	
	FragColor = vec4(color, 1.0); 
}

No change for that bug. :confused:

It’s not one of the darkest blue.

1 Like

@Tatsuya79 @guest.r

Not sure if this is the same thing, I got similar artifacts on LUT3 and posted my “fix” in this post:

I haven’t got a clue about coding or what that value does in the lut file, but messing about and changing the value from 1.20 to 1.0 removed the artifacts!

By the way, this worked on GLSL and SLANG versions and it was the original GDV shader, not sure if the lut file has changed in recent times.

2 Likes

That doesn’t help here.

But I just found that setting FBNeo to 16bits instead of 32bits color (in the core options) gets rid of the problem.

3 Likes

Thanks for the shader, even without a mask it’s fun to play. I like the glow :sunrise_over_mountains:

Bonus with bloom and mask:

  1. https://pasteboard.co/JDf9yMx.png

  2. https://pasteboard.co/JDfelTf.png

Deconvergence 1.0:

  1. https://pasteboard.co/JDfeEaG.png
3 Likes