CRT-Guest-Advanced, HD and NTSC for ReShade!

Hey, @Pluuth and @AliAkbar. You can use my CRT-Geom port to get perfect scanlines in Ragebound (Just set Resolution_Y to 540 not 270) -

uniform float gm_crt <
	ui_type = "drag";
	ui_min = 0.5;
	ui_max = 4.0;
	ui_step = 0.05;
	ui_label = "CRT Gamma";
> = 2.4;

uniform float gm_lcd <
	ui_type = "drag";
	ui_min = 0.5;
	ui_max = 4.0;
	ui_step = 0.05;
	ui_label = "LCD Gamma";
> = 2.2;

uniform float brightness <
	ui_type = "drag";
	ui_min = 0.25;
	ui_max = 5.0;
	ui_step = 0.01;
	ui_label = "Brightness";
> = 1.0;

uniform float dmw <
	ui_type = "drag";
	ui_min = 0.0;
	ui_max = 1.0;
	ui_step = 0.05;
	ui_label = "Mask Strength";
> = 0.3;

uniform float wib <
	ui_type = "drag";
	ui_min = 0.1;
	ui_max = 0.5;
	ui_step = 0.05;
	ui_label = "Scanlines Strength";
> = 0.3;

uniform float gauss_scanlines <
	ui_type = "drag";
	ui_min = 0.0;
	ui_max = 1.0;
	ui_step = 1.0;
	ui_label = "Gaussian Scanlines";
> = 0.0;

uniform float csize <
	ui_type = "drag";
	ui_min = 0.0;
	ui_max = 0.25;
	ui_step = 0.005;
	ui_label = "Corner Size";
> = 0.0;

uniform float bsize <
	ui_type = "drag";
	ui_min = 0.0;
	ui_max = 3.0;
	ui_step = 0.01;
	ui_label = "Border Size";
> = 0.01;

uniform float sborder <
	ui_type = "drag";
	ui_min = 0.25;
	ui_max = 2.0;
	ui_step = 0.05;
	ui_label = "Border Intensity";
> = 0.75;

uniform float warpx <
	ui_type = "drag";
	ui_min = 0.0;
	ui_max = 0.25;
	ui_step = 0.01;
	ui_label = "Curvature X (Default 0.03)";
> = 0.0;

uniform float warpy <
	ui_type = "drag";
	ui_min = 0.0;
	ui_max = 0.25;
	ui_step = 0.01;
	ui_label = "Curvature Y (Default 0.04)";
> = 0.0;

uniform float c_shape <
	ui_type = "drag";
	ui_min = 0.05;
	ui_max = 0.6;
	ui_step = 0.05;
	ui_label = "Curvature Shape";
> = 0.25;

#include "ReShade.fxh"

#define TexSize float2(Resolution_X,Resolution_Y)
#define IptSize float2(Resolution_X,Resolution_Y)
#define OptSize float4(BUFFER_SCREEN_SIZE,1.0/BUFFER_SCREEN_SIZE)
#define SrcSize float4(TexSize,1.0/TexSize)
#define aspect float2(1.0,0.75)
#define FIX(c) max(abs(c),1e-5)
#define PI 3.14159265
#define mod_fact texcoord.x*TexSize.x*OptSize.x/IptSize.x
#define TEX2D(c) tex2D(GEOM_S00,(c))

#ifndef Resolution_X
#define Resolution_X 320
#endif

#ifndef Resolution_Y
#define Resolution_Y 240
#endif

#define GEOM_S00 ReShade::BackBuffer

uniform int framecount<source="framecount";>;

float2 curve(float2 pos)
{
	pos=pos*2.0-1.0;
	pos=lerp(pos,float2(pos.x*rsqrt(1.0-c_shape*pos.y*pos.y),pos.y*rsqrt(1.0-c_shape*pos.x*pos.x)),float2(warpx,warpy)/c_shape);
	return pos*0.5+0.5;
}

float corner(float2 pos)
{
	float2 bc=bsize*float2(1.0,OptSize.x/OptSize.y)*0.050;
	pos=clamp(pos,0.0,1.0);
	pos=abs(2.0*(pos-0.5));
	float csz=lerp(400.0,7.0,pow(4.0*csize,0.10));
	float crn=dot(pow(pos,csz.xx*float2(1.0,OptSize.y/OptSize.x)),1.0.xx);
	crn=(csize==0.0)? max(pos.x,pos.y):pow(crn,1.0/(csz));
	pos=max(pos,crn);
	float2 rs=(bsize==0.0)? 1.0.xx:lerp(0.0.xx,1.0.xx,smoothstep(1.0.xx,1.0.xx-bc,sqrt(pos)));
	rs=pow(rs, sborder.xx);
	return sqrt(rs.x*rs.y);
}

