Easymode CRT shader works correctly

This commit is contained in:
Robert Beckebans 2024-08-01 17:23:07 +02:00
parent a4de5a1350
commit cef666f2fd
8 changed files with 349 additions and 10 deletions

View file

@ -6509,7 +6509,7 @@ void idRenderBackend::CRTPostProcess()
}
else
{
renderProgManager.BindShader_CrtZFast();
renderProgManager.BindShader_CrtEasyMode();
}
float windowCoordParm[4];

View file

@ -539,7 +539,7 @@ void idRenderProgManager::Init( nvrhi::IDevice* device )
{ BUILTIN_POSTPROCESS_RETRO_PSX, "builtin/post/retro_ps1", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_CRT_MATTIAS, "builtin/post/crt_mattias", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_CRT_NUPIXIE, "builtin/post/crt_newpixie", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_CRT_ZFAST, "builtin/post/crt_zfast_curvature", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_CRT_EASYMODE, "builtin/post/crt_easymode", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_POST_PROCESS_FINAL },
{ BUILTIN_SCREEN, "builtin/post/screen", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
{ BUILTIN_TONEMAP, "builtin/post/tonemap", "", { { "BRIGHTPASS", "0" }, { "HDR_DEBUG", "0"} }, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },

View file

@ -377,7 +377,7 @@ enum
BUILTIN_POSTPROCESS_RETRO_PSX, // Sony Playstation 1
BUILTIN_CRT_MATTIAS,
BUILTIN_CRT_NUPIXIE,
BUILTIN_CRT_ZFAST,
BUILTIN_CRT_EASYMODE,
BUILTIN_SCREEN,
BUILTIN_TONEMAP,
BUILTIN_BRIGHTPASS,
@ -869,9 +869,9 @@ public:
BindShader_Builtin( BUILTIN_CRT_NUPIXIE );
}
void BindShader_CrtZFast()
void BindShader_CrtEasyMode()
{
BindShader_Builtin( BUILTIN_CRT_ZFAST );
BindShader_Builtin( BUILTIN_CRT_EASYMODE );
}
void BindShader_Screen()

View file

@ -57,7 +57,7 @@ struct PS_OUT
// Set to 0 to use linear filter and gain speed
#define ENABLE_LANCZOS 1
#define RESOLUTION_DIVISOR 2.0
#define RESOLUTION_DIVISOR 4.0
float4 dilate( float4 col )
{
@ -110,6 +110,17 @@ float mod( float x, float y )
return x - y * floor( x / y );
}
float2 curve( float2 uv, float curvature )
{
uv = ( uv - 0.5 ) * curvature;
uv *= 1.1;
uv.x *= 1.0 + pow( ( abs( uv.y ) / 5.0 ), 2.0 );
uv.y *= 1.0 + pow( ( abs( uv.x ) / 4.0 ), 2.0 );
uv = ( uv / curvature ) + 0.5;
uv = uv * 0.92 + 0.04;
return uv;
}
void main( PS_IN fragment, out PS_OUT result )
{
// revised version from RetroArch
@ -163,11 +174,19 @@ void main( PS_IN fragment, out PS_OUT result )
float4 sourceSize = outputSize;
#else
float4 sourceSize;
sourceSize.xy = rpWindowCoord.zw / RESOLUTION_DIVISOR;
sourceSize.xy = rpWindowCoord.zw / float2( 4, 4.4 ); //RESOLUTION_DIVISOR;
sourceSize.zw = float2( 1.0, 1.0 ) / sourceSize.xy;
#endif
float2 vTexCoord = fragment.texcoord0.xy;
#if 0
if( rpWindowCoord.x > 0.0 )
{
vTexCoord = curve( vTexCoord, 2.0 );
}
#endif
float2 dx = float2( sourceSize.z, 0.0 );
float2 dy = float2( 0.0, sourceSize.w );
float2 pix_co = vTexCoord * sourceSize.xy - float2( 0.5, 0.5 );
@ -201,7 +220,7 @@ void main( PS_IN fragment, out PS_OUT result )
float bright = ( max( col.r, max( col.g, col.b ) ) + luma ) * 0.5;
float scan_bright = clamp( bright, params.SCANLINE_BRIGHT_MIN, params.SCANLINE_BRIGHT_MAX );
float scan_beam = clamp( bright * params.SCANLINE_BEAM_WIDTH_MAX, params.SCANLINE_BEAM_WIDTH_MIN, params.SCANLINE_BEAM_WIDTH_MAX );
float scan_weight = 1.0 - pow( cos( vTexCoord.y * 2.0 * PI * sourceSize.y ) * 0.5 + 0.5, scan_beam ) * params.SCANLINE_STRENGTH;
float scan_weight = 1.0 - pow( cos( vTexCoord.y * 2.0 * PI * sourceSize.y / RESOLUTION_DIVISOR ) * 0.5 + 0.5, scan_beam ) * params.SCANLINE_STRENGTH;
float mask = 1.0 - params.MASK_STRENGTH;
float2 mod_fac = floor( vTexCoord * outputSize.xy * sourceSize.xy / ( sourceSize.xy * float2( params.MASK_SIZE, params.MASK_DOT_HEIGHT * params.MASK_SIZE ) ) );
@ -234,5 +253,9 @@ void main( PS_IN fragment, out PS_OUT result )
col *= mask_weight;
col = pow( col, _float3( 1.0 / params.GAMMA_OUTPUT ) );
//col = col2;
//col = _float3( scan_weight );
//col = float3( scan_bright, scan_beam, scan_weight );
result.color = float4( col * params.BRIGHT_BOOST, 1.0 );
}

