Shaders: Add new pack of shaders (reshade) (#3232)

- Add crt-geom, super-xbr, geom, multi-LUT, deblur-luma, bicubic and lanczos3. All .fx shaders;
- Added some LUTs.
This commit is contained in:
Hyllian 2024-06-23 21:16:51 -03:00 committed by GitHub
parent 6021e435ba
commit 9189588554
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 1931 additions and 0 deletions

View file

@ -0,0 +1,628 @@
#include "ReShade.fxh"
/*
CRT-interlaced
Copyright (C) 2010-2012 cgwg, Themaister and DOLLS
This program 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 2 of the License, or (at your option)
any later version.
(cgwg gave their consent to have the original version of this shader
distributed under the GPL in this message:
http://board.byuu.org/viewtopic.php?p=26075#p26075
"Feel free to distribute my shaders under the GPL. After all, the
barrel distortion code was taken from the Curvature shader, which is
under the GPL."
)
This shader variant is pre-configured with screen curvature
*/
uniform float CRTgamma <
ui_type = "drag";
ui_min = 0.1;
ui_max = 5.0;
ui_step = 0.1;
ui_label = "CRTGeom Target Gamma";
> = 2.4;
uniform float monitorgamma <
ui_type = "drag";
ui_min = 0.1;
ui_max = 5.0;
ui_step = 0.1;
ui_label = "CRTGeom Monitor Gamma";
> = 2.2;
uniform float d <
ui_type = "drag";
ui_category = "Curvature";
ui_min = 0.1;
ui_max = 3.0;
ui_step = 0.1;
ui_label = "CRTGeom Distance";
> = 1.5;
uniform bool CURVATURE <
ui_category = "Curvature";
ui_type = "radio";
ui_label = "CRTGeom Curvature Toggle";
> = 1.0;
uniform float invert_aspect <
ui_type = "drag";
ui_category = "Curvature";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 1.0;
ui_label = "CRTGeom Curvature Aspect Inversion";
> = 0.0;
uniform float R <
ui_type = "drag";
ui_category = "Curvature";
ui_min = 0.1;
ui_max = 10.0;
ui_step = 0.1;
ui_label = "CRTGeom Curvature Radius";
> = 2.0;
uniform float cornersize <
ui_type = "drag";
ui_category = "Curvature";
ui_min = 0.001;
ui_max = 1.0;
ui_step = 0.005;
ui_label = "CRTGeom Corner Size";
> = 0.03;
uniform float cornersmooth <
ui_type = "drag";
ui_category = "Curvature";
ui_min = 80.0;
ui_max = 2000.0;
ui_step = 100.0;
ui_label = "CRTGeom Corner Smoothness";
> = 1000.0;
uniform float x_tilt <
ui_type = "drag";
ui_category = "Curvature";
ui_min = -0.5;
ui_max = 0.5;
ui_step = 0.05;
ui_label = "CRTGeom Horizontal Tilt";
> = 0.0;
uniform float y_tilt <
ui_type = "drag";
ui_category = "Curvature";
ui_min = -0.5;
ui_max = 0.5;
ui_step = 0.05;
ui_label = "CRTGeom Vertical Tilt";
> = 0.0;
uniform float overscan_x <
ui_type = "drag";
ui_min = -125.0;
ui_max = 125.0;
ui_step = 0.5;
ui_label = "CRTGeom Horiz. Overscan %";
> = 100.0;
uniform float overscan_y <
ui_type = "drag";
ui_min = -125.0;
ui_max = 125.0;
ui_step = 0.5;
ui_label = "CRTGeom Vert. Overscan %";
> = 100.0;
uniform float DOTMASK <
ui_type = "drag";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 0.05;
ui_label = "CRTGeom Dot Mask Strength";
> = 0.3;
uniform float SHARPER <
ui_type = "drag";
ui_min = 1.0;
ui_max = 3.0;
ui_step = 1.0;
ui_label = "CRTGeom Sharpness";
> = 1.0;
uniform float scanline_weight <
ui_type = "drag";
ui_min = 0.1;
ui_max = 0.5;
ui_step = 0.05;
ui_label = "CRTGeom Scanline Weight";
> = 0.3;
uniform float vertical_scanlines <
ui_type = "drag";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 1.0;
ui_label = "CRTGeom Vertical Scanlines";
> = 0.0;
uniform float lum <
ui_type = "drag";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 0.01;
ui_label = "CRTGeom Luminance";
> = 0.0;
uniform float interlace_detect <
ui_type = "drag";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 1.0;
ui_label = "CRTGeom Interlacing Simulation";
> = 1.0;
uniform float FrameCount < source = "framecount"; >;
uniform float2 BufferViewportRatio < source = "buffer_to_viewport_ratio"; >;
uniform float2 InternalPixelSize < source = "internal_pixel_size"; >;
uniform float2 NativePixelSize < source = "native_pixel_size"; >;
uniform float2 NormalizedInternalPixelSize < source = "normalized_internal_pixel_size"; >;
uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >;
uniform float UpscaleMultiplier < source = "upscale_multiplier"; >;
uniform float2 ViewportSize < source = "viewportsize"; >;
// Comment the next line to disable interpolation in linear gamma (and
// gain speed).
#define LINEAR_PROCESSING
// Enable 3x oversampling of the beam profile; improves moire effect caused by scanlines+curvature
#define OVERSAMPLE
// Use the older, purely gaussian beam profile; uncomment for speed
//#define USEGAUSSIAN
// Macros.
#define FIX(c) max(abs(c), 1e-5);
#define PI 3.141592653589
#ifdef LINEAR_PROCESSING
# define TEX2D(c) pow(tex2D(ReShade::BackBuffer, (c)), float4(CRTgamma,CRTgamma,CRTgamma,CRTgamma))
#else
# define TEX2D(c) tex2D(ReShade::BackBuffer, (c))
#endif
// aspect ratio
#define aspect (invert_aspect>0.5?float2(0.75,1.0):float2(1.0,0.75))
#define overscan (float2(1.01,1.01));
struct ST_VertexOut
{
float2 sinangle : TEXCOORD1;
float2 cosangle : TEXCOORD2;
float3 stretch : TEXCOORD3;
float2 ilfac : TEXCOORD4;
float2 one : TEXCOORD5;
float mod_factor : TEXCOORD6;
float2 TextureSize : TEXCOORD7;
};
float vs_intersect(float2 xy, float2 sinangle, float2 cosangle)
{
float A = dot(xy,xy) + d*d;
float B = 2.0*(R*(dot(xy,sinangle)-d*cosangle.x*cosangle.y)-d*d);
float C = d*d + 2.0*R*d*cosangle.x*cosangle.y;
return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
}
float2 vs_bkwtrans(float2 xy, float2 sinangle, float2 cosangle)
{
float c = vs_intersect(xy, sinangle, cosangle);
float2 point = (float2(c, c)*xy - float2(-R, -R)*sinangle) / float2(R, R);
float2 poc = point/cosangle;
float2 tang = sinangle/cosangle;
float A = dot(tang, tang) + 1.0;
float B = -2.0*dot(poc, tang);
float C = dot(poc, poc) - 1.0;
float a = (-B + sqrt(B*B - 4.0*A*C))/(2.0*A);
float2 uv = (point - a*sinangle)/cosangle;
float r = FIX(R*acos(a));
return uv*r/sin(r/R);
}
float2 vs_fwtrans(float2 uv, float2 sinangle, float2 cosangle)
{
float r = FIX(sqrt(dot(uv,uv)));
uv *= sin(r/R)/r;
float x = 1.0-cos(r/R);
float D = d/R + x*cosangle.x*cosangle.y+dot(uv,sinangle);
return d*(uv*cosangle-x*sinangle)/D;
}
float3 vs_maxscale(float2 sinangle, float2 cosangle)
{
float2 c = vs_bkwtrans(-R * sinangle / (1.0 + R/d*cosangle.x*cosangle.y), sinangle, cosangle);
float2 a = float2(0.5,0.5)*aspect;
float2 lo = float2(vs_fwtrans(float2(-a.x, c.y), sinangle, cosangle).x,
vs_fwtrans(float2( c.x, -a.y), sinangle, cosangle).y)/aspect;
float2 hi = float2(vs_fwtrans(float2(+a.x, c.y), sinangle, cosangle).x,
vs_fwtrans(float2( c.x, +a.y), sinangle, cosangle).y)/aspect;
return float3((hi+lo)*aspect*0.5,max(hi.x-lo.x,hi.y-lo.y));
}
// Vertex shader generating a triangle covering the entire screen
void VS_CRT_Geom(in uint id : SV_VertexID, out float4 position : SV_Position, out float2 texcoord : TEXCOORD, out ST_VertexOut vVARS)
{
texcoord.x = (id == 2) ? 2.0 : 0.0;
texcoord.y = (id == 1) ? 2.0 : 0.0;
position = float4(texcoord * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
float2 SourceSize = 1.0/NormalizedNativePixelSize;
float2 OutputSize = ViewportSize*BufferViewportRatio;
// Precalculate a bunch of useful values we'll need in the fragment
// shader.
vVARS.sinangle = sin(float2(x_tilt, y_tilt));
vVARS.cosangle = cos(float2(x_tilt, y_tilt));
vVARS.stretch = vs_maxscale(vVARS.sinangle, vVARS.cosangle);
if(vertical_scanlines < 0.5)
{
vVARS.TextureSize = float2(SHARPER * SourceSize.x, SourceSize.y);
vVARS.ilfac = float2(1.0, clamp(floor(SourceSize.y/(interlace_detect > 0.5 ? 200.0 : 1000)), 1.0, 2.0));
// The size of one texel, in texture-coordinates.
vVARS.one = vVARS.ilfac / vVARS.TextureSize;
// Resulting X pixel-coordinate of the pixel we're drawing.
vVARS.mod_factor = texcoord.x * SourceSize.x * OutputSize.x / SourceSize.x;
}else{
vVARS.TextureSize = float2(SourceSize.x, SHARPER * SourceSize.y);
vVARS.ilfac = float2(clamp(floor(SourceSize.x/(interlace_detect > 0.5 ? 200.0 : 1000)), 1.0, 2.0), 1.0);
// The size of one texel, in texture-coordinates.
vVARS.one = vVARS.ilfac / vVARS.TextureSize;
// Resulting X pixel-coordinate of the pixel we're drawing.
vVARS.mod_factor = texcoord.y * SourceSize.y * OutputSize.y / SourceSize.y;
}
}
float intersect(float2 xy, float2 sinangle, float2 cosangle)
{
float A = dot(xy,xy) + d*d;
float B, C;
if(vertical_scanlines < 0.5)
{
B = 2.0*(R*(dot(xy,sinangle) - d*cosangle.x*cosangle.y) - d*d);
C = d*d + 2.0*R*d*cosangle.x*cosangle.y;
}else{
B = 2.0*(R*(dot(xy,sinangle) - d*cosangle.y*cosangle.x) - d*d);
C = d*d + 2.0*R*d*cosangle.y*cosangle.x;
}
return (-B-sqrt(B*B - 4.0*A*C))/(2.0*A);
}
float2 bkwtrans(float2 xy, float2 sinangle, float2 cosangle)
{
float c = intersect(xy, sinangle, cosangle);
float2 point = (float2(c, c)*xy - float2(-R, -R)*sinangle) / float2(R, R);
float2 poc = point/cosangle;
float2 tang = sinangle/cosangle;
float A = dot(tang, tang) + 1.0;
float B = -2.0*dot(poc, tang);
float C = dot(poc, poc) - 1.0;
float a = (-B + sqrt(B*B - 4.0*A*C)) / (2.0*A);
float2 uv = (point - a*sinangle) / cosangle;
float r = FIX(R*acos(a));
return uv*r/sin(r/R);
}
float2 fwtrans(float2 uv, float2 sinangle, float2 cosangle)
{
float r = FIX(sqrt(dot(uv, uv)));
uv *= sin(r/R)/r;
float x = 1.0 - cos(r/R);
float D;
if(vertical_scanlines < 0.5)
D = d/R + x*cosangle.x*cosangle.y + dot(uv,sinangle);
else
D = d/R + x*cosangle.y*cosangle.x + dot(uv,sinangle);
return d*(uv*cosangle - x*sinangle)/D;
}
float3 maxscale(float2 sinangle, float2 cosangle)
{
if(vertical_scanlines < 0.5)
{
float2 c = bkwtrans(-R * sinangle / (1.0 + R/d*cosangle.x*cosangle.y), sinangle, cosangle);
float2 a = float2(0.5, 0.5)*aspect;
float2 lo = float2(fwtrans(float2(-a.x, c.y), sinangle, cosangle).x,
fwtrans(float2( c.x, -a.y), sinangle, cosangle).y)/aspect;
float2 hi = float2(fwtrans(float2(+a.x, c.y), sinangle, cosangle).x,
fwtrans(float2( c.x, +a.y), sinangle, cosangle).y)/aspect;
return float3((hi+lo)*aspect*0.5,max(hi.x-lo.x, hi.y-lo.y));
}else{
float2 c = bkwtrans(-R * sinangle / (1.0 + R/d*cosangle.y*cosangle.x), sinangle, cosangle);
float2 a = float2(0.5, 0.5)*aspect;
float2 lo = float2(fwtrans(float2(-a.y, c.x), sinangle, cosangle).y,
fwtrans(float2( c.y, -a.x), sinangle, cosangle).x)/aspect;
float2 hi = float2(fwtrans(float2(+a.y, c.x), sinangle, cosangle).y,
fwtrans(float2( c.y, +a.x), sinangle, cosangle).x)/aspect;
return float3((hi+lo)*aspect*0.5,max(hi.y-lo.y, hi.x-lo.x));
}
}
// Calculate the influence of a scanline on the current pixel.
//
// 'distance' is the distance in texture coordinates from the current
// pixel to the scanline in question.
// 'color' is the colour of the scanline at the horizontal location of
// the current pixel.
float4 scanlineWeights(float distance, float4 color)
{
// "wid" controls the width of the scanline beam, for each RGB
// channel The "weights" lines basically specify the formula
// that gives you the profile of the beam, i.e. the intensity as
// a function of distance from the vertical center of the
// scanline. In this case, it is gaussian if width=2, and
// becomes nongaussian for larger widths. Ideally this should
// be normalized so that the integral across the beam is
// independent of its width. That is, for a narrower beam
// "weights" should have a higher peak at the center of the
// scanline than for a wider beam.
#ifdef USEGAUSSIAN
float4 wid = 0.3 + 0.1 * pow(color, float4(3.0, 3.0, 3.0, 3.0));
float dsw = distance / scanline_weight;
float4 weights = float4(dsw, dsw, dsw, dsw);
return (lum + 0.4) * exp(-weights * weights) / wid;
#else
float4 wid = 2.0 + 2.0 * pow(color, float4(4.0, 4.0, 4.0, 4.0));
float dsw = distance / scanline_weight;
float4 weights = float4(dsw, dsw, dsw, dsw);
return (lum + 1.4) * exp(-pow(weights * rsqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid);
#endif
}
float2 transform(float2 coord, float2 sinangle, float2 cosangle, float3 stretch)
{
coord = (coord - float2(0.5, 0.5))*aspect*stretch.z + stretch.xy;
return (bkwtrans(coord, sinangle, cosangle) /
float2(overscan_x / 100.0, overscan_y / 100.0)/aspect + float2(0.5, 0.5));
}
float corner(float2 coord)
{
coord = (coord - float2(0.5, 0.5)) * float2(overscan_x / 100.0, overscan_y / 100.0) + float2(0.5, 0.5);
coord = min(coord, float2(1.0, 1.0) - coord) * aspect;
float2 cdist = float2(cornersize, cornersize);
coord = (cdist - min(coord, cdist));
float dist = sqrt(dot(coord, coord));
if(vertical_scanlines < 0.5)
return clamp((cdist.x - dist)*cornersmooth, 0.0, 1.0);
else
return clamp((cdist.y - dist)*cornersmooth, 0.0, 1.0);
}
float fwidth(float value){
return abs(ddx(value)) + abs(ddy(value));
}
float4 PS_CRT_Geom(float4 vpos: SV_Position, float2 vTexCoord : TEXCOORD, in ST_VertexOut vVARS) : SV_Target
{
// Here's a helpful diagram to keep in mind while trying to
// understand the code:
//
// | | | | |
// -------------------------------
// | | | | |
// | 01 | 11 | 21 | 31 | <-- current scanline
// | | @ | | |
// -------------------------------
// | | | | |
// | 02 | 12 | 22 | 32 | <-- next scanline
// | | | | |
// -------------------------------
// | | | | |
//
// Each character-cell represents a pixel on the output
// surface, "@" represents the current pixel (always somewhere
// in the bottom half of the current scan-line, or the top-half
// of the next scanline). The grid of lines represents the
// edges of the texels of the underlying texture.
// Texture coordinates of the texel containing the active pixel.
float2 xy;
if (CURVATURE > 0.5)
xy = transform(vTexCoord, vVARS.sinangle, vVARS.cosangle, vVARS.stretch);
else
xy = vTexCoord;
float cval = corner(xy);
// Of all the pixels that are mapped onto the texel we are
// currently rendering, which pixel are we currently rendering?
float2 ilvec;
if(vertical_scanlines < 0.5)
ilvec = float2(0.0, vVARS.ilfac.y * interlace_detect > 1.5 ? (float(FrameCount) % 2.0) : 0.0);
else
ilvec = float2(vVARS.ilfac.x * interlace_detect > 1.5 ? (float(FrameCount) % 2.0) : 0.0, 0.0);
float2 ratio_scale = (xy * vVARS.TextureSize - float2(0.5, 0.5) + ilvec) / vVARS.ilfac;
float2 uv_ratio = frac(ratio_scale);
// Snap to the center of the underlying texel.
xy = (floor(ratio_scale)*vVARS.ilfac + float2(0.5, 0.5) - ilvec) / vVARS.TextureSize;
// Calculate Lanczos scaling coefficients describing the effect
// of various neighbour texels in a scanline on the current
// pixel.
float4 coeffs;
if(vertical_scanlines < 0.5)
coeffs = PI * float4(1.0 + uv_ratio.x, uv_ratio.x, 1.0 - uv_ratio.x, 2.0 - uv_ratio.x);
else
coeffs = PI * float4(1.0 + uv_ratio.y, uv_ratio.y, 1.0 - uv_ratio.y, 2.0 - uv_ratio.y);
// Prevent division by zero.
coeffs = FIX(coeffs);
// Lanczos2 kernel.
coeffs = 2.0 * sin(coeffs) * sin(coeffs / 2.0) / (coeffs * coeffs);
// Normalize.
coeffs /= dot(coeffs, float4(1.0, 1.0, 1.0, 1.0));
// Calculate the effective colour of the current and next
// scanlines at the horizontal location of the current pixel,
// using the Lanczos coefficients above.
float4 col, col2;
if(vertical_scanlines < 0.5)
{
col = clamp(
mul(coeffs, float4x4(
TEX2D(xy + float2(-vVARS.one.x, 0.0)),
TEX2D(xy),
TEX2D(xy + float2(vVARS.one.x, 0.0)),
TEX2D(xy + float2(2.0 * vVARS.one.x, 0.0))
)),
0.0, 1.0
);
col2 = clamp(
mul(coeffs, float4x4(
TEX2D(xy + float2(-vVARS.one.x, vVARS.one.y)),
TEX2D(xy + float2(0.0, vVARS.one.y)),
TEX2D(xy + vVARS.one),
TEX2D(xy + float2(2.0 * vVARS.one.x, vVARS.one.y))
)),
0.0, 1.0
);
}else{
col = clamp(
mul(coeffs, float4x4(
TEX2D(xy + float2(0.0, -vVARS.one.y)),
TEX2D(xy),
TEX2D(xy + float2(0.0, vVARS.one.y)),
TEX2D(xy + float2(0.0, 2.0 * vVARS.one.y))
)),
0.0, 1.0
);
col2 = clamp(
mul(coeffs, float4x4(
TEX2D(xy + float2(vVARS.one.x, -vVARS.one.y)),
TEX2D(xy + float2(vVARS.one.x, 0.0)),
TEX2D(xy + vVARS.one),
TEX2D(xy + float2(vVARS.one.x, 2.0 * vVARS.one.y))
)),
0.0, 1.0
);
}
#ifndef LINEAR_PROCESSING
col = pow(col , float4(CRTgamma, CRTgamma, CRTgamma, CRTgamma));
col2 = pow(col2, float4(CRTgamma, CRTgamma, CRTgamma, CRTgamma));
#endif
// Calculate the influence of the current and next scanlines on
// the current pixel.
float4 weights, weights2;
if(vertical_scanlines < 0.5)
{
weights = scanlineWeights(uv_ratio.y, col);
weights2 = scanlineWeights(1.0 - uv_ratio.y, col2);
#ifdef OVERSAMPLE
float filter = fwidth(ratio_scale.y);
uv_ratio.y = uv_ratio.y + 1.0/3.0*filter;
weights = (weights + scanlineWeights(uv_ratio.y, col))/3.0;
weights2 = (weights2 + scanlineWeights(abs(1.0 - uv_ratio.y), col2))/3.0;
uv_ratio.y = uv_ratio.y - 2.0/3.0*filter;
weights = weights + scanlineWeights(abs(uv_ratio.y), col)/3.0;
weights2 = weights2 + scanlineWeights(abs(1.0 - uv_ratio.y), col2)/3.0;
#endif
}else{
weights = scanlineWeights(uv_ratio.x, col);
weights2 = scanlineWeights(1.0 - uv_ratio.x, col2);
#ifdef OVERSAMPLE
float filter = fwidth(ratio_scale.x);
uv_ratio.x = uv_ratio.x + 1.0/3.0*filter;
weights = (weights + scanlineWeights(uv_ratio.x, col))/3.0;
weights2 = (weights2 + scanlineWeights(abs(1.0 - uv_ratio.x), col2))/3.0;
uv_ratio.x = uv_ratio.x - 2.0/3.0*filter;
weights = weights + scanlineWeights(abs(uv_ratio.x), col)/3.0;
weights2 = weights2 + scanlineWeights(abs(1.0 - uv_ratio.x), col2)/3.0;
#endif
}
float3 mul_res = (col * weights + col2 * weights2).rgb;
mul_res *= float3(cval, cval, cval);
// dot-mask emulation:
// Output pixels are alternately tinted green and magenta.
float3 dotMaskWeights = lerp(
float3(1.0, 1.0 - DOTMASK, 1.0),
float3(1.0 - DOTMASK, 1.0, 1.0 - DOTMASK),
floor((vVARS.mod_factor % 2.0))
);
mul_res *= dotMaskWeights;
// Convert the image gamma for display on our output device.
mul_res = pow(mul_res, float3(1.0 / monitorgamma, 1.0 / monitorgamma, 1.0 / monitorgamma));
return float4(mul_res, 1.0);
}
technique CRT_Geom
{
pass
{
VertexShader = VS_CRT_Geom;
PixelShader = PS_CRT_Geom;
}
}

View file

@ -0,0 +1,423 @@
#include "ReShade.fxh"
/*
******* Super XBR Shader *******
Copyright (c) 2015-2024 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
uniform float XBR_EDGE_STR_P0 <
ui_category = "Super-xBR:";
ui_type = "drag";
ui_min = 0.0;
ui_max = 5.0;
ui_step = 0.5;
ui_label = "Xbr - Edge Strength p0";
> = 5.0;
uniform float XBR_WEIGHT <
ui_category = "Super-xBR:";
ui_type = "drag";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 0.1;
ui_label = "Xbr - Filter Weight";
> = 1.0;
uniform float JINC2_WINDOW_SINC <
ui_category = "Jinc2:";
ui_type = "drag";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 0.01;
ui_label = "Window Sinc Param";
> = 0.5;
uniform float JINC2_SINC <
ui_category = "Jinc2:";
ui_type = "drag";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 0.01;
ui_label = "Sinc Param";
> = 0.88;
uniform float JINC2_AR_STRENGTH <
ui_category = "Jinc2:";
ui_type = "drag";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 0.01;
ui_label = "Anti-ringing Strength";
> = 0.5;
uniform float2 BufferToViewportRatio < source = "buffer_to_viewport_ratio"; >;
uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >;
texture2D tBackBufferY{Width=BUFFER_WIDTH;Height=BUFFER_HEIGHT;Format=RGBA8;};
sampler2D sBackBufferY{Texture=tBackBufferY;AddressU=BORDER;AddressV=BORDER;AddressW=BORDER;MagFilter=POINT;MinFilter=POINT;};
texture2D tSuper_xBR_P0 < pooled = true; > {Width=BUFFER_WIDTH;Height=BUFFER_HEIGHT;Format=RGBA8;};
sampler2D sSuper_xBR_P0{Texture=tSuper_xBR_P0;AddressU=CLAMP;AddressV=CLAMP;AddressW=CLAMP;MagFilter=POINT;MinFilter=POINT;};
texture2D tSuper_xBR_P1 < pooled = true; > {Width=BUFFER_WIDTH;Height=BUFFER_HEIGHT;Format=RGBA8;};
sampler2D sSuper_xBR_P1{Texture=tSuper_xBR_P1;AddressU=CLAMP;AddressV=CLAMP;AddressW=CLAMP;MagFilter=POINT;MinFilter=POINT;};
texture2D tSuper_xBR_P2 < pooled = true; > {Width=BUFFER_WIDTH;Height=BUFFER_HEIGHT;Format=RGBA8;};
sampler2D sSuper_xBR_P2{Texture=tSuper_xBR_P2;AddressU=CLAMP;AddressV=CLAMP;AddressW=CLAMP;MagFilter=POINT;MinFilter=POINT;};
#define Y float3(.2126,.7152,.0722)
static const float wp0[6] = {2.0, 1.0, -1.0, 4.0, -1.0, 1.0};
static const float wp1[6] = {1.0, 0.0, 0.0, 0.0, 0.0, 0.0};
static const float wp2[6] = {0.0, 0.0, 0.0, 1.0, 0.0, 0.0};
float luma(float3 color)
{
return dot(color, Y);
}
float df(float A, float B)
{
return abs(A-B);
}
/*
P1
|P0|B |C |P1| C F4 |a0|b1|c2|d3|
|D |E |F |F4| B F I4 |b0|c1|d2|e3| |e1|i1|i2|e2|
|G |H |I |I4| P0 E A I P3 |c0|d1|e2|f3| |e3|i3|i4|e4|
|P2|H5|I5|P3| D H I5 |d0|e1|f2|g3|
G H5
P2
*/
float d_wd(float wp[6], float b0, float b1, float c0, float c1, float c2, float d0, float d1, float d2, float d3, float e1, float e2, float e3, float f2, float f3)
{
return (wp[0]*(df(c1,c2) + df(c1,c0) + df(e2,e1) + df(e2,e3)) + wp[1]*(df(d2,d3) + df(d0,d1)) + wp[2]*(df(d1,d3) + df(d0,d2)) + wp[3]*df(d1,d2) + wp[4]*(df(c0,c2) + df(e1,e3)) + wp[5]*(df(b0,b1) + df(f2,f3)));
}
float hv_wd(float wp[6], float i1, float i2, float i3, float i4, float e1, float e2, float e3, float e4)
{
return ( wp[3]*(df(i1,i2)+df(i3,i4)) + wp[0]*(df(i1,e1)+df(i2,e2)+df(i3,e3)+df(i4,e4)) + wp[2]*(df(i1,e2)+df(i3,e4)+df(e1,i2)+df(e3,i4)));
}
float3 min4(float3 a, float3 b, float3 c, float3 d)
{
return min(a, min(b, min(c, d)));
}
float3 max4(float3 a, float3 b, float3 c, float3 d)
{
return max(a, max(b, max(c, d)));
}
float max4float(float a, float b, float c, float d)
{
return max(a, max(b, max(c, d)));
}
float3 super_xbr(float wp[6], float4 P0, float4 B, float4 C, float4 P1, float4 D, float4 E, float4 F, float4 F4, float4 G, float4 H, float4 I, float4 I4, float4 P2, float4 H5, float4 I5, float4 P3)
{
float b = B.a; float c = C.a; float d = D.a; float e = E.a;
float f = F.a; float g = G.a; float h = H.a; float i = I.a;
float i4 = I4.a; float p0 = P0.a; float i5 = I5.a; float p1 = P1.a;
float h5 = H5.a; float p2 = P2.a; float f4 = F4.a; float p3 = P3.a;
/* Calc edgeness in diagonal directions. */
float d_edge = (d_wd( wp, d, b, g, e, c, p2, h, f, p1, h5, i, f4, i5, i4 ) - d_wd( wp, c, f4, b, f, i4, p0, e, i, p3, d, h, i5, g, h5 ));
/* Calc edgeness in horizontal/vertical directions. */
float hv_edge = (hv_wd(wp, f, i, e, h, c, i5, b, h5) - hv_wd(wp, e, f, h, i, d, f4, g, i4));
float limits = XBR_EDGE_STR_P0 + 0.000001;
float edge_strength = smoothstep(0.0, limits, abs(d_edge));
float4 w1, w2;
float3 c3, c4;
float weight1 = (XBR_WEIGHT*1.29633/10.0);
float weight2 = (XBR_WEIGHT*1.75068/10.0/2.0);
/* Filter weights. Two taps only. */
w1 = float4(-weight1, weight1+0.50, weight1+0.50, -weight1);
w2 = float4(-weight2, weight2+0.25, weight2+0.25, -weight2);
c3 = mul(w2, float4x3(D.rgb+G.rgb, E.rgb+H.rgb, F.rgb+I.rgb, F4.rgb+I4.rgb));
c4 = mul(w2, float4x3(C.rgb+B.rgb, F.rgb+E.rgb, I.rgb+H.rgb, I5.rgb+H5.rgb));
/* Filtering and normalization in four direction generating four colors. */
float3 c1 = mul(w1, float4x3( P2.rgb, H.rgb, F.rgb, P1.rgb ));
float3 c2 = mul(w1, float4x3( P0.rgb, E.rgb, I.rgb, P3.rgb ));
/* Smoothly blends the two strongest directions (one in diagonal and the other in vert/horiz direction). */
float3 color = lerp(lerp(c1, c2, step(0.0, d_edge)), lerp(c3, c4, step(0.0, hv_edge)), 1. - edge_strength);
/* Anti-ringing code. */
float3 min_sample = min4( E.rgb, F.rgb, H.rgb, I.rgb );
float3 max_sample = max4( E.rgb, F.rgb, H.rgb, I.rgb );
color = clamp(color, min_sample, max_sample);
return color;
}
float4 BackBufferY(float4 pos: SV_Position, float2 vTexCoord : TEXCOORD) : SV_Target
{
float3 color = tex2D(ReShade::BackBuffer, vTexCoord.xy).rgb;
return float4(color, luma(color));
}
float4 Super_xBR_P0(float4 pos: SV_Position, float2 vTexCoord : TEXCOORD) : SV_Target
{
float2 ps = NormalizedNativePixelSize;
float4 P0 = tex2D(sBackBufferY, vTexCoord.xy + ps*float2(-1.0, -1.0));
float4 B = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 0.0, -1.0));
float4 C = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 1.0, -1.0));
float4 P1 = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 2.0, -1.0));
float4 D = tex2D(sBackBufferY, vTexCoord.xy + ps*float2(-1.0, 0.0));
float4 E = tex2D(sBackBufferY, vTexCoord.xy );
float4 F = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 1.0, 0.0));
float4 F4 = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 2.0, 0.0));
float4 G = tex2D(sBackBufferY, vTexCoord.xy + ps*float2(-1.0, 1.0));
float4 H = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 0.0, 1.0));
float4 I = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 1.0, 1.0));
float4 I4 = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 2.0, 1.0));
float4 P2 = tex2D(sBackBufferY, vTexCoord.xy + ps*float2(-1.0, 2.0));
float4 H5 = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 0.0, 2.0));
float4 I5 = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 1.0, 2.0));
float4 P3 = tex2D(sBackBufferY, vTexCoord.xy + ps*float2( 2.0, 2.0));
float3 color = super_xbr(wp0, P0, B, C, P1, D, E, F, F4, G, H, I, I4, P2, H5, I5, P3);
return float4(color, luma(color));
}
float4 Super_xBR_P1(float4 pos: SV_Position, float2 vTexCoord : TEXCOORD) : SV_Target
{
float2 ps = NormalizedNativePixelSize;
//Skip pixels on wrong grid
float2 fp = frac(vTexCoord.xy / ps);
float2 dir = fp - float2(0.5,0.5);
if ((dir.x*dir.y)>0.0)
{
return lerp( tex2D(sBackBufferY, vTexCoord), tex2D(sSuper_xBR_P0, vTexCoord), step(0.0, dir.x));
}
else
{
float2 g1 = (fp.x>0.5) ? float2(0.5*ps.x, 0.0) : float2(0.0, 0.5*ps.y);
float2 g2 = (fp.x>0.5) ? float2(0.0, 0.5*ps.y) : float2(0.5*ps.x, 0.0);
float4 P0 = tex2D( sBackBufferY, vTexCoord -3.0*g1 );
float4 P1 = tex2D(sSuper_xBR_P0, vTexCoord -3.0*g2);
float4 P2 = tex2D(sSuper_xBR_P0, vTexCoord +3.0*g2);
float4 P3 = tex2D( sBackBufferY, vTexCoord +3.0*g1 );
float4 B = tex2D(sSuper_xBR_P0, vTexCoord -2.0*g1 -g2);
float4 C = tex2D( sBackBufferY, vTexCoord -g1 -2.0*g2);
float4 D = tex2D(sSuper_xBR_P0, vTexCoord -2.0*g1 +g2);
float4 E = tex2D( sBackBufferY, vTexCoord -g1 );
float4 F = tex2D(sSuper_xBR_P0, vTexCoord -g2);
float4 G = tex2D( sBackBufferY, vTexCoord -g1 +2.0*g2);
float4 H = tex2D(sSuper_xBR_P0, vTexCoord +g2);
float4 I = tex2D( sBackBufferY, vTexCoord +g1 );
float4 F4 = tex2D(sBackBufferY, vTexCoord +g1 -2.0*g2);
float4 I4 = tex2D( sSuper_xBR_P0, vTexCoord +2.0*g1 -g2);
float4 H5 = tex2D(sBackBufferY, vTexCoord +g1 +2.0*g2);
float4 I5 = tex2D( sSuper_xBR_P0, vTexCoord +2.0*g1 +g2);
float3 color = super_xbr(wp1, P0, B, C, P1, D, E, F, F4, G, H, I, I4, P2, H5, I5, P3);
return float4(color, luma(color));
}
}
float4 Super_xBR_P2(float4 pos: SV_Position, float2 vTexCoord : TEXCOORD) : SV_Target
{
float2 ps = 0.5*NormalizedNativePixelSize;
float4 P0 = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2(-2.0, -2.0));
float4 B = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2(-1.0, -2.0));
float4 C = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2( 0.0, -2.0));
float4 P1 = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2( 1.0, -2.0));
float4 D = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2(-2.0, -1.0));
float4 E = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2(-1.0, -1.0));
float4 F = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2( 0.0, -1.0));
float4 F4 = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2( 1.0, -1.0));
float4 G = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2(-2.0, 0.0));
float4 H = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2(-1.0, 0.0));
float4 I = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2( 0.0, 0.0));
float4 I4 = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2( 1.0, 0.0));
float4 P2 = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2(-2.0, 1.0));
float4 H5 = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2(-1.0, 1.0));
float4 I5 = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2( 0.0, 1.0));
float4 P3 = tex2D(sSuper_xBR_P1, vTexCoord.xy + ps*float2( 1.0, 1.0));
float3 color = super_xbr(wp2, P0, B, C, P1, D, E, F, F4, G, H, I, I4, P2, H5, I5, P3);
return float4(color, 1.0);
}
#define halfpi 1.5707963267948966192313216916398
#define pi 3.1415926535897932384626433832795
#define wa (JINC2_WINDOW_SINC*pi)
#define wb (JINC2_SINC*pi)
// Calculates the distance between two points
float dst(float2 pt1, float2 pt2)
{
float2 v = pt2 - pt1;
return sqrt(dot(v,v));
}
float4 resampler(float4 x)
{
float4 res;
res.x = (x.x==0.0) ? (wa*wb) : sin(x.x*wa)*sin(x.x*wb)/(x.x*x.x);
res.y = (x.y==0.0) ? (wa*wb) : sin(x.y*wa)*sin(x.y*wb)/(x.y*x.y);
res.z = (x.z==0.0) ? (wa*wb) : sin(x.z*wa)*sin(x.z*wb)/(x.z*x.z);
res.w = (x.w==0.0) ? (wa*wb) : sin(x.w*wa)*sin(x.w*wb)/(x.w*x.w);
return res;
}
float4 Jinc2(float4 pos: SV_Position, float2 vTexCoord : TEXCOORD) : SV_Target
{
float2 ps = 0.5*NormalizedNativePixelSize;
float3 color;
float4x4 weights;
float2 dx = float2(1.0, 0.0);
float2 dy = float2(0.0, 1.0);
float2 pc = vTexCoord / ps;
float2 tc = (floor(pc-float2(0.5,0.5))+float2(0.5,0.5));
weights[0] = resampler(float4(dst(pc, tc -dx -dy), dst(pc, tc -dy), dst(pc, tc +dx -dy), dst(pc, tc+2.0*dx -dy)));
weights[1] = resampler(float4(dst(pc, tc -dx ), dst(pc, tc ), dst(pc, tc +dx ), dst(pc, tc+2.0*dx )));
weights[2] = resampler(float4(dst(pc, tc -dx +dy), dst(pc, tc +dy), dst(pc, tc +dx +dy), dst(pc, tc+2.0*dx +dy)));
weights[3] = resampler(float4(dst(pc, tc -dx+2.0*dy), dst(pc, tc +2.0*dy), dst(pc, tc +dx+2.0*dy), dst(pc, tc+2.0*dx+2.0*dy)));
//weights[0][0] = weights[0][3] = weights[3][0] = weights[3][3] = 0.0;
dx = dx * ps;
dy = dy * ps;
tc = tc * ps;
// reading the texels
float3 c00 = tex2D(sSuper_xBR_P2, tc -dx -dy).xyz;
float3 c10 = tex2D(sSuper_xBR_P2, tc -dy).xyz;
float3 c20 = tex2D(sSuper_xBR_P2, tc +dx -dy).xyz;
float3 c30 = tex2D(sSuper_xBR_P2, tc+2.0*dx -dy).xyz;
float3 c01 = tex2D(sSuper_xBR_P2, tc -dx ).xyz;
float3 c11 = tex2D(sSuper_xBR_P2, tc ).xyz;
float3 c21 = tex2D(sSuper_xBR_P2, tc +dx ).xyz;
float3 c31 = tex2D(sSuper_xBR_P2, tc+2.0*dx ).xyz;
float3 c02 = tex2D(sSuper_xBR_P2, tc -dx +dy).xyz;
float3 c12 = tex2D(sSuper_xBR_P2, tc +dy).xyz;
float3 c22 = tex2D(sSuper_xBR_P2, tc +dx +dy).xyz;
float3 c32 = tex2D(sSuper_xBR_P2, tc+2.0*dx +dy).xyz;
float3 c03 = tex2D(sSuper_xBR_P2, tc -dx+2.0*dy).xyz;
float3 c13 = tex2D(sSuper_xBR_P2, tc +2.0*dy).xyz;
float3 c23 = tex2D(sSuper_xBR_P2, tc +dx+2.0*dy).xyz;
float3 c33 = tex2D(sSuper_xBR_P2, tc+2.0*dx+2.0*dy).xyz;
color = mul(weights[0], float4x3(c00, c10, c20, c30));
color+= mul(weights[1], float4x3(c01, c11, c21, c31));
color+= mul(weights[2], float4x3(c02, c12, c22, c32));
color+= mul(weights[3], float4x3(c03, c13, c23, c33));
color = color/(dot(mul(weights, float4(1.,1.,1.,1.)), float4(1.,1.,1.,1.)));
// Anti-ringing
// Get min/max samples
float3 min_sample = min4(c11, c21, c12, c22);
float3 max_sample = max4(c11, c21, c12, c22);
float3 aux = color;
color = clamp(color, min_sample, max_sample);
color = lerp(aux, color, JINC2_AR_STRENGTH);
return float4(color, 1.0);
}
technique Super_xBR
{
pass PS_BackBufferY
{
VertexShader = PostProcessVS;
PixelShader = BackBufferY;
RenderTarget = tBackBufferY;
}
pass PS_Super_xBR_P0
{
VertexShader = PostProcessVS;
PixelShader = Super_xBR_P0;
RenderTarget = tSuper_xBR_P0;
}
pass PS_Super_xBR_P1
{
VertexShader = PostProcessVS;
PixelShader = Super_xBR_P1;
RenderTarget = tSuper_xBR_P1;
}
pass PS_Super_xBR_P2
{
VertexShader = PostProcessVS;
PixelShader = Super_xBR_P2;
RenderTarget = tSuper_xBR_P2;
}
pass PS_Jinc2
{
VertexShader = PostProcessVS;
PixelShader = Jinc2;
}
}

