mirror of
https://github.com/italicsjenga/slang-shaders.git
synced 2024-11-22 15:51:30 +11:00
add crtsim shader
This commit is contained in:
parent
a8206e90d6
commit
46172167c9
22
crt/crtsim.slangp
Normal file
22
crt/crtsim.slangp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
shaders = 5
|
||||||
|
|
||||||
|
shader0 = shaders/crtsim/composite.slang
|
||||||
|
filter_linear0 = false
|
||||||
|
|
||||||
|
shader1 = shaders/crtsim/screen.slang
|
||||||
|
alias1 = CRTPASS
|
||||||
|
|
||||||
|
shader2 = shaders/crtsim/post-downsample.slang
|
||||||
|
filter_linear2 = true
|
||||||
|
|
||||||
|
shader3 = shaders/crtsim/post-upsample.slang
|
||||||
|
filter_linear3 = true
|
||||||
|
|
||||||
|
shader4 = shaders/crtsim/present.slang
|
||||||
|
filter_linear4 = true
|
||||||
|
|
||||||
|
textures = "NTSCArtifactSampler;shadowMaskSampler"
|
||||||
|
NTSCArtifactSampler = "shaders/crtsim/artifacts.png"
|
||||||
|
NTSCArtifactSampler_linear = true
|
||||||
|
shadowMaskSampler = "shaders/crtsim/mask.png"
|
||||||
|
shadowMaskSampler_linear = true
|
BIN
crt/shaders/crtsim/artifacts.png
Normal file
BIN
crt/shaders/crtsim/artifacts.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
153
crt/shaders/crtsim/composite.slang
Normal file
153
crt/shaders/crtsim/composite.slang
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// CC0 1.0 Universal (CC0 1.0)
|
||||||
|
// Public Domain Dedication
|
||||||
|
//
|
||||||
|
// To the extent possible under law, J. Kyle Pittman has waived all
|
||||||
|
// copyright and related or neighboring rights to this implementation
|
||||||
|
// of CRT simulation. This work is published from the United States.
|
||||||
|
//
|
||||||
|
// For more information, please visit
|
||||||
|
// https://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// This is the second step of the CRT simulation process,
|
||||||
|
// after the ntsc.fx shader has transformed the RGB values with a lookup table.
|
||||||
|
// This is where we apply effects "inside the screen," including spatial and temporal bleeding,
|
||||||
|
// an unsharp mask to simulate overshoot/undershoot, NTSC artifacts, and so on.
|
||||||
|
|
||||||
|
#define RcpScrWidth vec2(params.SourceSize.x, 0.0)
|
||||||
|
#define RcpScrHeight vec2(0.0, params.SourceSize.w)
|
||||||
|
|
||||||
|
layout(push_constant) uniform Push
|
||||||
|
{
|
||||||
|
vec4 SourceSize;
|
||||||
|
vec4 OriginalSize;
|
||||||
|
vec4 OutputSize;
|
||||||
|
uint FrameCount;
|
||||||
|
float Tuning_Sharp; // typically [0,1], defines the weighting of the sharpness taps
|
||||||
|
float Tuning_Persistence_R; // typically [0,1] per channel, defines the total blending of previous frame values
|
||||||
|
float Tuning_Persistence_G;
|
||||||
|
float Tuning_Persistence_B;
|
||||||
|
float Tuning_Bleed; // typically [0,1], defines the blending of L/R values with center value from prevous frame
|
||||||
|
float Tuning_Artifacts; // typically [0,1], defines the weighting of NTSC scanline artifacts (not physically accurate by any means)
|
||||||
|
float NTSCLerp; // Defines an interpolation between the two NTSC filter states. Typically would be 0 or 1 for vsynced 60 fps gameplay or 0.5 for unsynced, but can be whatever.
|
||||||
|
float NTSCArtifactScale;
|
||||||
|
float animate_artifacts;
|
||||||
|
} params;
|
||||||
|
|
||||||
|
#pragma parameter Tuning_Sharp "Composite Sharp" 0.2 0.0 1.0 0.05
|
||||||
|
#pragma parameter Tuning_Persistence_R "Red Persistence" 0.065 0.0 1.0 0.01
|
||||||
|
#pragma parameter Tuning_Persistence_G "Green Persistence" 0.05 0.0 1.0 0.01
|
||||||
|
#pragma parameter Tuning_Persistence_B "Blue Persistence" 0.05 0.0 1.0 0.01
|
||||||
|
#pragma parameter Tuning_Bleed "Composite Bleed" 0.5 0.0 1.0 0.05
|
||||||
|
#pragma parameter Tuning_Artifacts "Composite Artifacts" 0.5 0.0 1.0 0.05
|
||||||
|
#pragma parameter NTSCLerp "NTSC Artifacts" 1.0 0.0 1.0 1.0
|
||||||
|
#pragma parameter NTSCArtifactScale "NTSC Artifact Scale" 200.0 0.0 1000.0 5.0
|
||||||
|
#pragma parameter animate_artifacts "Animate NTSC Artifacts" 1.0 0.0 1.0 1.0
|
||||||
|
|
||||||
|
layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
|
{
|
||||||
|
mat4 MVP;
|
||||||
|
} global;
|
||||||
|
|
||||||
|
// Weight for applying an unsharp mask at a distance of 1, 2, or 3 pixels from changes in luma.
|
||||||
|
// The sign of each weight changes in order to alternately simulate overshooting and undershooting.
|
||||||
|
const float SharpWeight[3] =
|
||||||
|
{
|
||||||
|
1.0, -0.3162277, 0.1
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate luma for an RGB value.
|
||||||
|
float Brightness(vec4 InVal)
|
||||||
|
{
|
||||||
|
return dot(InVal, vec4(0.299, 0.587, 0.114, 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma stage vertex
|
||||||
|
// Passthrough vertex shader. Nothing interesting here.
|
||||||
|
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 PassFeedback0;
|
||||||
|
#define prevFrameSampler PassFeedback0
|
||||||
|
layout(set = 0, binding = 3) uniform sampler2D Source;
|
||||||
|
#define curFrameSampler Source
|
||||||
|
layout(set = 0, binding = 4) uniform sampler2D NTSCArtifactSampler;
|
||||||
|
|
||||||
|
#define lerp(a, b, c) mix(a, b, c)
|
||||||
|
#define tex2D(a, b) texture(a, b)
|
||||||
|
#define half4 vec4
|
||||||
|
#define half2 vec2
|
||||||
|
#define half float
|
||||||
|
#define saturate(c) clamp(c, 0.0, 1.0)
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
half2 scanuv = vec2(fract(vTexCoord * 1.0001 * params.SourceSize.xy / params.NTSCArtifactScale));
|
||||||
|
half4 NTSCArtifact1 = tex2D(NTSCArtifactSampler, scanuv);
|
||||||
|
half4 NTSCArtifact2 = tex2D(NTSCArtifactSampler, scanuv + vec2(0.0, 1.0 / params.SourceSize.y));
|
||||||
|
half4 NTSCArtifact = lerp(NTSCArtifact1, NTSCArtifact2, 1.0 - params.NTSCLerp);
|
||||||
|
|
||||||
|
float artifacting = (params.animate_artifacts > 0.5) ? mod(params.FrameCount, 2.0) : 1.0;
|
||||||
|
half2 LeftUV = vTexCoord - vec2(artifacting / params.SourceSize.x, 0.0);//RcpScrWidth;
|
||||||
|
half2 RightUV = vTexCoord + vec2(artifacting / params.SourceSize.x, 0.0);//RcpScrWidth;
|
||||||
|
|
||||||
|
half4 Cur_Left = tex2D(curFrameSampler, LeftUV);
|
||||||
|
half4 Cur_Local = tex2D(curFrameSampler, vTexCoord);
|
||||||
|
half4 Cur_Right = tex2D(curFrameSampler, RightUV);
|
||||||
|
|
||||||
|
half4 TunedNTSC = NTSCArtifact * params.Tuning_Artifacts;
|
||||||
|
|
||||||
|
// Note: The "persistence" and "bleed" parameters have some overlap, but they are not redundant.
|
||||||
|
// "Persistence" affects bleeding AND trails. (Scales the sum of the previous value and its scaled neighbors.)
|
||||||
|
// "Bleed" only affects bleeding. (Scaling of neighboring previous values.)
|
||||||
|
|
||||||
|
half4 Prev_Left = tex2D(prevFrameSampler, LeftUV);
|
||||||
|
half4 Prev_Local = tex2D(prevFrameSampler, vTexCoord);
|
||||||
|
half4 Prev_Right = tex2D(prevFrameSampler, RightUV);
|
||||||
|
|
||||||
|
// Apply NTSC artifacts based on differences in luma between local pixel and neighbors..
|
||||||
|
Cur_Local =
|
||||||
|
saturate(Cur_Local +
|
||||||
|
(((Cur_Left - Cur_Local) + (Cur_Right - Cur_Local)) * TunedNTSC));
|
||||||
|
|
||||||
|
half curBrt = Brightness(Cur_Local);
|
||||||
|
half offset = 0.;
|
||||||
|
|
||||||
|
// Step left and right looking for changes in luma that would produce a ring or halo on this pixel due to undershooting/overshooting.
|
||||||
|
// (Note: It would probably be more accurate to look at changes in luma between pixels at a distance of N and N+1,
|
||||||
|
// as opposed to 0 and N as done here, but this works pretty well and is a little cheaper.)
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
half2 StepSize = (half2(1.0/256.0,0) * (float(i + 1)));
|
||||||
|
half4 neighborleft = tex2D(curFrameSampler, vTexCoord - StepSize);
|
||||||
|
half4 neighborright = tex2D(curFrameSampler, vTexCoord + StepSize);
|
||||||
|
|
||||||
|
half NBrtL = Brightness(neighborleft);
|
||||||
|
half NBrtR = Brightness(neighborright);
|
||||||
|
offset += ((((curBrt - NBrtL) + (curBrt - NBrtR))) * SharpWeight[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the NTSC artifacts to the unsharp offset as well.
|
||||||
|
Cur_Local = saturate(Cur_Local + (offset * params.Tuning_Sharp * lerp(ivec4(1,1,1,1), NTSCArtifact, params.Tuning_Artifacts)));
|
||||||
|
|
||||||
|
vec4 Tuning_Persistence = vec4(params.Tuning_Persistence_R, params.Tuning_Persistence_G, params.Tuning_Persistence_B, 1.0);
|
||||||
|
// Take the max here because adding is overkill; bleeding should only brighten up dark areas, not blow out the whole screen.
|
||||||
|
Cur_Local = saturate(max(Cur_Local, Tuning_Persistence * (10.0 / (1.0 + (2.0 * params.Tuning_Bleed))) * (Prev_Local + ((Prev_Left + Prev_Right) * params.Tuning_Bleed))));
|
||||||
|
|
||||||
|
FragColor = vec4(Cur_Local);
|
||||||
|
}
|
70
crt/shaders/crtsim/crtbase.h
Normal file
70
crt/shaders/crtsim/crtbase.h
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
layout(push_constant) uniform Push
|
||||||
|
{
|
||||||
|
float CRTMask_Scale;
|
||||||
|
// float CRTMask_Offset_X;
|
||||||
|
// float CRTMask_Offset_Y;
|
||||||
|
// float Tuning_Overscan;
|
||||||
|
// float Tuning_Dimming;
|
||||||
|
float Tuning_Satur;
|
||||||
|
// float Tuning_ReflScalar;
|
||||||
|
// float Tuning_Barrel;
|
||||||
|
float Tuning_Mask_Brightness;
|
||||||
|
float Tuning_Mask_Opacity;
|
||||||
|
// float Tuning_Diff_Brightness;
|
||||||
|
// float Tuning_Spec_Brightness;
|
||||||
|
// float Tuning_Spec_Power;
|
||||||
|
// float Tuning_Fres_Brightness;
|
||||||
|
// float Tuning_LightPos_R;
|
||||||
|
// float Tuning_LightPos_G;
|
||||||
|
// float Tuning_LightPos_B;
|
||||||
|
} params;
|
||||||
|
|
||||||
|
#pragma parameter CRTMask_Scale "CRT Mask Scale" 1.0 0.0 10.0 0.5
|
||||||
|
//#pragma parameter CRTMask_Offset_X "CRT Mask Offset X" 0.0 0.0 1.0 0.05
|
||||||
|
//#pragma parameter CRTMask_Offset_Y "CRT Mask Offset Y" 0.0 0.0 1.0 0.05
|
||||||
|
//#pragma parameter Tuning_Overscan "Overscan" 0.95 0.0 1.0 0.05
|
||||||
|
//#pragma parameter Tuning_Dimming "Dimming" 0.0 0.0 1.0 0.05
|
||||||
|
#pragma parameter Tuning_Satur "Saturation" 1.0 0.0 1.0 0.05
|
||||||
|
//#pragma parameter Tuning_ReflScalar "Reflection" 0.0 0.0 1.0 0.05
|
||||||
|
//#pragma parameter Tuning_Barrel "Barrel Distortion" 0.25 0.0 1.0 0.05
|
||||||
|
#pragma parameter Tuning_Mask_Brightness "Mask Brightness" 0.5 0.0 1.0 0.05
|
||||||
|
#pragma parameter Tuning_Mask_Opacity "Mask Opacity" 0.3 0.0 1.0 0.05
|
||||||
|
//#pragma parameter Tuning_Diff_Brightness "Diff Brightness" 0.5 0.0 1.0 0.05
|
||||||
|
//#pragma parameter Tuning_Spec_Brightness "Spec Brightness" 0.5 0.0 1.0 0.05
|
||||||
|
//#pragma parameter Tuning_Fres_Brightness "Fres Brightness" 0.5 0.0 1.0 0.05
|
||||||
|
//#pragma parameter Tuning_LightPos_R "Light Position R" 1.0 0.0 1.0 0.05
|
||||||
|
//#pragma parameter Tuning_LightPos_G "Light Position G" 1.0 0.0 1.0 0.05
|
||||||
|
//#pragma parameter Tuning_LightPos_B "Light Position B" 1.0 0.0 1.0 0.05
|
||||||
|
|
||||||
|
#define CRTMask_Offset vec2(params.CRTMask_Offset_X, params.CRTMask_Offset_Y)
|
||||||
|
|
||||||
|
half4 SampleCRT(sampler2D shadowMaskSampler, sampler2D compFrameSampler, half2 uv)
|
||||||
|
{
|
||||||
|
half2 ScaledUV = uv;
|
||||||
|
// ScaledUV *= UVScalar;
|
||||||
|
// ScaledUV += UVOffset;
|
||||||
|
|
||||||
|
half2 scanuv = vec2(fract(uv * global.SourceSize.xy / params.CRTMask_Scale));
|
||||||
|
vec4 phosphor_grid;
|
||||||
|
half3 scantex = tex2D(shadowMaskSampler, scanuv).rgb;
|
||||||
|
|
||||||
|
scantex += params.Tuning_Mask_Brightness; // adding looks better
|
||||||
|
scantex = lerp(ivec3(1,1,1), scantex, params.Tuning_Mask_Opacity);
|
||||||
|
/* // commenting this to move to present shader
|
||||||
|
// Apply overscan after scanline sampling is done.
|
||||||
|
half2 overscanuv = (ScaledUV * params.Tuning_Overscan) - ((params.Tuning_Overscan - 1.0) * 0.5);
|
||||||
|
|
||||||
|
// Curve UVs for composite texture inwards to garble things a bit.
|
||||||
|
overscanuv = overscanuv - half2(0.5,0.5);
|
||||||
|
half rsq = (overscanuv.x*overscanuv.x) + (overscanuv.y*overscanuv.y);
|
||||||
|
overscanuv = overscanuv + (overscanuv * (params.Tuning_Barrel * rsq)) + half2(0.5,0.5);
|
||||||
|
*/
|
||||||
|
half2 overscanuv = uv;
|
||||||
|
half3 comptex = tex2D(compFrameSampler, overscanuv).rgb;
|
||||||
|
|
||||||
|
half4 emissive = half4(comptex * scantex, 1);
|
||||||
|
half desat = dot(half4(0.299, 0.587, 0.114, 0.0), emissive);
|
||||||
|
emissive = lerp(half4(desat,desat,desat,1), emissive, params.Tuning_Satur);
|
||||||
|
|
||||||
|
return emissive;
|
||||||
|
}
|
115
crt/shaders/crtsim/frame.slang
Normal file
115
crt/shaders/crtsim/frame.slang
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// CC0 1.0 Universal (CC0 1.0)
|
||||||
|
// Public Domain Dedication
|
||||||
|
//
|
||||||
|
// To the extent possible under law, J. Kyle Pittman has waived all
|
||||||
|
// copyright and related or neighboring rights to this implementation
|
||||||
|
// of CRT simulation. This work is published from the United States.
|
||||||
|
//
|
||||||
|
// For more information, please visit
|
||||||
|
// https://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define half4 vec4
|
||||||
|
#define half3 vec3
|
||||||
|
#define half2 vec2
|
||||||
|
#define half float
|
||||||
|
#define lerp(a, b, c) mix(a, b, c)
|
||||||
|
#define tex2D(a, b) texture(a, b)
|
||||||
|
#define mul(a, b) (b * a)
|
||||||
|
#define saturate(c) clamp(c, 0.0, 1.0)
|
||||||
|
|
||||||
|
layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
|
{
|
||||||
|
mat4 MVP;
|
||||||
|
vec4 SourceSize;
|
||||||
|
vec4 OriginalSize;
|
||||||
|
vec4 OutputSize;
|
||||||
|
uint FrameCount;
|
||||||
|
float FrameColor_R;
|
||||||
|
float FrameColor_G;
|
||||||
|
float FrameColor_B;
|
||||||
|
} global;
|
||||||
|
|
||||||
|
#pragma parameter FrameColor_R "Frame Color R" 1.0 0.0 1.0 0.05
|
||||||
|
#pragma parameter FrameColor_G "Frame Color G" 1.0 0.0 1.0 0.05
|
||||||
|
#pragma parameter FrameColor_B "Frame Color B" 1.0 0.0 1.0 0.05
|
||||||
|
|
||||||
|
#include "crtbase.h"
|
||||||
|
|
||||||
|
#pragma stage vertex
|
||||||
|
layout(location = 0) in vec4 Position;
|
||||||
|
layout(location = 1) in vec2 TexCoord;
|
||||||
|
layout(location = 0) out vec2 vTexCoord;
|
||||||
|
//layout(location = 1) out vec3 norm;
|
||||||
|
//layout(location = 2) out vec3 camDir;
|
||||||
|
//layout(location = 3) out vec3 lightDir;
|
||||||
|
//layout(location = 4) out float blend;
|
||||||
|
|
||||||
|
//mat4x4 wvpMat = global.MVP;
|
||||||
|
//mat4x4 worldMat = global.MVP;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = global.MVP * Position;
|
||||||
|
vTexCoord = TexCoord;
|
||||||
|
/*
|
||||||
|
// This is really unnecessary since it SHOULD always be identity, but whatever...
|
||||||
|
half3 worldPos = mul(half4(Position.xyz, 1.0), worldMat).xyz;
|
||||||
|
|
||||||
|
// Don't normalize this pre-pixel shader
|
||||||
|
camDir = camPos - worldPos;
|
||||||
|
lightDir = params.Tuning_LightPos - worldPos;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma stage fragment
|
||||||
|
layout(location = 0) in vec2 vTexCoord;
|
||||||
|
//layout(location = 1) in vec3 norm;
|
||||||
|
//layout(location = 2) in vec3 camDir;
|
||||||
|
//layout(location = 3) in vec3 lightDir;
|
||||||
|
//layout(location = 4) in float blend;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
layout(set = 0, binding = 2) uniform sampler2D Source;
|
||||||
|
layout(set = 0, binding = 3) uniform sampler2D shadowMaskSampler;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
half3 norm = normalize(norm);
|
||||||
|
|
||||||
|
half3 camDir = normalize(camDir);
|
||||||
|
half3 lightDir = normalize(lightDir);
|
||||||
|
|
||||||
|
half diffuse = saturate(dot(norm, lightDir));
|
||||||
|
|
||||||
|
half3 worldUp = half3(0.,0.,1.);
|
||||||
|
half hemi = dot(norm, worldUp) * 0.5 + 0.5;
|
||||||
|
hemi = hemi * 0.4 + 0.3; // [0.3,0.7] range
|
||||||
|
|
||||||
|
vec4 Tuning_FrameColor = vec4(global.FrameColor_R, global.FrameColor_G, global.FrameColor_B, 1.0);
|
||||||
|
half4 colordiff = Tuning_FrameColor * (diffuse + hemi) * params.Tuning_Diff_Brightness;
|
||||||
|
|
||||||
|
half3 halfVec = normalize(lightDir + camDir);
|
||||||
|
half spec = saturate(dot(norm, halfVec));
|
||||||
|
spec = pow(spec, Tuning_Spec_Power);
|
||||||
|
half4 colorspec = half4(0.25, 0.25, 0.25, 1.) * spec * params.Tuning_Spec_Brightness;
|
||||||
|
|
||||||
|
half4 emissive = SampleCRT(shadowMaskSampler, Source, vTexCoord);
|
||||||
|
|
||||||
|
colorspec += (emissive * blend * Tuning_ReflScalar);
|
||||||
|
|
||||||
|
half fres = 1.0 - dot(camDir, norm);
|
||||||
|
fres = (fres*fres) * Tuning_Fres_Brightness;
|
||||||
|
half4 colorfres = half4(0.15, 0.15, 0.15, 1.) * fres;
|
||||||
|
|
||||||
|
half4 nearfinal = (colorfres + colordiff + colorspec);
|
||||||
|
|
||||||
|
FragColor = (nearfinal * lerp(ivec4(1,1,1,1), color, Tuning_Dimming));
|
||||||
|
*/
|
||||||
|
FragColor = vec4(SampleCRT(shadowMaskSampler, Source, vTexCoord));
|
||||||
|
}
|
BIN
crt/shaders/crtsim/mask.png
Normal file
BIN
crt/shaders/crtsim/mask.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
86
crt/shaders/crtsim/post-downsample.slang
Normal file
86
crt/shaders/crtsim/post-downsample.slang
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// CC0 1.0 Universal (CC0 1.0)
|
||||||
|
// Public Domain Dedication
|
||||||
|
//
|
||||||
|
// To the extent possible under law, J. Kyle Pittman has waived all
|
||||||
|
// copyright and related or neighboring rights to this implementation
|
||||||
|
// of CRT simulation. This work is published from the United States.
|
||||||
|
//
|
||||||
|
// For more information, please visit
|
||||||
|
// https://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Multi-purpose code used for both downsampling and upsampling the full-resolution output image.
|
||||||
|
|
||||||
|
layout(push_constant) uniform Push
|
||||||
|
{
|
||||||
|
vec4 SourceSize;
|
||||||
|
vec4 OriginalSize;
|
||||||
|
vec4 OutputSize;
|
||||||
|
uint FrameCount;
|
||||||
|
float bloom_scale_down;
|
||||||
|
} params;
|
||||||
|
|
||||||
|
#pragma parameter bloom_scale_down "Downsample Bloom Scale" 0.015 0.0 0.03 0.001
|
||||||
|
|
||||||
|
layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
|
{
|
||||||
|
mat4 MVP;
|
||||||
|
} global;
|
||||||
|
|
||||||
|
#define half4 vec4
|
||||||
|
#define half3 vec3
|
||||||
|
#define half2 vec2
|
||||||
|
#define half float
|
||||||
|
#define float2 vec2
|
||||||
|
#define lerp(a, b, c) mix(a, b, c)
|
||||||
|
#define tex2D(a, b) texture(a, b)
|
||||||
|
#define mul(a, b) (b * a)
|
||||||
|
#define saturate(c) clamp(c, 0.0, 1.0)
|
||||||
|
|
||||||
|
const float2 Poisson0 = float2(0.000000, 0.000000);
|
||||||
|
const float2 Poisson1 = float2(0.000000, 1.000000);
|
||||||
|
const float2 Poisson2 = float2(0.000000, -1.000000);
|
||||||
|
const float2 Poisson3 = float2(-0.866025, 0.500000);
|
||||||
|
const float2 Poisson4 = float2(-0.866025, -0.500000);
|
||||||
|
const float2 Poisson5 = float2(0.866025, 0.500000);
|
||||||
|
const float2 Poisson6 = float2(0.866025, -0.500000);
|
||||||
|
|
||||||
|
const float InvNumSamples = 0.1428571428571429; //<- 1.0 / number of Poisson samples
|
||||||
|
|
||||||
|
#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 Original;
|
||||||
|
#define PreBloomBufferSampler Original
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 bloom = vec4(0.0);
|
||||||
|
vec2 BloomScale = vec2(params.bloom_scale_down);
|
||||||
|
bloom += tex2D(PreBloomBufferSampler, vTexCoord + (Poisson0 * BloomScale));
|
||||||
|
bloom += tex2D(PreBloomBufferSampler, vTexCoord + (Poisson1 * BloomScale));
|
||||||
|
bloom += tex2D(PreBloomBufferSampler, vTexCoord + (Poisson2 * BloomScale));
|
||||||
|
bloom += tex2D(PreBloomBufferSampler, vTexCoord + (Poisson3 * BloomScale));
|
||||||
|
bloom += tex2D(PreBloomBufferSampler, vTexCoord + (Poisson4 * BloomScale));
|
||||||
|
bloom += tex2D(PreBloomBufferSampler, vTexCoord + (Poisson5 * BloomScale));
|
||||||
|
bloom += tex2D(PreBloomBufferSampler, vTexCoord + (Poisson6 * BloomScale));
|
||||||
|
bloom *= InvNumSamples;
|
||||||
|
|
||||||
|
FragColor = vec4(bloom);
|
||||||
|
}
|
86
crt/shaders/crtsim/post-upsample.slang
Normal file
86
crt/shaders/crtsim/post-upsample.slang
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// CC0 1.0 Universal (CC0 1.0)
|
||||||
|
// Public Domain Dedication
|
||||||
|
//
|
||||||
|
// To the extent possible under law, J. Kyle Pittman has waived all
|
||||||
|
// copyright and related or neighboring rights to this implementation
|
||||||
|
// of CRT simulation. This work is published from the United States.
|
||||||
|
//
|
||||||
|
// For more information, please visit
|
||||||
|
// https://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Multi-purpose code used for both downsampling and upsampling the full-resolution output image.
|
||||||
|
|
||||||
|
layout(push_constant) uniform Push
|
||||||
|
{
|
||||||
|
vec4 SourceSize;
|
||||||
|
vec4 OriginalSize;
|
||||||
|
vec4 OutputSize;
|
||||||
|
uint FrameCount;
|
||||||
|
float bloom_scale_up;
|
||||||
|
} params;
|
||||||
|
|
||||||
|
#pragma parameter bloom_scale_up "Upsample Bloom Scale" 0.02 0.0 0.03 0.001
|
||||||
|
|
||||||
|
layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
|
{
|
||||||
|
mat4 MVP;
|
||||||
|
} global;
|
||||||
|
|
||||||
|
#define half4 vec4
|
||||||
|
#define half3 vec3
|
||||||
|
#define half2 vec2
|
||||||
|
#define half float
|
||||||
|
#define float2 vec2
|
||||||
|
#define lerp(a, b, c) mix(a, b, c)
|
||||||
|
#define tex2D(a, b) texture(a, b)
|
||||||
|
#define mul(a, b) (b * a)
|
||||||
|
#define saturate(c) clamp(c, 0.0, 1.0)
|
||||||
|
|
||||||
|
const float2 Poisson0 = float2(0.000000, 0.000000);
|
||||||
|
const float2 Poisson1 = float2(0.000000, 1.000000);
|
||||||
|
const float2 Poisson2 = float2(0.000000, -1.000000);
|
||||||
|
const float2 Poisson3 = float2(-0.866025, 0.500000);
|
||||||
|
const float2 Poisson4 = float2(-0.866025, -0.500000);
|
||||||
|
const float2 Poisson5 = float2(0.866025, 0.500000);
|
||||||
|
const float2 Poisson6 = float2(0.866025, -0.500000);
|
||||||
|
|
||||||
|
const float InvNumSamples = 0.1428571428571429; //<- 1.0 / number of Poisson samples
|
||||||
|
|
||||||
|
#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 Source;
|
||||||
|
#define DownsampleBufferSampler Source
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 bloom = vec4(0.0);
|
||||||
|
vec2 BloomScale = vec2(params.bloom_scale_up);
|
||||||
|
bloom += tex2D(DownsampleBufferSampler, vTexCoord + (Poisson0.yx * BloomScale));
|
||||||
|
bloom += tex2D(DownsampleBufferSampler, vTexCoord + (Poisson1.yx * BloomScale));
|
||||||
|
bloom += tex2D(DownsampleBufferSampler, vTexCoord + (Poisson2.yx * BloomScale));
|
||||||
|
bloom += tex2D(DownsampleBufferSampler, vTexCoord + (Poisson3.yx * BloomScale));
|
||||||
|
bloom += tex2D(DownsampleBufferSampler, vTexCoord + (Poisson4.yx * BloomScale));
|
||||||
|
bloom += tex2D(DownsampleBufferSampler, vTexCoord + (Poisson5.yx * BloomScale));
|
||||||
|
bloom += tex2D(DownsampleBufferSampler, vTexCoord + (Poisson6.yx * BloomScale));
|
||||||
|
bloom *= InvNumSamples;
|
||||||
|
|
||||||
|
FragColor = vec4(bloom);
|
||||||
|
}
|
100
crt/shaders/crtsim/present.slang
Normal file
100
crt/shaders/crtsim/present.slang
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// CC0 1.0 Universal (CC0 1.0)
|
||||||
|
// Public Domain Dedication
|
||||||
|
//
|
||||||
|
// To the extent possible under law, J. Kyle Pittman has waived all
|
||||||
|
// copyright and related or neighboring rights to this implementation
|
||||||
|
// of CRT simulation. This work is published from the United States.
|
||||||
|
//
|
||||||
|
// For more information, please visit
|
||||||
|
// https://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Blends the original full-resolution scene with the blurred output of post shaders to create bloom.
|
||||||
|
|
||||||
|
#pragma parameter BloomPower "Bloom Power" 1.0 0.0 10.0 0.1
|
||||||
|
#pragma parameter BloomScalar "Bloom Scalar" 0.1 0.0 1.0 0.05
|
||||||
|
|
||||||
|
#pragma parameter Tuning_Overscan "Overscan" 0.95 0.0 1.0 0.05
|
||||||
|
#pragma parameter Tuning_Barrel "Barrel Distortion" 0.25 0.0 1.0 0.05
|
||||||
|
#pragma parameter mask_toggle "Mask Toggle" 1.0 0.0 1.0 1.0
|
||||||
|
//#pragma parameter mixfactor "Bloom Mix" 0.5 0.0 1.0 0.05
|
||||||
|
|
||||||
|
layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
|
{
|
||||||
|
mat4 MVP;
|
||||||
|
vec4 SourceSize;
|
||||||
|
vec4 OriginalSize;
|
||||||
|
vec4 OutputSize;
|
||||||
|
uint FrameCount;
|
||||||
|
float BloomPower;
|
||||||
|
float BloomScalar;
|
||||||
|
float Tuning_Overscan;
|
||||||
|
float Tuning_Barrel;
|
||||||
|
float mask_toggle;
|
||||||
|
// float mixfactor;
|
||||||
|
} global;
|
||||||
|
|
||||||
|
#define half4 vec4
|
||||||
|
#define half3 vec3
|
||||||
|
#define half2 vec2
|
||||||
|
#define half float
|
||||||
|
#define lerp(a, b, c) mix(a, b, c)
|
||||||
|
#define tex2D(a, b) texture(a, b)
|
||||||
|
#define mul(a, b) (b * a)
|
||||||
|
#define saturate(c) clamp(c, 0.0, 1.0)
|
||||||
|
|
||||||
|
#include "crtbase.h"
|
||||||
|
|
||||||
|
// Apply power to brightness while preserving color
|
||||||
|
// TODO: Clamp ActLuma to very small number to prevent (zero) division by zero when a component is zero?
|
||||||
|
half4 ColorPow(half4 InColor, half InPower)
|
||||||
|
{
|
||||||
|
// This method preserves color better.
|
||||||
|
half4 RefLuma = half4(0.299, 0.587, 0.114, 0.0);
|
||||||
|
half ActLuma = dot(InColor, RefLuma);
|
||||||
|
half4 ActColor = InColor / ActLuma;
|
||||||
|
half PowLuma = pow(ActLuma, InPower);
|
||||||
|
half4 PowColor = ActColor * PowLuma;
|
||||||
|
return PowColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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 Source;
|
||||||
|
layout(set = 0, binding = 3) uniform sampler2D CRTPASS;
|
||||||
|
layout(set = 0, binding = 4) uniform sampler2D shadowMaskSampler;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Apply overscan after scanline sampling is done.
|
||||||
|
half2 overscanuv = (vTexCoord * global.Tuning_Overscan) - ((global.Tuning_Overscan - 1.0) * 0.5);
|
||||||
|
|
||||||
|
// Curve UVs for composite texture inwards to garble things a bit.
|
||||||
|
overscanuv = overscanuv - half2(0.5,0.5);
|
||||||
|
half rsq = (overscanuv.x*overscanuv.x) + (overscanuv.y*overscanuv.y);
|
||||||
|
overscanuv = overscanuv + (overscanuv * (global.Tuning_Barrel * rsq)) + half2(0.5,0.5);
|
||||||
|
vec4 PreBloom = vec4(0.0);
|
||||||
|
// Mask effect cancels curvature due to righteous moire
|
||||||
|
overscanuv = (global.mask_toggle > 0.5) ? vTexCoord : overscanuv;
|
||||||
|
PreBloom = (global.mask_toggle > 0.5) ? SampleCRT(shadowMaskSampler, CRTPASS, overscanuv) : texture(CRTPASS, overscanuv);
|
||||||
|
|
||||||
|
vec4 Blurred = texture(Source, overscanuv);
|
||||||
|
FragColor = vec4(PreBloom + (ColorPow(Blurred, global.BloomPower) * global.BloomScalar));//vec4(mix(PreBloom, Blurred, global.mixfactor));
|
||||||
|
}
|
100
crt/shaders/crtsim/screen.slang
Normal file
100
crt/shaders/crtsim/screen.slang
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// CC0 1.0 Universal (CC0 1.0)
|
||||||
|
// Public Domain Dedication
|
||||||
|
//
|
||||||
|
// To the extent possible under law, J. Kyle Pittman has waived all
|
||||||
|
// copyright and related or neighboring rights to this implementation
|
||||||
|
// of CRT simulation. This work is published from the United States.
|
||||||
|
//
|
||||||
|
// For more information, please visit
|
||||||
|
// https://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define half4 vec4
|
||||||
|
#define half3 vec3
|
||||||
|
#define half2 vec2
|
||||||
|
#define half float
|
||||||
|
#define lerp(a, b, c) mix(a, b, c)
|
||||||
|
#define tex2D(a, b) texture(a, b)
|
||||||
|
#define mul(a, b) (b * a)
|
||||||
|
#define saturate(c) clamp(c, 0.0, 1.0)
|
||||||
|
|
||||||
|
layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
|
{
|
||||||
|
mat4 MVP;
|
||||||
|
vec4 SourceSize;
|
||||||
|
vec4 OriginalSize;
|
||||||
|
vec4 OutputSize;
|
||||||
|
uint FrameCount;
|
||||||
|
} global;
|
||||||
|
|
||||||
|
#include "crtbase.h"
|
||||||
|
|
||||||
|
#pragma stage vertex
|
||||||
|
layout(location = 0) in vec4 Position;
|
||||||
|
layout(location = 1) in vec2 TexCoord;
|
||||||
|
layout(location = 0) out vec2 vTexCoord;
|
||||||
|
//layout(location = 1) out vec3 norm;
|
||||||
|
//layout(location = 2) out vec3 camDir;
|
||||||
|
//layout(location = 3) out vec3 lightDir;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = global.MVP * Position;
|
||||||
|
vTexCoord = TexCoord;
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Going head and getting this stuff ready but not hooking anything up yet
|
||||||
|
mat3x3 wMat3 = mat3x3(worldMat[0].xyz, worldMat[1].xyz, worldMat[2].xyz);
|
||||||
|
mat3x3 invWorldRot = transpose(wMat3);
|
||||||
|
|
||||||
|
// Don't normalize this pre-pixel shader
|
||||||
|
camDir = mul(camPos - worldPos, invWorldRot);
|
||||||
|
vec3 Tuning_lightPos = vec3(params.Tuning_lightPos_R, params.Tuning_lightPos_G, params.Tuning_lightPos_B);
|
||||||
|
lightDir = mul(Tuning_LightPos - worldPos, invWorldRot)
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma stage fragment
|
||||||
|
layout(location = 0) in vec2 vTexCoord;
|
||||||
|
//layout(location = 1) in vec3 norm;
|
||||||
|
//layout(location = 2) in vec3 camDir;
|
||||||
|
//layout(location = 3) in vec3 lightDir;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
layout(set = 0, binding = 2) uniform sampler2D Source;
|
||||||
|
layout(set = 0, binding = 3) uniform sampler2D shadowMaskSampler;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
half3 norm = normalize(norm);
|
||||||
|
|
||||||
|
half3 camDir = normalize(camDir);
|
||||||
|
half3 lightDir = normalize(lightDir);
|
||||||
|
|
||||||
|
half3 refl = reflect(camDir, norm);
|
||||||
|
|
||||||
|
half diffuse = saturate(dot(norm, lightDir));
|
||||||
|
half4 colordiff = half4(0.175, 0.15, 0.2, 1.) * diffuse * params.Tuning_Diff_Brightness;
|
||||||
|
|
||||||
|
half3 halfVec = normalize(lightDir + camDir);
|
||||||
|
half spec = saturate(dot(norm, halfVec));
|
||||||
|
spec = pow(spec, params.Tuning_Spec_Power);
|
||||||
|
half4 colorspec = half4(0.25, 0.25, 0.25, 1.) * spec * params.Tuning_Spec_Brightness;
|
||||||
|
|
||||||
|
half fres = 1.0 - dot(camDir, norm);
|
||||||
|
fres = (fres*fres) * params.Tuning_Fres_Brightness;
|
||||||
|
half4 colorfres = half4(0.45, 0.4, 0.5, 1.) * fres;
|
||||||
|
|
||||||
|
half4 emissive = SampleCRT(shadowMaskSampler, Source, vTexCoord);
|
||||||
|
|
||||||
|
half4 nearfinal = colorfres + colordiff + colorspec + emissive;
|
||||||
|
|
||||||
|
FragColor = (nearfinal * lerp(ivec4(1,1,1,1), color, params.Tuning_Dimming)); //TODO: not sure what 'color' would be here
|
||||||
|
*/
|
||||||
|
FragColor = vec4(SampleCRT(shadowMaskSampler, Source, vTexCoord));
|
||||||
|
}
|
Loading…
Reference in a new issue