float mod(float x,float y)
{
	return x-y* floor(x/y);
}

float4 scanlines(float distance,float4 color)
{
	if(gauss_scanlines==1.0)
	{
	float4 wid=0.3+0.1*pow(color,3.0);
	float4 wld=distance/wid;
	return 0.4*exp(-wld*wld)/wid;}else
	{
	float4 wid=2.0+2.0*pow(color,4.0);
	float4 wld=distance/wib;
	return 1.4*exp(-pow(wld*rsqrt(0.5*wid),wid))/(0.6+0.2*wid);
	}
}

float4 GeomPS(float4 position:SV_Position,float2 texcoord:TEXCOORD):SV_Target
{
	float2 ilfac=float2(1.0,clamp(floor(IptSize.y/200.0),1.0,2.0));
	float2 xy=curve(texcoord);
	float2 ilvec=float2(0.0,0.0>1.5?mod(framecount,2.0):0.0);
	float2 ratio_scale=(xy*TexSize-0.5+ilvec)/ilfac;
	float2 uv_ratio=frac(ratio_scale);
	float2 cone=ilfac/TexSize;
	float2 yx=xy;
	float cval=corner(xy);
	float clear=fwidth(ratio_scale.y);
	xy=(floor(ratio_scale)*ilfac+0.5-ilvec)/TexSize;
	float4 co=PI*float4(1.0+uv_ratio.x,uv_ratio.x,1.0-uv_ratio.x,2.0-uv_ratio.x);
	co =FIX(co);
	co =2.0*sin(co)*sin(co/2.0)/(co*co);
	co/=dot(co,1.0);
	float4 col0=clamp(TEX2D(xy+float2(-cone.x,cone.y))*co.x+TEX2D(xy+float2(0.0,cone.y))*co.y+TEX2D(xy+cone)*co.z+TEX2D(xy+float2(2.0*cone.x,cone.y))*co.w,0.0,1.0);
	float4 col1=clamp(TEX2D(xy+float2(-cone.x,0.0))*co.x+TEX2D(xy)*co.y+TEX2D(xy+float2(cone.x,0.0))*co.z+TEX2D(xy+float2(2.0*cone.x,0.0))*co.w,0.0,1.0);
	col0=pow(col0,gm_crt);
	col1=pow(col1,gm_crt);
	float4 weights0=scanlines(1.0-uv_ratio.y,col0);
	float4 weights1=scanlines(    uv_ratio.y,col1);
	uv_ratio.y=uv_ratio.y+1.0/3.0*clear;
	weights0=(weights0+scanlines(abs(1.0-uv_ratio.y),col0))/3.0;
	weights1=(weights1+scanlines(abs(    uv_ratio.y),col1))/3.0;
	uv_ratio.y=uv_ratio.y-2.0/3.0*clear;
	weights0=(weights0+scanlines(abs(1.0-uv_ratio.y),col0))/3.0;
	weights1=(weights1+scanlines(abs(    uv_ratio.y),col1))/3.0;
	float3 mul_res=(col1*weights1+col0*weights0).rgb;
	float3 maskweights=lerp(float3(1.0,1.0-dmw,1.0),float3(1.0-dmw,1.0,1.0-dmw),floor(mod(mod_fact,2.0)));
	mul_res*=maskweights;
	mul_res=pow(mul_res,1.0/gm_lcd);
	return float4(mul_res*brightness*cval,1.0);
}

technique CRT_Geom
{
	pass
	{
	VertexShader=PostProcessVS;
	PixelShader=GeomPS;
	}
}

Resolution_Y = 270 -

Resolution_Y = 540 -

If you want something similar in the Guest-Advanced shaders. You need to ask @guest.r for EVEN/ODD scanlines.

5 Likes

isnt that what interlaced mode=1-3 do?

any plan to update to crt-guest-advanced-2025-10-08-release1?

2 Likes

I’ll look at it when I return home for 2 weeks holiday for New Year. No promises though.

4 Likes

Any plans for Lite or Single Pass versions? I have a Mini PC that groans under HD/Advanced/NTSC depending on the game. Imagine it’s even worse on Steam Deck.

I’m on Bazzite and using Reshade through Proton…

Hi, I downloaded this after trying it out in ShaderGlass, I think it’s simply amazing. I have a question: what exactly does the “interlace trigger resolution” do? and if it does what I think it does, how to use it? I see in the preprocessor definitions that the resolution X and Y are set to 320x240 so it seems the resolution cannot be fetched dynamically? I would definitely enjoy playing FFVIII for example with the menus interlaced and the gameplay fields in 240p as the game originally runs in the PS1. If this is what it’s supposed to do, how do I make it work?