View file

@ -0,0 +1,143 @@
#include "../ReShade.fxh"
/*
Bicubic multipass Shader
Copyright (C) 2011-2022 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
uniform int BICUBIC_FILTER <
ui_type = "combo";
ui_items = "Bicubic\0Catmull-Rom\0B-Spline\0Hermite\0";
ui_label = "Bicubic Filter";
ui_tooltip = "Bicubic: balanced. Catmull-Rom: sharp. B-Spline: blurred. Hermite: soft pixelized.";
> = 0;
uniform bool B_ANTI_RINGING <
ui_type = "radio";
ui_label = "Bicubic Anti-Ringing";
> = false;
uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >;
uniform float2 BufferToViewportRatio < source = "buffer_to_viewport_ratio"; >;
uniform float2 ViewportSize < source = "viewportsize"; >;
texture2D tBicubic_P0{Width=BUFFER_WIDTH;Height=BUFFER_HEIGHT;Format=RGBA8;};
sampler2D sBicubic_P0{Texture=tBicubic_P0;AddressU=CLAMP;AddressV=CLAMP;AddressW=CLAMP;MagFilter=POINT;MinFilter=POINT;};
#define AR_STRENGTH 1.0
// Classic Mitchell-Netravali bicubic parameters
float4x4 get_inv()
{
float bf = 1.0/3.0;
float cf = 1.0/3.0;
if (BICUBIC_FILTER == 1) {bf = 0.0; cf = 0.5;}
if (BICUBIC_FILTER == 2) {bf = 1.0; cf = 0.0;}
if (BICUBIC_FILTER == 3) {bf = 0.0; cf = 0.0;}
return float4x4( (-bf - 6.0*cf)/6.0, (3.0*bf + 12.0*cf)/6.0, (-3.0*bf - 6.0*cf)/6.0, bf/6.0,
(12.0 - 9.0*bf - 6.0*cf)/6.0, (-18.0 + 12.0*bf + 6.0*cf)/6.0, 0.0, (6.0 - 2.0*bf)/6.0,
-(12.0 - 9.0*bf - 6.0*cf)/6.0, (18.0 - 15.0*bf - 12.0*cf)/6.0, (3.0*bf + 6.0*cf)/6.0, bf/6.0,
(bf + 6.0*cf)/6.0, -cf, 0.0, 0.0);
}
float3 bicubic_ar(float fp, float3 C0, float3 C1, float3 C2, float3 C3)
{
float4 weights = mul(get_inv(), float4(fp*fp*fp, fp*fp, fp, 1.0));
float3 color = mul(weights, float4x3( C0, C1, C2, C3 ));
// Anti-ringing
if (B_ANTI_RINGING == true)
{
float3 aux = color;
float3 min_sample = min(min(C0, C1), min(C2, C3));
float3 max_sample = max(max(C0, C1), max(C2, C3));
color = clamp(color, min_sample, max_sample);
color = lerp(aux, color, step(0.0, (C0-C1)*(C2-C3)));
}
return color;
}
float4 Bicubic_X(float4 pos: SV_Position, float2 uv_tx : TEXCOORD) : SV_Target
{
// Both dimensions are unfiltered, so it looks for lores pixels.
float2 ps = NormalizedNativePixelSize;
float2 posi = uv_tx.xy + ps * float2(0.5, 0.0);
float2 fp = frac(posi / ps);
float2 tc = posi - (fp + 0.5) * ps;
float3 C0 = tex2D(ReShade::BackBuffer, tc + ps*float2(-1.0, 1.0)).rgb;
float3 C1 = tex2D(ReShade::BackBuffer, tc + ps*float2( 0.0, 1.0)).rgb;
float3 C2 = tex2D(ReShade::BackBuffer, tc + ps*float2( 1.0, 1.0)).rgb;
float3 C3 = tex2D(ReShade::BackBuffer, tc + ps*float2( 2.0, 1.0)).rgb;
float3 color = bicubic_ar(fp.x, C0, C1, C2, C3);
return float4(color, 1.0);
}
float4 Bicubic_Y(float4 pos: SV_Position, float2 uv_tx : TEXCOORD) : SV_Target
{
// One must be careful here. Horizontal dimension is already filtered, so it looks for x in hires.
float2 ps = float2(1.0/(ViewportSize.x*BufferToViewportRatio.x), NormalizedNativePixelSize.y);
float2 posi = uv_tx.xy + ps * float2(0.5, 0.5);
float2 fp = frac(posi / ps);
float2 tc = posi - (fp + 0.5) * ps;
float3 C0 = tex2D(sBicubic_P0, tc + ps*float2(1.0, -1.0)).rgb;
float3 C1 = tex2D(sBicubic_P0, tc + ps*float2(1.0, 0.0)).rgb;
float3 C2 = tex2D(sBicubic_P0, tc + ps*float2(1.0, 1.0)).rgb;
float3 C3 = tex2D(sBicubic_P0, tc + ps*float2(1.0, 2.0)).rgb;
float3 color = bicubic_ar(fp.y, C0, C1, C2, C3);
return float4(color, 1.0);
}
technique Bicubic
{
pass PS_Bicubic_X
{
VertexShader = PostProcessVS;
PixelShader = Bicubic_X;
RenderTarget = tBicubic_P0;
}
pass PS_Bicubic_Y
{
VertexShader = PostProcessVS;
PixelShader = Bicubic_Y;
}
}

View file

@ -0,0 +1,144 @@
#include "ReShade.fxh"
/*
Lanczos3 - Multipass code by Hyllian 2022.
*/
/*
Copyright (C) 2010 Team XBMC
http://www.xbmc.org
Copyright (C) 2011 Stefanos A.
http://www.opentk.com
This Program 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 2, or (at your option)
any later version.
This Program 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 XBMC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
http://www.gnu.org/copyleft/gpl.html
*/
uniform bool LANCZOS3_ANTI_RINGING <
ui_type = "radio";
ui_label = "Lanczos3 Anti-Ringing";
> = true;
uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >;
uniform float2 BufferToViewportRatio < source = "buffer_to_viewport_ratio"; >;
uniform float2 ViewportSize < source = "viewportsize"; >;
texture2D tLanczos3_P0{Width=BUFFER_WIDTH;Height=BUFFER_HEIGHT;Format=RGBA8;};
sampler2D sLanczos3_P0{Texture=tLanczos3_P0;AddressU=CLAMP;AddressV=CLAMP;AddressW=CLAMP;MagFilter=POINT;MinFilter=POINT;};
#define AR_STRENGTH 1.0
#define FIX(c) (max(abs(c),1e-5))
#define PI 3.1415926535897932384626433832795
#define radius 3.0
float3 weight3(float x)
{
float3 Sample = FIX(2.0 * PI * float3(x - 1.5, x - 0.5, x + 0.5));
// Lanczos3. Note: we normalize outside this function, so no point in multiplying by radius.
return sin(Sample) * sin(Sample / radius) / (Sample * Sample);
}
float3 lanczos3ar(float fp, float3 C0, float3 C1, float3 C2, float3 C3, float3 C4, float3 C5)
{
float3 w1 = weight3(0.5 - fp * 0.5);
float3 w2 = weight3(1.0 - fp * 0.5);
float sum = dot( w1, float3(1.,1.,1.)) + dot( w2, float3(1.,1.,1.));
w1 /= sum;
w2 /= sum;
float3 color = mul(w1, float3x3( C0, C2, C4 )) + mul(w2, float3x3( C1, C3, C5));
// Anti-ringing
if (LANCZOS3_ANTI_RINGING == true)
{
float3 aux = color;
float3 min_sample = min(min(C1, C2), min(C3, C4));
float3 max_sample = max(max(C1, C2), max(C3, C4));
color = clamp(color, min_sample, max_sample);
color = lerp(aux, color, AR_STRENGTH*step(0.0, (C1-C2)*(C3-C4)));
}
return color;
}
float4 Lanczos3_X(float4 pos: SV_Position, float2 uv_tx : TEXCOORD) : SV_Target
{
// Both dimensions are unfiltered, so it looks for lores pixels.
float2 ps = NormalizedNativePixelSize;
float2 posi = uv_tx.xy + ps * float2(0.5, 0.0);
float2 fp = frac(posi / ps);
float2 xystart = posi - (fp + 0.5) * ps;
float ypos = xystart.y + ps.y;
float3 C0 = tex2D(ReShade::BackBuffer, float2(xystart.x - ps.x * 2.0, ypos)).rgb;
float3 C1 = tex2D(ReShade::BackBuffer, float2(xystart.x - ps.x * 1.0, ypos)).rgb;
float3 C2 = tex2D(ReShade::BackBuffer, float2(xystart.x , ypos)).rgb;
float3 C3 = tex2D(ReShade::BackBuffer, float2(xystart.x + ps.x * 1.0, ypos)).rgb;
float3 C4 = tex2D(ReShade::BackBuffer, float2(xystart.x + ps.x * 2.0, ypos)).rgb;
float3 C5 = tex2D(ReShade::BackBuffer, float2(xystart.x + ps.x * 3.0, ypos)).rgb;
float3 color = lanczos3ar(fp.x, C0, C1, C2, C3, C4, C5);
return float4(color, 1.0);
}
float4 Lanczos3_Y(float4 pos: SV_Position, float2 uv_tx : TEXCOORD) : SV_Target
{
// One must be careful here. Horizontal dimension is already filtered, so it looks for x in hires.
float2 ps = float2(1.0/(ViewportSize.x*BufferToViewportRatio.x), NormalizedNativePixelSize.y);
float2 posi = uv_tx.xy + ps * float2(0.5, 0.5);
float2 fp = frac(posi / ps);
float2 xystart = posi - (fp + 0.5) * ps;
float xpos = xystart.x + ps.x;
float3 C0 = tex2D(sLanczos3_P0, float2(xpos, xystart.y - ps.y * 2.0)).rgb;
float3 C1 = tex2D(sLanczos3_P0, float2(xpos, xystart.y - ps.y * 1.0)).rgb;
float3 C2 = tex2D(sLanczos3_P0, float2(xpos, xystart.y )).rgb;
float3 C3 = tex2D(sLanczos3_P0, float2(xpos, xystart.y + ps.y * 1.0)).rgb;
float3 C4 = tex2D(sLanczos3_P0, float2(xpos, xystart.y + ps.y * 2.0)).rgb;
float3 C5 = tex2D(sLanczos3_P0, float2(xpos, xystart.y + ps.y * 3.0)).rgb;
float3 color = lanczos3ar(fp.y, C0, C1, C2, C3, C4, C5);
return float4(color, 1.0);
}
technique Lanczos3
{
pass PS_Lanczos3_X
{
VertexShader = PostProcessVS;
PixelShader = Lanczos3_X;
RenderTarget = tLanczos3_P0;
}
pass PS_Lanczos3_Y
{
VertexShader = PostProcessVS;
PixelShader = Lanczos3_Y;
}
}