View file

@ -0,0 +1,261 @@
/*
CRT Shader by EasyMode
License: GPL
A flat CRT shader ideally for 1080p or higher displays.
Recommended Settings:
Video
- Aspect Ratio: 4:3
- Integer Scale: Off
Shader
- Filter: Nearest
- Scale: Don't Care
Example RGB Mask Parameter Settings:
Aperture Grille (Default)
- Dot Width: 1
- Dot Height: 1
- Stagger: 0
Lottes' Shadow Mask
- Dot Width: 2
- Dot Height: 1
- Stagger: 3
*/
#include <global_inc.hlsl>
// *INDENT-OFF*
Texture2D t_CurrentRender : register( t0 VK_DESCRIPTOR_SET( 0 ) );
Texture2D t_BlueNoise : register( t1 VK_DESCRIPTOR_SET( 0 ) );
SamplerState s_LinearClamp : register(s0 VK_DESCRIPTOR_SET( 1 ) );
SamplerState s_LinearWrap : register(s1 VK_DESCRIPTOR_SET( 1 ) ); // blue noise 256
struct PS_IN
{
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
struct PS_OUT
{
float4 color : SV_Target0;
};
// *INDENT-ON*
#define TEX2D(c) dilate(t_CurrentRender.Sample( s_LinearClamp, c ).rgba)
#define FIX(c) max(abs(c), 1e-5)
// Set to 0 to use linear filter and gain speed
#define ENABLE_LANCZOS 1
#define RESOLUTION_DIVISOR 4.0
float4 dilate( float4 col )
{
#if 1
// FIXME
//float4 x = lerp( _float4( 1.0 ), col, params.DILATION );
float4 x = lerp( _float4( 1.0 ), col, 1.0 );
return col * x;
#else
return col;
#endif
}
float curve_distance( float x, float sharp )
{
/*
apply half-circle s-curve to distance for sharper (more pixelated) interpolation
single line formula for Graph Toy:
0.5 - sqrt(0.25 - (x - step(0.5, x)) * (x - step(0.5, x))) * sign(0.5 - x)
*/
float x_step = step( 0.5, x );
float curve = 0.5 - sqrt( 0.25 - ( x - x_step ) * ( x - x_step ) ) * sign( 0.5 - x );
return lerp( x, curve, sharp );
}
float4x4 get_color_matrix( float2 co, float2 dx )
{
return float4x4( TEX2D( co - dx ), TEX2D( co ), TEX2D( co + dx ), TEX2D( co + 2.0 * dx ) );
// transpose for HLSL
//m = transpose(m);
//return m;
}
float3 filter_lanczos( float4 coeffs, float4x4 color_matrix )
{
float4 col = mul( color_matrix, coeffs );
float4 sample_min = min( color_matrix[1], color_matrix[2] );
float4 sample_max = max( color_matrix[1], color_matrix[2] );
col = clamp( col, sample_min, sample_max );
return col.rgb;
}
float mod( float x, float y )
{
return x - y * floor( x / y );
}
float2 curve( float2 uv, float curvature )
{
uv = ( uv - 0.5 ) * curvature;
uv *= 1.1;
uv.x *= 1.0 + pow( ( abs( uv.y ) / 5.0 ), 2.0 );
uv.y *= 1.0 + pow( ( abs( uv.x ) / 4.0 ), 2.0 );
uv = ( uv / curvature ) + 0.5;
uv = uv * 0.92 + 0.04;
return uv;
}
void main( PS_IN fragment, out PS_OUT result )
{
// revised version from RetroArch
struct Params
{
float BRIGHT_BOOST;
float DILATION;
float GAMMA_INPUT;
float GAMMA_OUTPUT;
float MASK_SIZE;
float MASK_STAGGER;
float MASK_STRENGTH;
float MASK_DOT_HEIGHT;
float MASK_DOT_WIDTH;
float SCANLINE_CUTOFF;
float SCANLINE_BEAM_WIDTH_MAX;
float SCANLINE_BEAM_WIDTH_MIN;
float SCANLINE_BRIGHT_MAX;
float SCANLINE_BRIGHT_MIN;
float SCANLINE_STRENGTH;
float SHARPNESS_H;
float SHARPNESS_V;
};
Params params;
params.BRIGHT_BOOST = 1.2;
params.DILATION = 1.0;
params.GAMMA_INPUT = 2.0;
params.GAMMA_OUTPUT = 1.8;
params.MASK_SIZE = 1.0;
params.MASK_STAGGER = 0.0;
params.MASK_STRENGTH = 0.8;
params.MASK_DOT_HEIGHT = 1.0;
params.MASK_DOT_WIDTH = 1.0;
params.SCANLINE_CUTOFF = 400.0;
params.SCANLINE_BEAM_WIDTH_MAX = 1.5;
params.SCANLINE_BEAM_WIDTH_MIN = 1.5;
params.SCANLINE_BRIGHT_MAX = 0.65;
params.SCANLINE_BRIGHT_MIN = 0.35;
params.SCANLINE_STRENGTH = 1.0;
params.SHARPNESS_H = 0.5;
params.SHARPNESS_V = 1.0;
float4 outputSize;
outputSize.xy = rpWindowCoord.zw;
outputSize.zw = float2( 1.0, 1.0 ) / rpWindowCoord.zw;
#if 1
float4 sourceSize = outputSize;
#else
float4 sourceSize;
sourceSize.xy = rpWindowCoord.zw / float2( 4, 4.4 ); //RESOLUTION_DIVISOR;
sourceSize.zw = float2( 1.0, 1.0 ) / sourceSize.xy;
#endif
float2 vTexCoord = fragment.texcoord0.xy;
#if 0
if( rpWindowCoord.x > 0.0 )
{
vTexCoord = curve( vTexCoord, 2.0 );
}
#endif
float2 dx = float2( sourceSize.z, 0.0 );
float2 dy = float2( 0.0, sourceSize.w );
float2 pix_co = vTexCoord * sourceSize.xy - float2( 0.5, 0.5 );
float2 tex_co = ( floor( pix_co ) + float2( 0.5, 0.5 ) ) * sourceSize.zw;
float2 dist = frac( pix_co );
float curve_x;
float3 col, col2;
#if ENABLE_LANCZOS
curve_x = curve_distance( dist.x, params.SHARPNESS_H * params.SHARPNESS_H );
float4 coeffs = PI * float4( 1.0 + curve_x, curve_x, 1.0 - curve_x, 2.0 - curve_x );
coeffs = FIX( coeffs );
coeffs = 2.0 * sin( coeffs ) * sin( coeffs * 0.5 ) / ( coeffs * coeffs );
coeffs /= dot( coeffs, _float4( 1.0 ) );
col = filter_lanczos( coeffs, get_color_matrix( tex_co, dx ) );
col2 = filter_lanczos( coeffs, get_color_matrix( tex_co + dy, dx ) );
#else
curve_x = curve_distance( dist.x, params.SHARPNESS_H );
col = lerp( TEX2D( tex_co ).rgb, TEX2D( tex_co + dx ).rgb, curve_x );
col2 = lerp( TEX2D( tex_co + dy ).rgb, TEX2D( tex_co + dx + dy ).rgb, curve_x );
#endif
col = lerp( col, col2, curve_distance( dist.y, params.SHARPNESS_V ) );
col = pow( col, _float3( params.GAMMA_INPUT / ( params.DILATION + 1.0 ) ) );
float luma = dot( float3( 0.2126, 0.7152, 0.0722 ), col );
float bright = ( max( col.r, max( col.g, col.b ) ) + luma ) * 0.5;
float scan_bright = clamp( bright, params.SCANLINE_BRIGHT_MIN, params.SCANLINE_BRIGHT_MAX );
float scan_beam = clamp( bright * params.SCANLINE_BEAM_WIDTH_MAX, params.SCANLINE_BEAM_WIDTH_MIN, params.SCANLINE_BEAM_WIDTH_MAX );
float scan_weight = 1.0 - pow( cos( vTexCoord.y * 2.0 * PI * sourceSize.y / RESOLUTION_DIVISOR ) * 0.5 + 0.5, scan_beam ) * params.SCANLINE_STRENGTH;
float mask = 1.0 - params.MASK_STRENGTH;
float2 mod_fac = floor( vTexCoord * outputSize.xy * sourceSize.xy / ( sourceSize.xy * float2( params.MASK_SIZE, params.MASK_DOT_HEIGHT * params.MASK_SIZE ) ) );
int dot_no = int( mod( ( mod_fac.x + mod( mod_fac.y, 2.0 ) * params.MASK_STAGGER ) / params.MASK_DOT_WIDTH, 3.0 ) );
float3 mask_weight;
if( dot_no == 0 )
{
mask_weight = float3( 1.0, mask, mask );
}
else if( dot_no == 1 )
{
mask_weight = float3( mask, 1.0, mask );
}
else
{
mask_weight = float3( mask, mask, 1.0 );
}
#if 0
if( sourceSize.y >= params.SCANLINE_CUTOFF )
{
scan_weight = 1.0;
}
#endif
col2 = col.rgb;
col *= _float3( scan_weight );
col = lerp( col, col2, scan_bright );
col *= mask_weight;
col = pow( col, _float3( 1.0 / params.GAMMA_OUTPUT ) );
//col = col2;
//col = _float3( scan_weight );
//col = float3( scan_bright, scan_beam, scan_weight );
result.color = float4( col * params.BRIGHT_BOOST, 1.0 );
}

View file

@ -0,0 +1,55 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "global_inc.hlsl"
// *INDENT-OFF*
struct VS_IN
{
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
float4 normal : NORMAL;
float4 tangent : TANGENT;
float4 color : COLOR0;
float4 color2 : COLOR1;
};
struct VS_OUT {
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
// *INDENT-ON*
void main( VS_IN vertex, out VS_OUT result )
{
result.position = vertex.position;
result.position.y = -result.position.y;
result.texcoord0 = vertex.texcoord;
}

View file

@ -68,8 +68,8 @@ builtin/post/crt_mattias.vs.hlsl -T vs
builtin/post/crt_mattias.ps.hlsl -T ps
builtin/post/crt_newpixie.vs.hlsl -T vs
builtin/post/crt_newpixie.ps.hlsl -T ps
builtin/post/crt_zfast_curvature.vs.hlsl -T vs
builtin/post/crt_zfast_curvature.ps.hlsl -T ps
builtin/post/crt_easymode.vs.hlsl -T vs
builtin/post/crt_easymode.ps.hlsl -T ps
builtin/post/screen.vs.hlsl -T vs
builtin/post/screen.ps.hlsl -T ps
builtin/post/tonemap.vs.hlsl -T vs -D BRIGHTPASS={0,1} -D HDR_DEBUG={0,1}