I have an issue with the shader in Reshade (trying to run in DuckStation) where there are weird horizontal bands appearing, like a moiré pattern of some sort. But it is not due to scanlines nor shadow mask, because I tried disabling scanlines and shadowmask and the issue still appears. It’s like the screen is “cut” in horizontal “slices” and there are pixels missing in between those slices. As is, the shader is unusable, I don’t know if it’s an issue on my side but I have no idea what to do. Too bad because this is the best CRT shader ever. Comparing it side to side with my actual CRT and it gets so close.

EDIT #1: I just tried it in ShaderGlass again, and the issue was the exact same. But after changing the pixel size to 8x instead of 9x (which is correct for 240p at 4K, 8x being incorrect), the issue goes away. If needed I will post a video of the issue.

EDIT #2: I just tried it again in ShaderGlass, but this time I played the game on my actual CRT at real 240p resolution, and I set ShaderGlass to capture the game in clone mode instead of glass mode, with the pixel size set to 1. In this case, the issue doesn’t appear either. I can confirm this is an issue with resolution, but I don’t exactly know what. I don’t think I can help further with this but for the time being, I will use the ShaderGlass clone method. Unfortunately it adds input lag…

That trigger setting is the vertical resolution at which interlacing will be activated. Those patterns are probably due to a scaling mismatch. On reshade, you need to configure the scaling of the shader manually. For most ps1 games, X axis should be the horizontal resolution of your screen (2560, 1920, etc) and Y axis 240. For 1080p:

PreprocessorDefinitions=Resolution_X=1920,Resolution_Y=240

1 Like

Just popped an update in the main Guest thread; but to be honest its probably more suited here given that its related to Reshade.

In any case; I don’t want to just dupe the post - but here’s a link: New CRT shader from Guest + CRT Guest Advanced updates

1 Like

thanks! and if you forget about

then this a reminder :slight_smile: it was ok for me so better to be added in the next update

I have an interesting issue in Chained Echoes which will be in part to do with the way the game works - but, with Guest-HD on in Reshade, the assets wobble when you move the character. I assume it’s something to do with how they have placed pixel art assets on top of their pixel art backgrounds. If you turn Guest-HD off, the assets don’t move and just look like part of the static background.

I’ve changed a bunch of settings to see if it makes a difference but so far the only thing stopping it is turning off the shader altogether.

This doesn’t occur with other shaders in Reshade like Hyllian, FakeLottes etc

Hey there… Maybe try to tweak with “High Resolution Scanline” set to 1, or “Interlaced” OFF, as the wobble may be due to resolution downsizing or interlaced treshold res I guess.

1 Like

Thanks - I did try those but it hasn’t seemed to had an effect.

I definitely think it’s a scaling issue somewhere - I’m noticing diagonal lines are skewed when the shader is on. I’ll add example pictures later

1 Like

I guess there may be some dithering patterns in the pixel arts that could also cause some moire effects with the scanlines when they’re moved? I dont have the game so, yeah cant really help…

1 Like

Increasing the width resolution to the native of the screen helps with some of the distortion; the game runs at 640x360 and multiplies itself to 1920x1080; so going 1920x360 corrects some issues.

This is raw pixels:

This is with Guest and Reshade’s resolution set to 640x360 - notice the skewed diagonals on the top border; and the gold border on the side of the box at the bottom has been ‘overwritten’ with blue:

Changing Reshade to 1920x360 solves the border issue but the diagonals still aren’t perfect:

This doesn’t fix the wobbly assets but it’s not a huge issue; more a curiosity. It still looks great!

This is Guest-HD, Mask 10/Size 1/Zoom -1/Preserve Mask and Scanlines at 0.85

2 Likes

Seems some pixels in the raw images are taller than squares, could indicate a native res that doesnt fit with an integer scale at 1080p. So yeah, diagonals looks already skewed in the raw image. Are you sure it’s 640x360?

That’s what PCGamingWiki says; otherwise I’m not sure how else I can find out…

EDIT: Reshade’s statistics say 640x360 when you set the window scaling in game to 1x

Yeah it’s weird, lots of non-square pixels in the raw image you posted.

Odd; they’re like a pixel-and-a-half in size. I think the game was made in Unity and I have heard it can produce some issues with pixel art. Oh well, nothing to be done! Applying CRT shaders/using actual CRTs for modern games is always going to be a bit of a crap shoot

I mean, the added grain and texture of the shader you added still makes it nice to look at… Maybe try to tweak the “rolling scanlines” parameter to see how it interacts with the wobble?

1 Like