View file

@ -0,0 +1,151 @@
#include "ReShade.fxh"
/*
Deblur-Luma Shader
Copyright (C) 2005 - 2024 guest(r) - guest.r@gmail.com
Luma adaptation by Hyllian
This program 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 2
of the License, or (at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
uniform float OFFSET <
ui_type = "drag";
ui_min = 0.25;
ui_max = 4.0;
ui_step = 0.25;
ui_label = "Deblur offset";
> = 2.0;
uniform float DEBLUR <
ui_type = "drag";
ui_min = 1.0;
ui_max = 7.0;
ui_step = 0.25;
ui_label = "Deblur str.";
> = 1.75;
uniform float SMART <
ui_type = "drag";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 0.05;
ui_label = "Smart deblur";
> = 1.0;
uniform float2 ViewportSize < source = "viewportsize"; >;
static const float3 luma = float3(0.299,0.587,0.114);
static const float4 res = float4(0.0001, 0.0001, 0.0001, 0.0001);
static const float4 uno = float4(1.,1.,1.,1.);
float min8(float4 a4, float4 b4)
{
float4 ab4 = min(a4, b4); float2 ab2 = min(ab4.xy, ab4.zw); return min(ab2.x, ab2.y);
}
float max8(float4 a4, float4 b4)
{
float4 ab4 = max(a4, b4); float2 ab2 = max(ab4.xy, ab4.zw); return max(ab2.x, ab2.y);
}
struct ST_VertexOut
{
float4 t1 : TEXCOORD1;
float4 t2 : TEXCOORD2;
float4 t3 : TEXCOORD3;
};
// Vertex shader generating a triangle covering the entire screen
void VS_Deblur_Luma(in uint id : SV_VertexID, out float4 position : SV_Position, out float2 texcoord : TEXCOORD, out ST_VertexOut vVARS)
{
texcoord.x = (id == 2) ? 2.0 : 0.0;
texcoord.y = (id == 1) ? 2.0 : 0.0;
position = float4(texcoord * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
float dx = OFFSET/ViewportSize.x;
float dy = OFFSET/ViewportSize.y;
vVARS.t1 = texcoord.xxxy + float4( -dx, 0.0, dx, -dy); // c00 c10 c20
vVARS.t2 = texcoord.xxxy + float4( -dx, 0.0, dx, 0.0); // c01 c11 c21
vVARS.t3 = texcoord.xxxy + float4( -dx, 0.0, dx, dy); // c02 c12 c22
}
float4 PS_Deblur_Luma(float4 vpos: SV_Position, float2 vTexCoord : TEXCOORD, in ST_VertexOut vVARS) : SV_Target
{
float3 c11 = tex2D(ReShade::BackBuffer, vVARS.t2.yw).xyz;
float3 c00 = tex2D(ReShade::BackBuffer, vVARS.t1.xw).xyz;
float3 c20 = tex2D(ReShade::BackBuffer, vVARS.t1.zw).xyz;
float3 c22 = tex2D(ReShade::BackBuffer, vVARS.t3.zw).xyz;
float3 c02 = tex2D(ReShade::BackBuffer, vVARS.t3.xw).xyz;
float3 c10 = tex2D(ReShade::BackBuffer, vVARS.t1.yw).xyz;
float3 c21 = tex2D(ReShade::BackBuffer, vVARS.t2.zw).xyz;
float3 c12 = tex2D(ReShade::BackBuffer, vVARS.t3.yw).xyz;
float3 c01 = tex2D(ReShade::BackBuffer, vVARS.t2.xw).xyz;
float4x3 chv = float4x3(c10, c01, c21, c12);
float4x3 cdi = float4x3(c00, c02, c20, c22);
float4 CHV = mul(chv, luma);
float4 CDI = mul(cdi, luma);
float C11 = dot(c11, luma);
float mn1 = min8(CHV, CDI);
float mx1 = max8(CHV, CDI);
float2 mnmx = float2(min(C11, mn1), max(C11, mx1));
float2 dif = abs(float2(C11, C11) - mnmx) + res.xy;
dif = pow(dif, float2(DEBLUR, DEBLUR));
float D11 = dot(dif, mnmx.yx)/(dif.x + dif.y);
float k11 = 1.0/(abs(C11 - D11) + res.x);
float4 khv = float4(1.0/(abs(CHV-float4(D11, D11, D11, D11)) + res));
float4 kdi = float4(1.0/(abs(CDI-float4(D11, D11, D11, D11)) + res));
float avg = (dot(khv + kdi, uno) + k11)/10.0;
khv = max(khv-float4(avg, avg, avg, avg), float4(0.0, 0.0, 0.0, 0.0));
kdi = max(kdi-float4(avg, avg, avg, avg), float4(0.0, 0.0, 0.0, 0.0));
k11 = max(k11-avg, 0.0);
float3 d11 = (mul(khv, chv) + mul(kdi, cdi) + (k11 + res.x)*c11) / (dot(khv + kdi, uno) + k11 + res.x);
float contrast = mnmx.y - mnmx.x;
c11 = lerp(c11, d11, clamp(1.75*contrast-0.125, 0.0, 1.0));
c11 = lerp(d11, c11, SMART);
return float4(c11, 1.0);
}
technique Deblur_Luma
{
pass
{
VertexShader = VS_Deblur_Luma;
PixelShader = PS_Deblur_Luma;
}
}

View file

@ -0,0 +1,367 @@
#include "ReShade.fxh"
/*
Geom Shader - a modified CRT-Geom without CRT features made to be appended/integrated
into any other shaders and provide curvature/warping/oversampling features.
Adapted by Hyllian (2024).
*/
/*
CRT-interlaced
Copyright (C) 2010-2012 cgwg, Themaister and DOLLS
This program 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 2 of the License, or (at your option)
any later version.
(cgwg gave their consent to have the original version of this shader
distributed under the GPL in this message:
http://board.byuu.org/viewtopic.php?p=26075#p26075
"Feel free to distribute my shaders under the GPL. After all, the
barrel distortion code was taken from the Curvature shader, which is
under the GPL."
)
This shader variant is pre-configured with screen curvature
*/
uniform float geom_curvature <
ui_type = "drag";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 1.0;
ui_label = "Geom Curvature Toggle";
> = 1.0;
uniform float geom_R <
ui_type = "drag";
ui_min = 0.1;
ui_max = 10.0;
ui_step = 0.1;
ui_label = "Geom Curvature Radius";
> = 2.0;
uniform float geom_d <
ui_type = "drag";
ui_min = 0.1;
ui_max = 3.0;
ui_step = 0.1;
ui_label = "Geom Distance";
> = 1.5;
uniform float geom_invert_aspect <
ui_type = "drag";
ui_min = 0.0;
ui_max = 1.0;
ui_step = 1.0;
ui_label = "Geom Curvature Aspect Inversion";
> = 0.0;
uniform float geom_cornersize <
ui_type = "drag";
ui_min = 0.001;
ui_max = 1.0;
ui_step = 0.005;
ui_label = "Geom Corner Size";
> = 0.03;
uniform float geom_cornersmooth <
ui_type = "drag";
ui_min = 80.0;
ui_max = 2000.0;
ui_step = 100.0;
ui_label = "Geom Corner Smoothness";
> = 1000.0;
uniform float geom_x_tilt <
ui_type = "drag";
ui_min = -0.5;
ui_max = 0.5;
ui_step = 0.05;
ui_label = "Geom Horizontal Tilt";
> = 0.0;
uniform float geom_y_tilt <
ui_type = "drag";
ui_min = -0.5;
ui_max = 0.5;
ui_step = 0.05;
ui_label = "Geom Vertical Tilt";
> = 0.0;
uniform float geom_overscan_x <
ui_type = "drag";
ui_min = -125.0;
ui_max = 125.0;
ui_step = 0.5;
ui_label = "Geom Horiz. Overscan %";
> = 100.0;
uniform float geom_overscan_y <
ui_type = "drag";
ui_min = -125.0;
ui_max = 125.0;
ui_step = 0.5;
ui_label = "Geom Vert. Overscan %";
> = 100.0;
uniform float geom_lum <
ui_type = "drag";
ui_min = 0.5;
ui_max = 2.0;
ui_step = 0.01;
ui_label = "Geom Luminance";
> = 1.0;
uniform float geom_target_gamma <
ui_type = "drag";
ui_min = 0.1;
ui_max = 5.0;
ui_step = 0.1;
ui_label = "Geom Target Gamma";
> = 2.4;
uniform float geom_monitor_gamma <
ui_type = "drag";
ui_min = 0.1;
ui_max = 5.0;
ui_step = 0.1;
ui_label = "Geom Monitor Gamma";
> = 2.2;
uniform float2 BufferViewportRatio < source = "buffer_to_viewport_ratio"; >;
uniform float2 NormalizedNativePixelSize < source = "normalized_native_pixel_size"; >;
uniform float2 ViewportSize < source = "viewportsize"; >;
// Comment the next line to disable interpolation in linear gamma (and
// gain speed).
#define LINEAR_PROCESSING
// Enable 3x oversampling of the beam profile; improves moire effect caused by scanlines+curvature
#define OVERSAMPLE
// Use the older, purely gaussian beam profile; uncomment for speed
//#define USEGAUSSIAN
// Macros.
#define FIX(c) max(abs(c), 1e-5);
#define PI 3.141592653589
#ifdef LINEAR_PROCESSING
# define TEX2D(c) pow(tex2D(ReShade::BackBuffer, (c)), float4(geom_target_gamma,geom_target_gamma,geom_target_gamma,geom_target_gamma))
#else
# define TEX2D(c) tex2D(ReShade::BackBuffer, (c))
#endif
// aspect ratio
#define aspect (geom_invert_aspect>0.5?float2(0.75,1.0):float2(1.0,0.75))
#define overscan (float2(1.01,1.01));
struct ST_VertexOut
{
float2 sinangle : TEXCOORD1;
float2 cosangle : TEXCOORD2;
float3 stretch : TEXCOORD3;
float2 TextureSize : TEXCOORD4;
};
float vs_intersect(float2 xy, float2 sinangle, float2 cosangle)
{
float A = dot(xy,xy) + geom_d*geom_d;
float B = 2.0*(geom_R*(dot(xy,sinangle)-geom_d*cosangle.x*cosangle.y)-geom_d*geom_d);
float C = geom_d*geom_d + 2.0*geom_R*geom_d*cosangle.x*cosangle.y;
return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
}
float2 vs_bkwtrans(float2 xy, float2 sinangle, float2 cosangle)
{
float c = vs_intersect(xy, sinangle, cosangle);
float2 point = (float2(c, c)*xy - float2(-geom_R, -geom_R)*sinangle) / float2(geom_R, geom_R);
float2 poc = point/cosangle;
float2 tang = sinangle/cosangle;
float A = dot(tang, tang) + 1.0;
float B = -2.0*dot(poc, tang);
float C = dot(poc, poc) - 1.0;
float a = (-B + sqrt(B*B - 4.0*A*C))/(2.0*A);
float2 uv = (point - a*sinangle)/cosangle;
float r = FIX(geom_R*acos(a));
return uv*r/sin(r/geom_R);
}
float2 vs_fwtrans(float2 uv, float2 sinangle, float2 cosangle)
{
float r = FIX(sqrt(dot(uv,uv)));
uv *= sin(r/geom_R)/r;
float x = 1.0-cos(r/geom_R);
float D = geom_d/geom_R + x*cosangle.x*cosangle.y+dot(uv,sinangle);
return geom_d*(uv*cosangle-x*sinangle)/D;
}
float3 vs_maxscale(float2 sinangle, float2 cosangle)
{
float2 c = vs_bkwtrans(-geom_R * sinangle / (1.0 + geom_R/geom_d*cosangle.x*cosangle.y), sinangle, cosangle);
float2 a = float2(0.5,0.5)*aspect;
float2 lo = float2(vs_fwtrans(float2(-a.x, c.y), sinangle, cosangle).x,
vs_fwtrans(float2( c.x, -a.y), sinangle, cosangle).y)/aspect;
float2 hi = float2(vs_fwtrans(float2(+a.x, c.y), sinangle, cosangle).x,
vs_fwtrans(float2( c.x, +a.y), sinangle, cosangle).y)/aspect;
return float3((hi+lo)*aspect*0.5,max(hi.x-lo.x,hi.y-lo.y));
}
// Vertex shader generating a triangle covering the entire screen
void VS_CRT_Geom(in uint id : SV_VertexID, out float4 position : SV_Position, out float2 texcoord : TEXCOORD, out ST_VertexOut vVARS)
{
texcoord.x = (id == 2) ? 2.0 : 0.0;
texcoord.y = (id == 1) ? 2.0 : 0.0;
position = float4(texcoord * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
// float2 SourceSize = 1.0/NormalizedNativePixelSize;
float2 SourceSize = ViewportSize*BufferViewportRatio;
// Precalculate a bunch of useful values we'll need in the fragment
// shader.
vVARS.sinangle = sin(float2(geom_x_tilt, geom_y_tilt));
vVARS.cosangle = cos(float2(geom_x_tilt, geom_y_tilt));
vVARS.stretch = vs_maxscale(vVARS.sinangle, vVARS.cosangle);
vVARS.TextureSize = float2(SourceSize.x, SourceSize.y);
}
float intersect(float2 xy, float2 sinangle, float2 cosangle)
{
float A = dot(xy,xy) + geom_d*geom_d;
float B, C;
B = 2.0*(geom_R*(dot(xy,sinangle) - geom_d*cosangle.x*cosangle.y) - geom_d*geom_d);
C = geom_d*geom_d + 2.0*geom_R*geom_d*cosangle.x*cosangle.y;
return (-B-sqrt(B*B - 4.0*A*C))/(2.0*A);
}
float2 bkwtrans(float2 xy, float2 sinangle, float2 cosangle)
{
float c = intersect(xy, sinangle, cosangle);
float2 point = (float2(c, c)*xy - float2(-geom_R, -geom_R)*sinangle) / float2(geom_R, geom_R);
float2 poc = point/cosangle;
float2 tang = sinangle/cosangle;
float A = dot(tang, tang) + 1.0;
float B = -2.0*dot(poc, tang);
float C = dot(poc, poc) - 1.0;
float a = (-B + sqrt(B*B - 4.0*A*C)) / (2.0*A);
float2 uv = (point - a*sinangle) / cosangle;
float r = FIX(geom_R*acos(a));
return uv*r/sin(r/geom_R);
}
float2 fwtrans(float2 uv, float2 sinangle, float2 cosangle)
{
float r = FIX(sqrt(dot(uv, uv)));
uv *= sin(r/geom_R)/r;
float x = 1.0 - cos(r/geom_R);
float D;
D = geom_d/geom_R + x*cosangle.x*cosangle.y + dot(uv,sinangle);
return geom_d*(uv*cosangle - x*sinangle)/D;
}
float3 maxscale(float2 sinangle, float2 cosangle)
{
float2 c = bkwtrans(-geom_R * sinangle / (1.0 + geom_R/geom_d*cosangle.x*cosangle.y), sinangle, cosangle);
float2 a = float2(0.5, 0.5)*aspect;
float2 lo = float2(fwtrans(float2(-a.x, c.y), sinangle, cosangle).x,
fwtrans(float2( c.x, -a.y), sinangle, cosangle).y)/aspect;
float2 hi = float2(fwtrans(float2(+a.x, c.y), sinangle, cosangle).x,
fwtrans(float2( c.x, +a.y), sinangle, cosangle).y)/aspect;
return float3((hi+lo)*aspect*0.5,max(hi.x-lo.x, hi.y-lo.y));
}
float2 transform(float2 coord, float2 sinangle, float2 cosangle, float3 stretch)
{
coord = (coord - float2(0.5, 0.5))*aspect*stretch.z + stretch.xy;
return (bkwtrans(coord, sinangle, cosangle) /
float2(geom_overscan_x / 100.0, geom_overscan_y / 100.0)/aspect + float2(0.5, 0.5));
}
float corner(float2 coord)
{
coord = (coord - float2(0.5, 0.5)) * float2(geom_overscan_x / 100.0, geom_overscan_y / 100.0) + float2(0.5, 0.5);
coord = min(coord, float2(1.0, 1.0) - coord) * aspect;
float2 cdist = float2(geom_cornersize, geom_cornersize);
coord = (cdist - min(coord, cdist));
float dist = sqrt(dot(coord, coord));
return clamp((cdist.x - dist)*geom_cornersmooth, 0.0, 1.0);
}
float fwidth(float value){
return abs(ddx(value)) + abs(ddy(value));
}
float4 PS_CRT_Geom(float4 vpos: SV_Position, float2 vTexCoord : TEXCOORD, in ST_VertexOut vVARS) : SV_Target
{
// Texture coordinates of the texel containing the active pixel.
float2 xy;
if (geom_curvature > 0.5)
xy = transform(vTexCoord, vVARS.sinangle, vVARS.cosangle, vVARS.stretch);
else
xy = vTexCoord;
float cval = corner(xy);
float2 uv_ratio = frac((xy * vVARS.TextureSize - float2(0.5, 0.5)) / vVARS.TextureSize);
float4 col = TEX2D(xy);
#ifndef LINEAR_PROCESSING
col = pow(col , float4(geom_target_gamma, geom_target_gamma, geom_target_gamma, geom_target_gamma));
#endif
col.rgb *= (geom_lum * step(0.0, uv_ratio.y));
float3 mul_res = col.rgb * float3(cval, cval, cval);
// Convert the image gamma for display on our output device.
mul_res = pow(mul_res, float3(1.0 / geom_monitor_gamma, 1.0 / geom_monitor_gamma, 1.0 / geom_monitor_gamma));
return float4(mul_res, 1.0);
}
technique CRT_Geom
{
pass
{
VertexShader = VS_CRT_Geom;
PixelShader = PS_CRT_Geom;
}
}

View file

@ -0,0 +1,75 @@
#include "ReShade.fxh"
// Multi-LUT Shader
// A simple shader that can load 2 LUTs.
// Can turn LUT off too.
uniform int LUT_selector <
ui_type = "combo";
ui_items = "Off\0Grade-RGB\0Grade-Composite\0";
ui_label = "LUT selector";
ui_tooltip = "Off: nothing. Grade-RGB: rgb trinitron colors. Grade-Composite: composite trinitron colors.";
> = 1;
texture tLUT1<source="../Textures/multi-LUT/grade-rgb.png";>{Width=1024;Height=32;};
sampler SamplerLUT1{Texture=tLUT1;};
texture tLUT2<source="../Textures/multi-LUT/grade-composite.png";>{Width=1024;Height=32;};
sampler SamplerLUT2{Texture=tLUT2;};
// 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
float4 mixfix(float4 a, float4 b, float c)
{
return (a.z < 1.0) ? lerp(a, b, c) : a;
}
float4 multiLUT(float4 vpos: SV_Position, float2 vTexCoord : TEXCOORD0) : SV_Target
{
float4 imgColor = tex2D(ReShade::BackBuffer, vTexCoord.xy);
if (LUT_selector > 0)
{
//float LUT_Size = lerp(textureSize(SamplerLUT1, 0).y, textureSize(SamplerLUT2, 0).y, LUT_selector_param - 1.0);
float LUT_Size = 32.0;
float4 color1, color2 = float4(0.,0.,0.,0.);
float red, green, blue1, blue2, mixer = 0.0;
red = ( imgColor.r * (LUT_Size - 1.0) + 0.4999 ) / (LUT_Size * LUT_Size);
green = ( imgColor.g * (LUT_Size - 1.0) + 0.4999 ) / LUT_Size;
blue1 = (floor( imgColor.b * (LUT_Size - 1.0) ) / LUT_Size) + red;
blue2 = (ceil( imgColor.b * (LUT_Size - 1.0) ) / LUT_Size) + red;
mixer = clamp(max((imgColor.b - blue1) / (blue2 - blue1), 0.0), 0.0, 32.0);
if(LUT_selector == 1)
{
color1 = tex2D(SamplerLUT1, float2( blue1, green ));
color2 = tex2D(SamplerLUT1, float2( blue2, green ));
}
else
{
color1 = tex2D(SamplerLUT2, float2( blue1, green ));
color2 = tex2D(SamplerLUT2, float2( blue2, green ));
}
imgColor = mixfix(color1, color2, mixer);
}
return imgColor;
}
technique multiLUT
{
pass PS_multiLUT
{
VertexShader = PostProcessVS;
PixelShader = multiLUT;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB