update crt-guest-dr-venom

This commit is contained in:
hunterk 2019-05-03 12:31:31 -05:00
parent b340d6cee3
commit 96c592851a
22 changed files with 1874 additions and 273 deletions

View file

@ -0,0 +1,40 @@
shaders = 5
shader0 = shaders/guest/lut/lut.slang
filter_linear0 = false
scale_type0 = source
scale0 = 1.0
textures = "SamplerLUT1;SamplerLUT2;SamplerLUT3"
SamplerLUT1 = shaders/guest/lut/sony_trinitron1.png
SamplerLUT1_linear = true
SamplerLUT2 = shaders/guest/lut/sony_trinitron2.png
SamplerLUT2_linear = true
SamplerLUT3 = shaders/guest/lut/other1.png
SamplerLUT3_linear = true
shader1 = shaders/guest/fast/smoothing.slang
filter_linear1 = false
scale_type1 = source
scale1 = 1.0
alias1 = SmoothPass
shader2 = shaders/guest/fast/linearize-multipass.slang
filter_linear2 = false
scale_type2 = source
scale2 = 1.0
float_framebuffer2 = true
shader3 = shaders/guest/fast/crt-guest-dr-venom-pass1.slang
filter_linear3 = false
scale_type_x3 = viewport
scale_x3 = 1.0
scale_type_y3 = source
scale_y3 = 1.0
float_framebuffer3 = true
shader4 = shaders/guest/fast/crt-guest-dr-venom-pass2.slang
filter_linear4 = false
scale_type4 = viewport
scale_x4 = 1.0
scale_y4 = 1.0

View file

@ -1,43 +1,68 @@
shaders = 7 shaders = 10
shader0 = shaders/guest/afterglow.slang shader0 = shaders/guest/lut/lut.slang
filter_linear0 = false filter_linear0 = false
scale_type0 = source scale_type0 = source
scale0 = 1.0 scale0 = 1.0
shader1 = shaders/guest/d65-d50.slang textures = "SamplerLUT1;SamplerLUT2;SamplerLUT3"
SamplerLUT1 = shaders/guest/lut/sony_trinitron1.png
SamplerLUT1_linear = true
SamplerLUT2 = shaders/guest/lut/sony_trinitron2.png
SamplerLUT2_linear = true
SamplerLUT3 = shaders/guest/lut/other1.png
SamplerLUT3_linear = true
shader1 = shaders/guest/color-profiles.slang
filter_linear1 = false filter_linear1 = false
scale_type1 = source scale_type1 = source
scale1 = 1.0 scale1 = 1.0
alias1 = temp_pass
shader2 = shaders/guest/avg-lum.slang shader2 = shaders/guest/d65-d50.slang
filter_linear2 = false filter_linear2 = false
scale_type2 = source scale_type2 = source
scale2 = 1.0 scale2 = 1.0
mipmap_input2 = true alias2 = WhitePointPass
alias2 = lum_pass
shader3 = shaders/guest/linearize.slang shader3 = shaders/guest/afterglow.slang
filter_linear3 = false filter_linear3 = false
scale_type3 = source scale_type3 = source
scale3 = 1.0 scale3 = 1.0
float_framebuffer3 = true alias3 = AfterglowPass
alias3 = linearize_pass
shader4 = shaders/guest/blur_horiz.slang shader4 = shaders/guest/avg-lum0.slang
filter_linear4 = false filter_linear4 = false
scale_type4 = source scale_type4 = source
scale4 = 1.0 scale4 = 1.0
float_framebuffer4 = true
shader5 = shaders/guest/blur_vert.slang shader5 = shaders/guest/avg-lum.slang
filter_linear5 = false filter_linear5 = false
scale_type5 = source scale_type5 = source
scale5 = 1.0 scale5 = 1.0
float_framebuffer5 = true mipmap_input5 = true
alias5 = AvgLumPass
shader6 = shaders/guest/crt-guest-dr-venom.slang shader6 = shaders/guest/linearize.slang
filter_linear6 = true filter_linear6 = false
scale_type6 = viewport scale_type6 = source
scale6 = 1.0 scale6 = 1.0
float_framebuffer6 = true
alias6 = LinearizePass
shader7 = shaders/guest/blur_horiz.slang
filter_linear7 = false
scale_type7 = source
scale7 = 1.0
float_framebuffer7 = true
shader8 = shaders/guest/blur_vert.slang
filter_linear8 = false
scale_type8 = source
scale8 = 1.0
float_framebuffer8 = true
shader9 = shaders/guest/crt-guest-dr-venom.slang
filter_linear9 = true
scale_type9 = viewport
scale_x9 = 1.0
scale_y9 = 1.0

365
crt/shaders/guest/README Normal file
View file

@ -0,0 +1,365 @@
____ ____ _____ ____ _ ____ __ __
/ ___| _ \_ _| / ___|_ _ ___ ___| |_ | _ \ _ _\ \ / /__ _ __ ___ _ __ ___
| | | |_) || |_____| | _| | | |/ _ \/ __| __|____| | | | '__\ \ / / _ \ '_ \ / _ \| '_ ` _ \
| |___| _ < | |_____| |_| | |_| | __/\__ \ ||_____| |_| | |_ \ V / __/ | | | (_) | | | | | |
\____|_| \_\|_| \____|\__,_|\___||___/\__| |____/|_(_) \_/ \___|_| |_|\___/|_| |_| |_|
CRT - Guest - Dr.Venom
Copyright (C) 2018-2019 guest(r) - guest.r@gmail.com
Incorporates many good ideas and suggestions from Dr.Venom.
This guide: Rev 1, April 28th 2019
----------------
# Introduction #
----------------
This shader mimics the look of Cathode Ray Tubes (CRTs) on modern LCD monitors.
Its main goal is to be accurate out of the box, and keep plenty of customization options for the CRT purists to tinker with. That's you if you're reading this :)
Since the range of shader parameters can be a bit overwhelming we've created this little readme to explain some of the options.
If you have questions, please don't hesitate to reach out to us!
Most of the stuff in this guide has been discussed on English Amiga Board here: http://eab.abime.net/showthread.php?t=95969&page=2
--------------
# Afterglow #
--------------
The RGB phosphors in CRTs have a decay time when going from fully lit to off. When going from bright lit status to off the luminance level instantly falls to about 10%, but then tend to linger at that level for a bit. This is what we call "afterglow". This afterglow of phosphors causes slightly visible trails when bright objects are moving fast on a dark background.
For an example of this "CRT phosphor afterglowing" see this video on youtube: https://youtu.be/N72uiXFgrh0
If you look at the UFO flying by from second 13 to 18 you can clearly see the trail in motion. In the video it looks slightly exaggerated because of the way cameras work.
The shader allows to control the strength of afterglow per Red, Green, Blue "phospors". Generally the blue phosphor has the least afterglow, so you may want to have red and green a bit stronger than blue.
Afterglow switch ON/OFF // Turn afterglow feature ON/OFF
Afterglow Red (more is more) // controls the initial brightness of the afterglow on the red phosphor. Higher values makes red more visible in the afterglow. Default is 0.07
Persistence Red (more is less) // Controls the decay time, i.e. if red should fade away quickly from its initial brightness or slowly. A higher value makes the red phosphor fade away more quickly. Default value is 0.05.
Afterglow Green
Persistence Green
Afterglow Blue
Persistence Blue
Afterglow saturation // Determines the saturation of the RGB afterglow. Generally afterglow has very low saturation so it defaults to a low value of 0.1. Higher values give more saturation.
-------------
# TATE mode #
-------------
Yes we do in weird lingo :) In short TATE means "vertical" orientation for arcade monitors. The term ”Tate” is apparently a shortened form of the Japanese verb “tateru,” which means “to stand.” Pronounced “tah-teh,” though the common mispronunciation of “tayte” has gained semi-acceptance. Also commonly spelled with all capital letters (“TATE”), though it is not an acronym.
In the shader when you set TATE to 1 both the scanlines and mask orientation will rotate by 90 degrees to accommodate to Arcade games that are in vertical orientation, like 1942 shooters and the like. Mostly useful for when running MAME vertical games.
-------------------------
# Smart Integer Scaling #
-------------------------
When the video scaling is set to full screen, it may happen that the scanlines appear slightly uneven. To remedy this you can enable this option. It will scale vertically to the nearest suitable integer scale factor. The "smart" part is that it will take into account "overscan" as it appeared on TVs, so it may scale the image slightly larger than the screen size to keep things full screen while also enabling integer scale factor. When it makes use of this overscan up to about 10% of the image may fall outside of the visible area. If the nearest integer larger scale factor would go over this this bound, it chooses the nearest lower integer scale, which will come at the cost of some black bars around the image. Just try and learn :).
Values are:
0 = off
1 = smart integer scale vertically
2 = smart integer scale vertically and keep aspect ratio
----------------
# Raster Bloom #
----------------
Raster bloom is a feature that occurs on some CRTs, where the image will slightly expand on brighter images. This may give some extra "pop" to short flashing bright images, like big explosions and such. Almost all CRTs are experiencing raster bloom to some extent, but how much and whether it's really visible depends largely on the CRT model and how much it has aged / been maintained.
The following two youtube videos show examples of raster blooming.
The first movie shows metal slug on a CRT TV. If you go to second 75 and look at the bottom right where it says "Credit 04", you'll see how this text gets pushed slightly to the outside of the bezel when the screen gets bright and it coming back in on darker screens. This is sort of the default case where bloom sizes up the image by 1 to 2%.
https://youtu.be/_K-kTSUaekk
The next one shows an older TV where the voltage regulation has clearly been diminished. From 1:15 in this youtube:
https://youtu.be/zbGYwPwf-zA
The guy is turning the brightness of the monitor up and down. You can see how the white raster expands quite a bit when the brightness on the monitor is turned up and then shrinks back when it's lowered. This is what we call the 10% blooming case. I.e. it has a defect and needs servicing, opposed to the 1 - 2% normal bloom on properly calibrated sets.
The following parameters control Raster Bloom in the shader:
Raster bloom % // This determines the raster bloom scale factor. A value of 2 to 3% will result in realistic raster bloom. Larger values will exaggerate the effect, or you're really into mimicking a faulty CRT :).
R. Bloom Overscan Mode // This setting determines whether a fully bright image may push the image outside of the screen / bezel or not. Possible settings:
(This assumes that automatic full screen scaling is enabled in Retroarch video options.)
0 = Raster bloom is always within the boundaries of the visible screen
1 = holds the middle between option 0 and 2 :)
2 = Raster bloom pushes part of the image outside of the visible area on bright screens.
Setting 1 and 2 more or less mimic the behavior as seen in the metal slug x video mentioned above.
-------------------------
# Saturation adjustment #
-------------------------
This controls how saturated the image is. Higher values give more saturation. This may be useful with emulated systems like e.g. SNES, which tend to have a more saturated image than default.
--------------------------
# Gamma In and Gamma Out #
--------------------------
Setting Gamma In ("input gamma") to 2.4 affects the following:
- horizontal interpolation is done in gamma space, where brighter colors spread a bit more over darker ones. Should match interpolation of CRT's.
- scanlines are applied differently
- masks are better distributed over the spectrum
Generally it's best to keep this value at the default of 2.4 as it mostly concerns a shader internal conversion step where this default value results in desired behavior
Gamma Out:
Of course we have to switch back to the normal color space, so there is the Gamma Out out functionality. In some CRT shaders it's about 10% lower compared with the input gamma. Different input/output gamma values affect saturation and brightness.
Since there is an option to use neutral input/output gamma (1.0), you can observe the difference within the shader.
I think most importantly is that this part of the shader functions as intended and can be tweaked to personal preference.
I think the most catchy part here is that CRT's have this 2.2-2.25 gamma and I defaulted 2.4. It roots in sRGB a bit and I got used to it. You can set output gamma (often referred to as CRT gamma) to 2.25 np.
From the CRT color research (at the end of this section) it was found that the researched CRTs had a Gamma of 2.25. So to have the shader color profiles displayed properly one has to set the Gamma Out to 2.25.
----------------
# Bright boost #
----------------
This setting makes the image brighter. Making the image brighter is useful / necessary when scanlines are enabled, as scanline simulation reduces brightness of the image.
Good values for "bright boost" are between 1.1 and 1.3 depending on preference. Note that there's a tradeoff, higher values for brightboost make the image brighter, but can cause clipping of colors, making the image become more "flat". On lower color systems, like 8-bit, this clipping may be seen as soon as you go over 1.2. It's best to experiment a bit to see what suits one's own taste.
-------------
# Scanlines #
-------------
One of the most distinguishable features of CRTs when run in progressive mode are visible scanlines. I.e. the image is characterized by distinguishable brighter lines (the "scanlines"), and darker/black in-between lines. Sometime people refer to these darker lines when they say scanlines, but the bottom line is the same ;-)
Since good scanline simulation is one of the most determining aspects of good CRT simulation, there are no less than 5 parameters that control this feature:
Scanline Type // 0 = normal scanlines; 1 = more intense scanline type ; 2 = more aggressive / accentuated scanline type. Default = 0
Scanline beamshape // The scanline beamshape "low" and "high" parameters define the look of the scanlines. With these two settings the scanlines can be made thinner or thicker, less or more rounded at the edges and degrees between them. In particular the scanline beamshape low value defines the scanline shape near the middle and the beamshape high value defines the scanline shape near the edges. For example a setting of 5.0,15.0 creates a stronger but more flat like looking scanline. The default values work very well, but you may want to experiment depending on your screen resolution and preference.
Scanline dark // On a real CRT darker scanlines are thinner than bright scanlines. This setting determines by how much. Raising the value makes them thinner. Default is 1.35.
Scanline bright // On a real CRT bright scanlines are thicker than darker scanlines. This setting determines how much thicker. Lowering the values will make them thicker. Default is 1.10.
Increased bright scanline beam // This accentuates the brighter parts or pixels within a single scanline. On a real CRT bright pixels within a scanline will appear thicker. This setting controls by how much. Default is 0.65.
---------------------------
# Sharpness and smoothing #
---------------------------
The following parameters determine the smoothness versus sharpness balance of the image.
A real CRT has the peculiar but very nice characteristic that single pixels are smooth, while the overall image is sharp. This opposed to modern LCDs, where both individual pixels and the total image are very sharp. To recreate the soft "pillow shape" phosphor dot characteristics while keeping overall image sharp there 4 parameters that control this balance.
Horizontal sharpness // This setting determines the overall image sharpness mostly. Higher values create a sharper image. Default is 5.25.
Substractive sharpness // This is a nice "hack" that may be used in combination with "horizontal sharpness". Higher values give more sharpness to pixels and mask. Default is 0.05.
Horizontal Smoothing // This is some candy that blends pixels more that are close in color tint to each other. Gives a nice touch to especially high color systems that have many grades of color (like playstation).
Smart Smoothing Threshold // This works in cooperation with "Horizontal Smoothing". It sets the threshold for how far apart "same" color tints must be for horizontal smoothing to apply.
-------------
# Curvature #
-------------
The physical properties of (earlier) shadow mask CRTs make them to have a slightly curved screen. For some of these CRTs the image may appear slightly curved as well, although that largely depends on make and model and how well the set is calibrated. The following two parameters allow for the curvature to be configured in the vertical and horizontal direction.
CurvatureX // default is OFF. In case you like curvature, a recommended value is 0.03.
CurvatureY // Default is OFF. In case you like curvature, a recommended value is 0.04.
--------
# Glow #
--------
Phosphors typically create a small surrounding glow on objects. This is especially noticeable when bright objects are shown on a dark background, and even more so when watching a CRT in a dim environment. Whether this glow exists because the light emission gets scattered slightly in the front glass of the tube or something else we would like to know :).
In the shader the glow strength, radius and grade (fall-off) can be configured.
Glow Strength // Determines the overall strength of the glow . Default is 0.02.
H. Glow Radius // Determines the radius of the glow in horizontal direction. Higher values create a bigger radius. Default is 4.0.
Horizontal Glow Grade // Determines the grade/ fall-off / fade of the glow. Higher values make the glow fade out more quickly.
V. Glow Radius // Same as horizontal parameter but for vertical.
Vertical Glow Grade // Same as horizontal parameter but for vertical.
--------
# Mask #
--------
Together with scanlines the second most distinguishable feature of CRTs is the very subtle pattern, also called "mask", apparent in images displayed on a CRT. The type of pattern largely depends on the technology used, shadow mask (dotmask and slotmask) versus aperture grille (trinitron). All these types of masks can be simulated with the shader.
CRT Mask: 0:CGWG, 1-4:Lottes, 5-6:'Trinitron', 7: slotmask (see below) // The shader allows to set 7 different types of masks
0 = CGCW - a very light generic mask pattern
1 - 4 = Lottes masks, 4 different types of masks that simulate a shadow mask more or less.
5 - 6 = Trinitron. These are very effective mask types, that closely resemble the appearance of Trinitron's aperture grill. "5" is a finer version, mostly for use on 1080p, "6" is a more coarse version, mostly for use on 4K resolution.
7 = slotmask, to be used in conjunction with the additional slotmask parameters.
Mask types 1 to 6 strength can be set with these two parameters:
Lottes maskDark // lower values generally make the mask appear more strongly
Lottes maskLight // higher values generally make the mask appear more strongly
When using "7" slotmask, below parameters need to be set:
CRT Mask Size (2.0 is nice in 4k) // set to 1 for 1080p, 2 for 4K resolution
Slot Mask Strength // Overall strength of the slot mask. Good values are around 0.5
Slot Mask Width // Determines the horizontal size of the slotmask pattern. Use 2 or 3 for 1080p, 4-6 for 4K resolution.
Slot Mask Height: 2x1 or 4x1" // Determines the vertical size of the slotmask pattern. Use 1 for 1080p, or 2 for 4K resolution.
Finally there's a parameter that influences the look of mask 5 - 7.
Mask 5&6 cutoff // This determines how soon black appears between pixels for colors that are close to the R, G, or B primaries. This is suitable for both Trinitron and Slotmask. Default is 0.2. Higher values create a quicker cutoff to black between these pixels.
-----------------------
# Color Temperature % #
-----------------------
Each CRT monitor has a "whitepoint" setting, which influences how warm or cold the colors will look. The whitepoint setting differed quite a bit between different CRT models. Some had a 5000K (D50) whitepoint, i.e. "warm" colors, and some had a 9300K whitepoint,i.e. very "cold" colors. Most will sit somewhere in between, with today's standard being 6500K (D65). Note that a warmer setting tends the greys noticeably to a more yellowish brown, while the colder setting moves it to a more blueish grey.
At setting 0 the "color temperature %" is equivalent to the D65 whitepoint, let's say "neutral". Lower it to move towards the more warm 5000K point, or raise it to move it more towards the 9300K cold point.
-------------------
# PVM Like Colors #
-------------------
PVM Like Colors // This is a bit of candy that tries to simulate some of the color aberrations that appear with Sony PVM and BVM monitors.
-------------------
# LUT Colors #
-------------------
The shader has two ways to simulating "CRT Colors". LUT colors and CRT Color Profiles. LUT colors use lookup tables to transform the sRGB color profile to something more close to CRT colors. These LUTs come from varying sources, and the accuracy regarding CRT color simulation is a bit of an unknown, but at the least they provide some nice alternative color schemes which you may like.
--------------------- ---------------
# CRT Color Profile # & # Color Space #
--------------------- ---------------
"CRT colors" changes the default colors to something more close to what the RGB Phosphors in CRTs produce.
These profiles are about subtle changes, but if you were used to the display of CRTs you may remember the display having more vivid greens, softer yellows and red, etc. It all depends on the type of CRT you were looking at, but admittedly CRT colors are different from the default sRGB color gamut that is prevalent in today's LCD screens.
The CRT colors are based on research of the CIE chromaticity coordinates of the most common phosphors used back in the day. Therefore we ended up with 3 "specs" which are EBU standard phosphors, P22-RGB phosphors and the SMPTE-C standard. These three profiles can be selected under "CRT colors" as number 1, 2 and 3.
Then there are two additional "calibrated" profiles that actually quite closely match a Philips based CRT monitor and a Trinitron monitor. They are profile number 4 and 5.
Some more information on these profiles can be read below.
The main drawback currently is that Phosphor color primaries are partly outside the sRGB spectrum, such that for these profiles a "Wide Color Gamut" monitor is needed / recommended. This is what the "Color space" option is for. If you happen to own a monitor that is able to display DCI-P3 color gamut, then set this option to "1". Option "2" is for AdobeRGB and "3" for Rec. 2020. DCI-P3 is verified to be quite accurate.
In conclusion:
The good news is that we've got "CRT colors" largely covered now with the correct specs and two "quite accurate" calibrated profiles. The bad news is that with a default sRGB monitor the profiles will be more or less clipped and look wrong, depending on the content. Then we have some good news, as it seems that DCI-P3 or some other wide color gamut will be part of the HDR-500+ spec (see here: https://displayhdr.org/wp-content/uploads/2019/02/DisplayHDR_SpecChart_Rows_190219.jpg ) So within a few years wide color gamut should become mainstream in monitors. The question remains whether for HDR-500+ certified monitors this wide color gamut can be enabled by the user or emulator, or whether it will be only available in HDR content encoded mode. Time will tell.
Lastly, let's not forget we are talking about subtle differences from the default sRGB colors here. Let's just say you have to be slightly OCD on CRT tech to really appreciate the difference :-)
For those interested below is some additional information on each of the profiles and the specific chromaticity values used. This is purely additional information, there is no need (or possibility) to do anything with these in the shader settings.
"CRT Colors" for CRT-Guest-Dr-Venom -- Additional information.
3 x spec
2 x calibration
Specifications for three standards
1. EBU Standard Phosphors
// Amongst others used in Sony BVMs and Higher-end PVMs
// Tolerances are described in the E.B.U. standard reference document "E.B.U. standard for chromaticity tolerances for studio monitors" tech-3213-E.
// PVM-1440QM service manual quotes 0.01 as tolerance on the RGB CIE coordinates.
xb0 = "150.000000"
xg0 = "290.000000"
xr0 = "640.000000"
yb0 = "60.000000"
yg0 = "600.000000"
yr0 = "330.000000"
Whitepoint is D65
X 95,04 --> Xw0 950.4
Y 100 --> Yw0 1000
Z 108,88 --> Zw0 1088.8
2. P22 Phosphors
// These phosphors are often quoted as the "default" phosphors used in CRTs
// Also used in lower-end PVMs, see Sony PVM-20M4E 20M2E Colour Video Monitor.pdf
// These can still be bought :-) https://www.phosphor-technology.com/crt-phosphors/ -- includes CIE coordinates.
xb0 = "148.000000"
xg0 = "310.000000"
xr0 = "647.000000"
yb0 = "62.000000"
yg0 = "594.000000"
yr0 = "343.000000"
3. SMPTE-C
// Spec for most of America.
// I have forgone on the 1953 NTSC standard, as apart from very few early color TV's the 1953 NTSC standard was never actually used. Instead less saturated primaries were used to achieve brighter screens.
// Taken from the WIKI on NTSC (https://en.wikipedia.org/wiki/NTSC) In 1968-69 the Conrac Corp., working with RCA, defined a set of controlled phosphors for use in broadcast color picture video monitors. This specification survives today as the SMPTE "C" phosphor specification:
xb0 = "155.000000"
xg0 = "310.000000"
xr0 = "630.000000"
yb0 = "70.000000"
yg0 = "595.000000"
yr0 = "340.000000"
Whitepoint is D65
X 95,04 --> Xw0 950.4
Y 100 --> Yw0 1000
Z 108,88 --> Zw0 1088.8
4. Calibrated profile for Philips CRT monitors. Of course an approximation, but I'm pleased with the "quite accurate" results.
// Manually calibrated and compared to real Philips based CRT monitors, running side by side with the shader on a 10-bit DCI-P3 gamut panel. This calibrated CRT profile covers amongst others Philips CM8533, Philips VS-0080, and Commodore 1084.
// Note the whitepoint is significantly different from D65. It's closer to 6100K, but clearly not on the blackbody curve. Possibly an ISO-line target, given the slight hue on the whitepoint. Other than that it could be aging / whitepoint drift. I compared four CRT monitors, one of them in very mint condition, and they all have this slight hue on the whitepoint, so I would guess this is how they came out of the factory. But then again since these things are now getting close to 30 years old, who knows? Either way the profile should be good: factory out or true to life aged CRTs... :D.
// It's important this specific whitepoint is used in the shader or the colors will not be accurate.
// Also it's important to note that this profile should be used with "Gamma Out" at 2.25 or the colors will be less accurate.
xb0 = "154.000000"
xg0 = "300.000000"
xr0 = "635.000000"
yb0 = "60.000000"
yg0 = "620.000000"
yr0 = "339.000000"
Whitepoint:
Xw0 = "910.000000"
Yw0 = "1000.000000"
Zw0 = "960.000000"
5. Calibrated profile for Sony Trinitron Monitor.
// In a similar fashion as the Philips CRT based profile, this is a manually calibrated profile for a Sony Trinitron monitor, model KX-14CP1.
// This monitor uses a Whitepoint that is close to 9300K. The Z value in the calibration process has been raised to the point where the "blue-ishness" of the white matches. To achieve further 9300K white, I guess one has to raise the hardware whitepoint of the host PC monitor...
// It's important this specific whitepoint is used in the shader or the colors will not be accurate.
// Also it's important to note that this profile should be used with "Gamma Out" at 2.25 or the colors will be less accurate.
xb0 = "152.000000"
xg0 = "279.000000"
xr0 = "647.000000"
yb0 = "60.000000"
yg0 = "635.000000"
yr0 = "335.000000"
Whitepoint:
Xw0 = "903.000000"
Yw0 = "1000.000000"
Zw0 = "1185.000000"
End :)

View file

@ -23,19 +23,7 @@
layout(push_constant) uniform Push layout(push_constant) uniform Push
{ {
vec4 SourceSize; float SW, AR, PR, AG, PG, AB, PB, sat;
vec4 OriginalSize;
vec4 OutputSize;
uint FrameCount;
float SW;
float AR;
float PR;
float AG;
float PG;
float AB;
float PB;
float sat;
float GTH;
} params; } params;
#pragma parameter SW "Afterglow switch ON/OFF" 1.0 0.0 1.0 1.0 #pragma parameter SW "Afterglow switch ON/OFF" 1.0 0.0 1.0 1.0
@ -46,7 +34,17 @@ layout(push_constant) uniform Push
#pragma parameter AB "Afterglow Blue" 0.07 0.0 1.0 0.01 #pragma parameter AB "Afterglow Blue" 0.07 0.0 1.0 0.01
#pragma parameter PB "Persistence Blue" 0.05 0.0 1.0 0.01 #pragma parameter PB "Persistence Blue" 0.05 0.0 1.0 0.01
#pragma parameter sat "Afterglow saturation" 0.10 0.0 1.0 0.01 #pragma parameter sat "Afterglow saturation" 0.10 0.0 1.0 0.01
#pragma parameter GTH "Afterglow threshold" 5.0 0.0 255.0 1.0
#define SW params.SW
#define AR params.AR
#define PR params.PR
#define AG params.AG
#define PG params.PG
#define AB params.AB
#define PB params.PB
#define sat params.sat
#define COMPAT_TEXTURE(c,d) texture(c,d)
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
{ {
@ -75,30 +73,39 @@ layout(set = 0, binding = 6) uniform sampler2D OriginalHistory4;
layout(set = 0, binding = 7) uniform sampler2D OriginalHistory5; layout(set = 0, binding = 7) uniform sampler2D OriginalHistory5;
layout(set = 0, binding = 8) uniform sampler2D OriginalHistory6; layout(set = 0, binding = 8) uniform sampler2D OriginalHistory6;
#define eps 1e-4 #define Prev1Texture OriginalHistory1
#define Prev2Texture OriginalHistory2
#define Prev3Texture OriginalHistory3
#define Prev4Texture OriginalHistory4
#define Prev5Texture OriginalHistory5
#define Prev6Texture OriginalHistory6
#define TEX0 vTexCoord
#define eps 1e-3
vec3 afterglow(float number) vec3 afterglow(float number)
{ {
return vec3(params.AR, params.AG, params.AB)*exp2(-vec3(params.PR, params.PG, params.PB)*vec3(number*number)); return vec3(AR, AG, AB)*exp2(-vec3(PR, PG, PB)*vec3(number*number));
} }
void main() void main()
{ {
vec3 color = texture(Source, vTexCoord.xy).rgb; vec3 color = COMPAT_TEXTURE(Source, TEX0.xy).rgb;
vec3 color1 = texture(OriginalHistory1, vTexCoord.xy).rgb * afterglow(1.0); vec3 color1 = COMPAT_TEXTURE(Prev1Texture, TEX0.xy).rgb * afterglow(1.0);
vec3 color2 = texture(OriginalHistory2, vTexCoord.xy).rgb * afterglow(2.0); vec3 color2 = COMPAT_TEXTURE(Prev2Texture, TEX0.xy).rgb * afterglow(2.0);
vec3 color3 = texture(OriginalHistory3, vTexCoord.xy).rgb * afterglow(3.0); vec3 color3 = COMPAT_TEXTURE(Prev3Texture, TEX0.xy).rgb * afterglow(3.0);
vec3 color4 = texture(OriginalHistory4, vTexCoord.xy).rgb * afterglow(4.0); vec3 color4 = COMPAT_TEXTURE(Prev4Texture, TEX0.xy).rgb * afterglow(4.0);
vec3 color5 = texture(OriginalHistory5, vTexCoord.xy).rgb * afterglow(5.0); vec3 color5 = COMPAT_TEXTURE(Prev5Texture, TEX0.xy).rgb * afterglow(5.0);
vec3 color6 = texture(OriginalHistory6, vTexCoord.xy).rgb * afterglow(6.0); vec3 color6 = COMPAT_TEXTURE(Prev6Texture, TEX0.xy).rgb * afterglow(6.0);
vec3 glow = color1 + color2 + color3 + color4 + color5 + color6; vec3 glow = color1 + color2 + color3 + color4 + color5 + color6;
float l = length(glow); float l = length(glow);
glow = normalize(pow(glow + vec3(eps), vec3(params.sat)))*l; glow = normalize(pow(glow + vec3(eps), vec3(sat)))*l;
float w = 1.0; float w = 1.0;
if ((color.r + color.g + color.b) > params.GTH/255.0) w = 0.0; if ((color.r + color.g + color.b) > 7.0/255.0) w = 0.0;
FragColor = vec4(color + params.SW*w*glow,1.0); FragColor = vec4(color + SW*w*glow,1.0);
} }

View file

@ -1,9 +1,9 @@
#version 450 #version 450
/* /*
Average Luminance Shader Average Luminance Shader, Smart Smoothing Difference Shader
Copyright (C) 2018 guest(r) - guest.r@gmail.com Copyright (C) 2018-2019 guest(r) - guest.r@gmail.com
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
@ -19,19 +19,22 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Thanks to HunterK for the mipmap hint. :D Thanks to HunterK for the mipmap hint. :D
*/ */
layout(push_constant) uniform Push layout(push_constant) uniform Push
{ {
vec4 SourceSize; vec4 SourceSize;
vec4 OriginalSize; float STH;
vec4 OutputSize;
uint FrameCount;
float grade;
} params; } params;
#pragma parameter grade "Raster Bloom Grade" 0.65 0.10 1.0 0.05 #pragma parameter STH "Smart Smoothing Threshold" 0.7 0.4 1.2 0.05
#define STH params.STH
#define COMPAT_TEXTURE(c,d) texture(c,d)
#define SourceSize params.SourceSize
#define InputSize SourceSize
#define TEX0 vTexCoord
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
{ {
@ -46,32 +49,61 @@ layout(location = 0) out vec2 vTexCoord;
void main() void main()
{ {
gl_Position = global.MVP * Position; gl_Position = global.MVP * Position;
vTexCoord = TexCoord; vTexCoord = TexCoord * 1.0001;
} }
#pragma stage fragment #pragma stage fragment
layout(location = 0) in vec2 vTexCoord; layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor; layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source; layout(set = 0, binding = 2) uniform sampler2D Source;
layout(set = 0, binding = 3) uniform sampler2D WhitePointPass;
#define PassPrev2Texture WhitePointPass
float df (vec3 A, vec3 B)
{
float diff = length(A-B);
float luma = clamp(length(0.5*min(A,B) + 0.25*(A+B) + 1e-8), 0.0001, 1.0);
float diff1 = diff/luma;
return 1.0 - clamp(7.0*(max(1.5*diff,diff1)-STH), 0.0, 0.9999);
}
void main() void main()
{ {
float xtotal = floor(params.SourceSize.x/32.0); float xtotal = floor(InputSize.x/64.0);
float ytotal = floor(params.SourceSize.y/32.0); float ytotal = floor(InputSize.y/64.0);
float ltotal = 0.0; float ltotal = 0.0;
vec2 dx = vec2(params.SourceSize.z, 0.0)*32.0;
vec2 dy = vec2(0.0, params.SourceSize.w)*32.0; vec2 dx = vec2(SourceSize.z, 0.0)*64.0;
vec2 dy = vec2(0.0, SourceSize.w)*64.0;
vec2 offset = 0.25*(dx+dy);
for (float i = 0.0; i <= xtotal; i++) for (float i = 0.0; i <= xtotal; i++)
{ {
for (float j = 0.0; j <= ytotal; j++) for (float j = 0.0; j <= ytotal; j++)
{ {
ltotal += length(textureLod(Source, i*dx + j*dy, 5.0).rgb); ltotal+= max(0.25, length(textureLod(Source, i*dx + j*dy + offset, 6.0).rgb));
} }
} }
ltotal = 0.577350269 * ltotal / ((xtotal+1.0)*(ytotal+1.0));
ltotal = inversesqrt(3.0)*ltotal / ((xtotal+1.0)*(ytotal+1.0)); dx = vec2(SourceSize.z, 0.0);
dy = vec2(0.0, SourceSize.w);
FragColor = vec4(pow(ltotal, params.grade)); vec3 l1 = COMPAT_TEXTURE(PassPrev2Texture, TEX0.xy -dx).xyz;
vec3 ct = COMPAT_TEXTURE(PassPrev2Texture, TEX0.xy ).xyz;
vec3 r1 = COMPAT_TEXTURE(PassPrev2Texture, TEX0.xy +dx).xyz;
vec3 t1 = COMPAT_TEXTURE(PassPrev2Texture, TEX0.xy -dy).xyz;
vec3 b1 = COMPAT_TEXTURE(PassPrev2Texture, TEX0.xy +dy).xyz;
float dl = df(ct, l1);
float dr = df(ct, r1);
float dt = df(ct, t1);
float db = df(ct, b1);
float resx = dl; float resy = dr; float resz = floor(9.0*dt)/10.0 + floor(9.0*db)/100.0;
FragColor = vec4(resx,resy,resz,pow(ltotal, 0.65));
} }

View file

@ -0,0 +1,63 @@
#version 450
// Avg. Luminance Smoothing
layout(push_constant) uniform Push
{
vec4 SourceSize;
vec4 OriginalSize;
vec4 OutputSize;
uint FrameCount;
} params;
layout(std140, set = 0, binding = 0) uniform UBO
{
mat4 MVP;
} global;
#pragma stage vertex
layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 vTexCoord;
void main()
{
gl_Position = global.MVP * Position;
vTexCoord = TexCoord;
}
#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D OriginalHistory1;
layout(set = 0, binding = 3) uniform sampler2D OriginalHistory2;
layout(set = 0, binding = 4) uniform sampler2D OriginalHistory3;
layout(set = 0, binding = 5) uniform sampler2D OriginalHistory4;
layout(set = 0, binding = 6) uniform sampler2D OriginalHistory5;
layout(set = 0, binding = 7) uniform sampler2D OriginalHistory6;
layout(set = 0, binding = 8) uniform sampler2D OriginalHistory7;
#define PrevTexture OriginalHistory1
#define Prev1Texture OriginalHistory2
#define Prev2Texture OriginalHistory3
#define Prev3Texture OriginalHistory4
#define Prev4Texture OriginalHistory5
#define Prev5Texture OriginalHistory6
#define Prev6Texture OriginalHistory7
#define TEX0 vTexCoord
#define COMPAT_TEXTURE(c,d) texture(c,d)
void main()
{
vec3 color = COMPAT_TEXTURE(PrevTexture, TEX0.xy).rgb;
color+= COMPAT_TEXTURE(Prev6Texture, TEX0.xy).rgb;
color+= COMPAT_TEXTURE(Prev5Texture, TEX0.xy).rgb;
color+= COMPAT_TEXTURE(Prev4Texture, TEX0.xy).rgb;
color+= COMPAT_TEXTURE(Prev3Texture, TEX0.xy).rgb;
color+= COMPAT_TEXTURE(Prev2Texture, TEX0.xy).rgb;
color+= COMPAT_TEXTURE(Prev1Texture, TEX0.xy).rgb;
FragColor = vec4(color/7.0,1.0);
}

View file

@ -1,20 +1,21 @@
#version 450 #version 450
// Higher value, more centered glow.
// Lower values might need more taps.
layout(push_constant) uniform Push layout(push_constant) uniform Push
{ {
vec4 SourceSize; vec4 SourceSize;
vec4 OriginalSize; vec4 OriginalSize;
vec4 OutputSize; vec4 OutputSize;
uint FrameCount; uint FrameCount;
float TAPSH; float TAPSH;
float GLOW_FALLOFF_H; float GLOW_FALLOFF_H;
} params; } params;
// Higher value, more centered glow.
// Lower values might need more taps.
#pragma parameter TAPSH "H. Glow Radius" 4.0 1.0 10.0 1.0 #pragma parameter TAPSH "H. Glow Radius" 4.0 1.0 10.0 1.0
#pragma parameter GLOW_FALLOFF_H "Horizontal Glow Grade" 0.30 0.0 1.0 0.01 #define TAPSH params.TAPSH
#pragma parameter GLOW_FALLOFF_H "Horizontal Glow Grade" 0.30 0.00 1.0 0.01
#define GLOW_FALLOFF_H params.GLOW_FALLOFF_H
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
{ {
@ -37,19 +38,22 @@ layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor; layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source; layout(set = 0, binding = 2) uniform sampler2D Source;
#define kernel(x) exp(-params.GLOW_FALLOFF_H * (x) * (x)) #define COMPAT_TEXTURE(c,d) texture(c,d)
#define SourceSize params.SourceSize
#define kernel(x) exp(-GLOW_FALLOFF_H * (x) * (x))
void main() void main()
{ {
vec3 col = vec3(0.0); vec3 col = vec3(0.0);
float dx = params.SourceSize.z; float dx = SourceSize.z;
float k_total = 0.; float k_total = 0.;
for (float i = -params.TAPSH; i <= params.TAPSH; i++) for (float i = -TAPSH; i <= TAPSH; i++)
{ {
float k = kernel(i); float k = kernel(i);
k_total += k; k_total += k;
col += k * texture(Source, vTexCoord + vec2(float(i) * dx, 0.0)).rgb; col += k * COMPAT_TEXTURE(Source, vTexCoord + vec2(float(i) * dx, 0.0)).rgb;
} }
FragColor = vec4(col / k_total, 1.0); FragColor = vec4(col / k_total, 1.0);
} }

View file

@ -1,20 +1,22 @@
#version 450 #version 450
// Higher value, more centered glow.
// Lower values might need more taps.
layout(push_constant) uniform Push layout(push_constant) uniform Push
{ {
vec4 SourceSize; vec4 SourceSize;
vec4 OriginalSize; vec4 OriginalSize;
vec4 OutputSize; vec4 OutputSize;
uint FrameCount; uint FrameCount;
float TAPSV; float TAPSV;
float GLOW_FALLOFF_V; float GLOW_FALLOFF_V;
} params; } params;
// Higher value, more centered glow.
// Lower values might need more taps.
// Parameter lines go here:
#pragma parameter TAPSV "V. Glow Radius" 4.0 1.0 10.0 1.0 #pragma parameter TAPSV "V. Glow Radius" 4.0 1.0 10.0 1.0
#pragma parameter GLOW_FALLOFF_V "Vertical Glow Grade" 0.30 0.0 1.0 0.01 #define TAPSV params.TAPSV
#pragma parameter GLOW_FALLOFF_V "Vertical Glow Grade" 0.30 0.00 1.0 0.01
#define GLOW_FALLOFF_V params.GLOW_FALLOFF_V
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
{ {
@ -37,19 +39,22 @@ layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor; layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source; layout(set = 0, binding = 2) uniform sampler2D Source;
#define kernel(x) exp(-params.GLOW_FALLOFF_V * (x) * (x)) #define COMPAT_TEXTURE(c,d) texture(c,d)
#define SourceSize params.SourceSize
#define kernel(x) exp(-GLOW_FALLOFF_V * (x) * (x))
void main() void main()
{ {
vec3 col = vec3(0.0); vec3 col = vec3(0.0);
float dy = params.SourceSize.w; float dy = SourceSize.w;
float k_total = 0.; float k_total = 0.;
for (float i = -params.TAPSV; i <= params.TAPSV; i++) for (float i = -TAPSV; i <= TAPSV; i++)
{ {
float k = kernel(i); float k = kernel(i);
k_total += k; k_total += k;
col += k * texture(Source, vTexCoord + vec2(0.0, float(i) * dy)).rgb; col += k * COMPAT_TEXTURE(Source, vTexCoord + vec2(0.0, float(i) * dy)).rgb;
} }
FragColor = vec4(col / k_total, 1.0); FragColor = vec4(col / k_total, 1.0);
} }

View file

@ -0,0 +1,160 @@
#version 450
/*
CRT Color Profiles
Copyright (C) 2019 guest(r) and Dr. Venom
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.
*/
layout(push_constant) uniform Push
{
float CP, CS;
} params;
#pragma parameter CP "CRT Color Profile" 0.0 -1.0 5.0 1.0
#pragma parameter CS "Color Space: sRGB, DCI, Adobe, Rec.2020" 0.0 0.0 3.0 1.0
#define CP params.CP
#define CS params.CS
#define COMPAT_TEXTURE(c,d) texture(c,d)
#define TEX0 vTexCoord
layout(std140, set = 0, binding = 0) uniform UBO
{
mat4 MVP;
} global;
#pragma stage vertex
layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 vTexCoord;
void main()
{
gl_Position = global.MVP * Position;
vTexCoord = TexCoord;
}
#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source;
const mat3 Profile0 =
mat3(
0.412391, 0.212639, 0.019331,
0.357584, 0.715169, 0.119195,
0.180481, 0.072192, 0.950532
);
const mat3 Profile1 =
mat3(
0.430554, 0.222004, 0.020182,
0.341550, 0.706655, 0.129553,
0.178352, 0.071341, 0.939322
);
const mat3 Profile2 =
mat3(
0.396686, 0.210299, 0.006131,
0.372504, 0.713766, 0.115356,
0.181266, 0.075936, 0.967571
);
const mat3 Profile3 =
mat3(
0.393521, 0.212376, 0.018739,
0.365258, 0.701060, 0.111934,
0.191677, 0.086564, 0.958385
);
const mat3 Profile4 =
mat3(
0.392258, 0.209410, 0.016061,
0.351135, 0.725680, 0.093636,
0.166603, 0.064910, 0.850324
);
const mat3 Profile5 =
mat3(
0.377923, 0.195679, 0.010514,
0.317366, 0.722319, 0.097826,
0.207738, 0.082002, 1.076960
);
const mat3 ToSRGB =
mat3(
3.240970, -0.969244, 0.055630,
-1.537383, 1.875968, -0.203977,
-0.498611, 0.041555, 1.056972
);
const mat3 ToDCI =
mat3(
2.725394, -0.795168, 0.041242,
-1.018003, 1.689732, 0.022647,
-0.440163, 0.022647, 1.100929
);
const mat3 ToAdobe =
mat3(
2.041588, -0.969244, 0.013444,
-0.565007, 1.875968, -0.11836,
-0.344731, 0.041555, 1.015175
);
const mat3 ToREC =
mat3(
1.716651, -0.666684, 0.017640,
-0.355671, 1.616481, -0.042771,
-0.253366, 0.015769, 0.942103
);
void main()
{
vec3 c = COMPAT_TEXTURE(Source, TEX0.xy).rgb;
float p;
mat3 m_out;
if (CS == 0.0) { p = 2.4; m_out = ToSRGB; } else
if (CS == 1.0) { p = 2.6; m_out = ToDCI; } else
if (CS == 2.0) { p = 2.2; m_out = ToAdobe;} else
if (CS == 3.0) { p = 2.4; m_out = ToREC; }
vec3 color = pow(c, vec3(p));
mat3 m_in = Profile0;
if (CP == 0.0) { m_in = Profile0; } else
if (CP == 1.0) { m_in = Profile1; } else
if (CP == 2.0) { m_in = Profile2; } else
if (CP == 3.0) { m_in = Profile3; } else
if (CP == 4.0) { m_in = Profile4; } else
if (CP == 5.0) { m_in = Profile5; }
color = m_in*color;
color = m_out*color;
color = pow(color, vec3(1.0/p));
if (CP == -1.0) color = c;
FragColor = vec4(color,1.0);
}

View file

@ -4,9 +4,9 @@
CRT - Guest - Dr. Venom CRT - Guest - Dr. Venom
Copyright (C) 2018-2019 guest(r) - guest.r@gmail.com Copyright (C) 2018-2019 guest(r) - guest.r@gmail.com
Incorporates many good ideas and suggestions from Dr. Venom.
Incorporates many good ideas and suggestions from Dr. Venom.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 as published by the Free Software Foundation; either version 2
@ -25,82 +25,92 @@
layout(push_constant) uniform Push layout(push_constant) uniform Push
{ {
vec4 SourceSize; float TATE, IOS, OS, BLOOM, brightboost, gsl, scanline1, scanline2, beam_min, beam_max, beam_size,
vec4 OutputSize; h_sharp, s_sharp, h_smart, csize, bsize, warpX, warpY, glow, shadowMask, masksize, vertmask,
float TATE; // Screen orientation slotmask, slotwidth, double_slot, mcut, maskDark, maskLight, CGWG, GTW, gamma_out;
float IOS; // Smart Integer Scaling
float OS; // Do overscan
float BLOOM; // Bloom overscan percentage
float brightboost; // adjust brightness
float saturation; // 1.0 is normal saturation
float gsl; // Alternate scanlines
float scanline; // scanline param, vertical sharpness
float beam_min; // dark area beam min - wide
float beam_max; // bright area beam max - narrow
float h_sharp; // pixel sharpness
float s_sharp; // substractive sharpness
float csize; // corner size
float warpX; // Curvature X
float warpY; // Curvature Y
float glow; // Glow Strength
float shadowMask; // Mask Style
float maskDark; // Dark "Phosphor"
float maskLight; // Light "Phosphor"
float CGWG; // CGWG Mask Strength
float GTW; // Gamma tweak
float gamma_out; // output gamma
} params; } params;
#pragma parameter TATE "TATE Mode" 0.0 0.0 1.0 1.0 #pragma parameter TATE "TATE Mode" 0.0 0.0 1.0 1.0
#define TATE params.TATE #define TATE params.TATE // Screen orientation
#pragma parameter IOS "Smart Integer Scaling" 0.0 0.0 1.0 1.0 #pragma parameter IOS "Smart Integer Scaling: 1.0:Y, 2.0:'X'+Y" 0.0 0.0 2.0 1.0
#define IOS params.IOS #define IOS params.IOS // Smart Integer Scaling
#pragma parameter OS "R. Bloom Overscan Mode" 2.0 0.0 2.0 1.0 #pragma parameter OS "R. Bloom Overscan Mode" 1.0 0.0 2.0 1.0
#define OS params.OS #define OS params.OS // Do overscan
#pragma parameter BLOOM "Raster bloom %" 0.0 0.0 20.0 1.0 #pragma parameter BLOOM "Raster bloom %" 0.0 0.0 20.0 1.0
#define BLOOM params.BLOOM #define BLOOM params.BLOOM // Bloom overscan percentage
#pragma parameter brightboost "Bright boost" 1.10 0.50 2.00 0.01 #pragma parameter brightboost "Bright boost" 1.35 0.50 2.00 0.01
#define brightboost params.brightboost #define brightboost params.brightboost // adjust brightness
#pragma parameter saturation "Saturation adjustment" 1.0 0.1 2.0 0.05 #pragma parameter gsl "Scanline Type" 0.0 0.0 2.0 1.0
#define saturation params.saturation #define gsl params.gsl // Alternate scanlines
#pragma parameter gsl "Alternate scanlines" 0.0 0.0 1.0 1.0 #pragma parameter scanline1 "Scanline beam shape low" 8.0 1.0 15.0 1.0
#define gsl params.gsl #define scanline1 params.scanline1 // scanline param, vertical sharpness
#pragma parameter scanline "Scanline adjust" 8.0 1.0 12.0 1.0 #pragma parameter scanline2 "Scanline beam shape high" 8.0 5.0 23.0 1.0
#define scanline params.scanline #define scanline2 params.scanline2 // scanline param, vertical sharpness
#pragma parameter beam_min "Scanline dark" 1.30 0.5 2.0 0.05 #pragma parameter beam_min "Scanline dark" 1.35 0.5 2.0 0.05
#define beam_min params.beam_min #define beam_min params.beam_min // dark area beam min - narrow
#pragma parameter beam_max "Scanline bright" 1.0 0.5 2.0 0.05 #pragma parameter beam_max "Scanline bright" 1.05 0.5 2.0 0.05
#define beam_max params.beam_max #define beam_max params.beam_max // bright area beam max - wide
#pragma parameter h_sharp "Horizontal sharpness" 5.0 1.5 20.0 0.25 #pragma parameter beam_size "Increased bright scanline beam" 0.65 0.0 1.0 0.05
#define h_sharp params.h_sharp #define beam_size params.beam_size // increased max. beam size
#pragma parameter s_sharp "Substractive sharpness" 0.0 0.0 0.20 0.01 #pragma parameter h_sharp "Horizontal sharpness" 5.25 1.5 20.0 0.25
#define s_sharp params.s_sharp #define h_sharp params.h_sharp // pixel sharpness
#pragma parameter csize "Corner size" 0.0 0.0 0.05 0.01 #pragma parameter s_sharp "Substractive sharpness" 0.05 0.0 0.20 0.01
#define csize params.csize #define s_sharp params.s_sharp // substractive sharpness
#pragma parameter h_smart "Smart Horizontal Smoothing" 0.0 0.0 1.0 0.1
#define h_smart params.h_smart // smart horizontal smoothing
#pragma parameter csize "Corner size" 0.0 0.0 0.07 0.01
#define csize params.csize // corner size
#pragma parameter bsize "Border smoothness" 600.0 100.0 600.0 25.0
#define bsize params.bsize // border smoothness
#pragma parameter warpX "CurvatureX (default 0.03)" 0.0 0.0 0.125 0.01 #pragma parameter warpX "CurvatureX (default 0.03)" 0.0 0.0 0.125 0.01
#define warpX params.warpX #define warpX params.warpX // Curvature X
#pragma parameter warpY "CurvatureY (default 0.04)" 0.0 0.0 0.125 0.01 #pragma parameter warpY "CurvatureY (default 0.04)" 0.0 0.0 0.125 0.01
#define warpY params.warpY #define warpY params.warpY // Curvature Y
#pragma parameter glow "Glow Strength" 0.04 0.0 0.5 0.01 #pragma parameter glow "Glow Strength" 0.02 0.0 0.5 0.01
#define glow params.glow #define glow params.glow // Glow Strength
#pragma parameter shadowMask "Mask Style (0 = CGWG)" 0.0 -1.0 5.0 1.0 #pragma parameter shadowMask "CRT Mask: 0:CGWG, 1-4:Lottes, 5-6:'Trinitron'" 0.0 -1.0 7.0 1.0
#define shadowMask params.shadowMask #define shadowMask params.shadowMask // Mask Style
#pragma parameter maskDark "Lottes maskDark" 0.5 0.0 2.0 0.1 #pragma parameter masksize "CRT Mask Size (2.0 is nice in 4k)" 1.0 1.0 2.0 1.0
#define maskDark params.maskDark #define masksize params.masksize // Mask Size
#pragma parameter maskLight "Lottes maskLight" 1.5 0.0 2.0 0.1 #pragma parameter vertmask "PVM Like Colors" 0.0 0.0 0.25 0.01
#define maskLight params.maskLight #define vertmask params.vertmask // Vertical mask
#pragma parameter CGWG "CGWG Mask Str." 0.4 0.0 1.0 0.05 #pragma parameter slotmask "Slot Mask Strength" 0.0 0.0 1.0 0.05
#define CGWG params.CGWG #define slotmask params.slotmask // Slot Mask ON/OFF
#pragma parameter GTW "Gamma Tweak" 1.10 0.5 1.5 0.01 #pragma parameter slotwidth "Slot Mask Width" 2.0 2.0 6.0 0.5
#define GTW params.GTW #define slotwidth params.slotwidth // Slot Mask Width
#pragma parameter gamma_out "Gamma out" 2.4 1.0 3.0 0.05 #pragma parameter double_slot "Slot Mask Height: 2x1 or 4x1" 1.0 1.0 2.0 1.0
#define gamma_out params.gamma_out #define double_slot params.double_slot // Slot Mask Height
#pragma parameter mcut "Mask 5&6 cutoff" 0.2 0.0 0.5 0.05
#define mcut params.mcut // Mask 5&6 cutoff
#pragma parameter maskDark "Lottes maskDark" 0.5 0.0 2.0 0.05
#define maskDark params.maskDark // Dark "Phosphor"
#pragma parameter maskLight "Lottes maskLight" 1.5 0.0 2.0 0.05
#define maskLight params.maskLight // Light "Phosphor"
#pragma parameter CGWG "CGWG Mask Str." 0.3 0.0 1.0 0.05
#define CGWG params.CGWG // CGWG Mask Strength
#pragma parameter GTW "Gamma Tweak" 1.05 0.5 1.5 0.01
#define GTW params.GTW // Gamma tweak
#pragma parameter gamma_out "Gamma out" 2.4 1.0 3.5 0.05
#define gamma_out params.gamma_out // output gamma
#define COMPAT_TEXTURE(c,d) texture(c,d)
#define TEX0 vTexCoord
#define InputSize SourceSize
#define TextureSize SourceSize
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
{ {
mat4 MVP; mat4 MVP;
vec4 SourceSize;
vec4 OriginalSize;
vec4 OutputSize;
uint FrameCount;
} global; } global;
#define SourceSize global.SourceSize
#define OutputSize global.OutputSize
#define gl_FragCoord (vTexCoord * OutputSize.xy)
#pragma stage vertex #pragma stage vertex
layout(location = 0) in vec4 Position; layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord; layout(location = 1) in vec2 TexCoord;
@ -109,62 +119,71 @@ layout(location = 0) out vec2 vTexCoord;
void main() void main()
{ {
gl_Position = global.MVP * Position; gl_Position = global.MVP * Position;
vTexCoord = TexCoord * 1.0001; vTexCoord = TexCoord * 1.00001;
} }
#pragma stage fragment #pragma stage fragment
layout(location = 0) in vec2 vTexCoord; layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor; layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source; layout(set = 0, binding = 2) uniform sampler2D Source;
layout(set = 0, binding = 3) uniform sampler2D lum_pass; layout(set = 0, binding = 3) uniform sampler2D LinearizePass;
layout(set = 0, binding = 4) uniform sampler2D linearize_pass; layout(set = 0, binding = 4) uniform sampler2D AvgLumPass;
#define Texture Source
#define PassPrev3Texture LinearizePass
#define PassPrev4Texture AvgLumPass
#define eps 1e-10 #define eps 1e-10
float b_min = 1.0 + 7.0*(beam_min - 0.5)*0.666666666; float st(float x, float scanline)
float b_max = 1.0 + 7.0*(beam_max - 0.5)*0.666666666; {
float scn_s = 0.3 + 0.7*(scanline - 1.0)*0.090909090; return exp2(-scanline*x*x);
}
vec3 sw(float x, vec3 color)
vec3 sw0(vec3 x, vec3 color, float scanline)
{ {
vec3 tmp = mix(vec3(beam_min),vec3(beam_max), color); vec3 tmp = mix(vec3(beam_min),vec3(beam_max), color);
vec3 ex = vec3(x)*tmp; vec3 ex = x*tmp;
return exp2(-scanline*ex*ex); return exp2(-scanline*ex*ex);
}
vec3 sw1(vec3 x, vec3 color, float scanline)
{
float mx = max(max(color.r, color.g),color.b);
x = mix (x, beam_min*x, max(x-0.4*mx,0.0));
vec3 tmp = mix(vec3(1.2*beam_min),vec3(beam_max), color);
vec3 ex = x*tmp;
float br = clamp(0.8*beam_min - 1.0, 0.2, 0.45);
return exp2(-scanline*ex*ex)/(1.0-br+br*color);
}
vec3 sw2(vec3 x, vec3 color, float scanline)
{
vec3 tmp = mix(vec3(2.75*beam_min),vec3(beam_max), color);
tmp = mix(vec3(beam_max), tmp, pow(x, vec3(max(max(color.r, color.g),color.b)+0.3)));
vec3 ex = x*tmp;
return exp2(-scanline*ex*ex)/(0.6 + 0.4*color);
} }
vec3 sw2(float x, vec3 c) // Shadow mask (1-4 from PD CRT Lottes shader).
{ vec3 Mask(vec2 pos, vec3 c)
vec3 s = mix(vec3(b_min), vec3(b_max), c);
return clamp(smoothstep(vec3(0.0), vec3(scn_s), pow(vec3(x),s)), 0.0001, 1.0);
}
// Shadow mask (mostly from PD Lottes shader).
vec3 Mask(vec2 pos)
{ {
pos = floor(pos/masksize);
vec3 mask = vec3(maskDark, maskDark, maskDark); vec3 mask = vec3(maskDark, maskDark, maskDark);
float mf = floor(mod(pos.x,2.0));
float mf2 = floor(mod(pos.x + pos.y,2.0));
float mc = 1.0 - CGWG;
float mc2 = mc * 0.7;
// No mask // No mask
if (shadowMask == -1.0) if (shadowMask == -1.0)
{ {
mask = vec3(1.0); mask = vec3(1.0);
} }
// Light mask.
else if (shadowMask == 5.0)
{
if (mf2 == 0.0) { mask = vec3(1.0); }
else { mask = vec3(mc2); }
}
// Phosphor. // Phosphor.
else if (shadowMask == 0.0) else if (shadowMask == 0.0)
{ {
if (mf == 0.0) { mask.r = 1.0; mask.g = mc; mask.b = 1.0; } pos.x = fract(pos.x*0.5);
else { mask.r = mc; mask.g = 1.0; mask.b = mc; } float mc = 1.0 - CGWG;
if (pos.x < 0.5) { mask.r = 1.1; mask.g = mc; mask.b = 1.1; }
else { mask.r = mc; mask.g = 1.1; mask.b = mc; }
} }
// Very compressed TV style shadow mask. // Very compressed TV style shadow mask.
@ -183,6 +202,7 @@ vec3 Mask(vec2 pos)
if (pos.x < 0.333) mask.r = maskLight; if (pos.x < 0.333) mask.r = maskLight;
else if (pos.x < 0.666) mask.g = maskLight; else if (pos.x < 0.666) mask.g = maskLight;
else mask.b = maskLight; else mask.b = maskLight;
mask*=line; mask*=line;
} }
@ -218,10 +238,64 @@ vec3 Mask(vec2 pos)
else if (pos.x < 0.666) mask.g = maskLight; else if (pos.x < 0.666) mask.g = maskLight;
else mask.b = maskLight; else mask.b = maskLight;
} }
// Alternate mask 5
else if (shadowMask == 5.0)
{
float mx = max(max(c.r,c.g),c.b);
vec3 maskTmp = vec3( min( 1.25*max(mx-mcut,0.0)/(1.0-mcut) ,maskDark + 0.2*(1.0-maskDark)*mx));
float adj = 0.80*maskLight - 0.5*(0.80*maskLight - 1.0)*mx + 0.75*(1.0-mx);
mask = maskTmp;
pos.x = fract(pos.x/2.0);
if (pos.x < 0.5)
{ mask.r = adj;
mask.b = adj;
}
else mask.g = adj;
}
// Alternate mask 6
else if (shadowMask == 6.0)
{
float mx = max(max(c.r,c.g),c.b);
vec3 maskTmp = vec3( min( 1.33*max(mx-mcut,0.0)/(1.0-mcut) ,maskDark + 0.225*(1.0-maskDark)*mx));
float adj = 0.80*maskLight - 0.5*(0.80*maskLight - 1.0)*mx + 0.75*(1.0-mx);
mask = maskTmp;
pos.x = fract(pos.x/3.0);
if (pos.x < 0.333) mask.r = adj;
else if (pos.x < 0.666) mask.g = adj;
else mask.b = adj;
}
// Alternate mask 7
else if (shadowMask == 7.0)
{
float mx = max(max(c.r,c.g),c.b);
float maskTmp = min(1.6*max(mx-mcut,0.0)/(1.0-mcut) ,1.0 + 0.6*(1.0-mx));
mask = vec3(maskTmp);
pos.x = fract(pos.x/2.0);
if (pos.x < 0.5) mask = vec3(1.0 + 0.6*(1.0-mx));
}
return mask; return mask;
} }
float SlotMask(vec2 pos, vec3 c)
{
if (slotmask == 0.0) return 1.0;
float mx = pow(max(max(c.r,c.g),c.b),1.33);
float mlen = slotwidth*2.0;
float px = fract(pos.x/mlen);
float py = floor(fract(pos.y/(2.0*double_slot))*2.0*double_slot);
float slot_dark = mix(1.0-slotmask, 1.0-0.80*slotmask, mx);
float slot = 1.0 + 0.7*slotmask*(1.0-mx);
if (py == 0.0 && px < 0.5) slot = slot_dark; else
if (py == double_slot && px >= 0.5) slot = slot_dark;
return slot;
}
// Distortion of scanlines, and end of screen alpha (PD Lottes Curvature) // Distortion of scanlines, and end of screen alpha (PD Lottes Curvature)
vec2 Warp(vec2 pos) vec2 Warp(vec2 pos)
{ {
@ -236,25 +310,19 @@ vec2 Overscan(vec2 pos, float dx, float dy){
return pos*0.5+0.5; return pos*0.5+0.5;
} }
float Overscan2(float pos, float dy){
pos=pos*2.0-1.0;
pos*=dy;
return pos*0.5+0.5;
}
// Borrowed from cgwg's crt-geom, under GPL // Borrowed from cgwg's crt-geom, under GPL
float corner(vec2 coord) float corner(vec2 coord)
{ {
coord *= SourceSize.xy / InputSize.xy;
coord = (coord - vec2(0.5)) * 1.0 + vec2(0.5); coord = (coord - vec2(0.5)) * 1.0 + vec2(0.5);
coord = min(coord, vec2(1.0)-coord) * vec2(1.0, params.OutputSize.y*params.OutputSize.z); coord = min(coord, vec2(1.0)-coord) * vec2(1.0, OutputSize.y/OutputSize.x);
vec2 cdist = vec2(max(csize,0.002)); vec2 cdist = vec2(max(csize, max((1.0-smoothstep(100.0,600.0,bsize))*0.01,0.002)));
coord = (cdist - min(coord,cdist)); coord = (cdist - min(coord,cdist));
float dist = sqrt(dot(coord,coord)); float dist = sqrt(dot(coord,coord));
return clamp((cdist.x-dist)*700.0,0.0, 1.0); return clamp((cdist.x-dist)*bsize,0.0, 1.0);
} }
const float sqrt3 = 1.732050807568877;
vec3 gamma_correct(vec3 color, vec3 tmp) vec3 gamma_correct(vec3 color, vec3 tmp)
{ {
@ -263,29 +331,27 @@ vec3 gamma_correct(vec3 color, vec3 tmp)
void main() void main()
{ {
vec3 lum = texture(lum_pass, vec2(0.33,0.33)).xyz; float lum = COMPAT_TEXTURE(PassPrev4Texture, vec2(0.33,0.33)).a;
// Calculating texel coordinates // Calculating texel coordinates
vec2 texcoord = vTexCoord.xy; vec2 texcoord = TEX0.xy;
if (IOS == 1.0){ if (IOS > 0.0){
vec2 ofactor = params.OutputSize.xy*params.SourceSize.zw; vec2 ofactor = OutputSize.xy/InputSize.xy;
vec2 intfactor = round(ofactor); vec2 intfactor = round(ofactor);
vec2 diff = ofactor/intfactor; vec2 diff = ofactor/intfactor;
vec2 smartcoord; float scan = mix(diff.y, diff.x, TATE);
smartcoord.x = Overscan2(vTexCoord.x, diff.x); texcoord = Overscan(texcoord*(SourceSize.xy/InputSize.xy), scan, scan)*(InputSize.xy/SourceSize.xy);
smartcoord.y = Overscan2(vTexCoord.y, diff.y); if (IOS == 1.0) texcoord = mix(vec2(TEX0.x, texcoord.y), vec2(texcoord.x, TEX0.y), TATE);
texcoord = (TATE > 0.5) ? vec2(smartcoord.x, texcoord.y) :
vec2(texcoord.x, smartcoord.y);
} }
float factor = 1.00 + (1.0-0.5*OS)*BLOOM/100.0 - lum.x*BLOOM/100.0; float factor = 1.00 + (1.0-0.5*OS)*BLOOM/100.0 - lum*BLOOM/100.0;
texcoord = Overscan(texcoord, factor, factor); texcoord = Overscan(texcoord*(SourceSize.xy/InputSize.xy), factor, factor)*(InputSize.xy/SourceSize.xy);
vec2 pos = Warp(texcoord); vec2 pos = Warp(texcoord*(TextureSize.xy/InputSize.xy))*(InputSize.xy/TextureSize.xy);
vec2 pos0 = Warp(vTexCoord.xy); vec2 pos0 = Warp(TEX0.xy*(TextureSize.xy/InputSize.xy))*(InputSize.xy/TextureSize.xy);
vec2 ps = params.SourceSize.zw; vec2 ps = SourceSize.zw;
vec2 OGL2Pos = pos * params.SourceSize.xy - ((TATE < 0.5) ? vec2 OGL2Pos = pos * SourceSize.xy - ((TATE < 0.5) ?
vec2(0.0,0.5) : vec2(0.5, 0.0)); vec2(0.0,0.5) : vec2(0.5, 0.0));
vec2 fp = fract(OGL2Pos); vec2 fp = fract(OGL2Pos);
vec2 dx = vec2(ps.x,0.0); vec2 dx = vec2(ps.x,0.0);
@ -310,63 +376,110 @@ void main()
} }
bool sharp = (s_sharp > 0.0); bool sharp = (s_sharp > 0.0);
float wl2 = 1.5 + fpx; wl2*=wl2; wl2 = exp2(-h_sharp*wl2); wl2 = max(wl2 - s_sharp, -wl2);
float wl1 = 0.5 + fpx; wl1*=wl1; wl1 = exp2(-h_sharp*wl1); wl1 = max(wl1 - s_sharp, -0.4*s_sharp);
float wct = 0.5 - fpx; wct*=wct; wct = exp2(-h_sharp*wct); wct = max(wct - s_sharp, s_sharp);
float wr1 = 1.5 - fpx; wr1*=wr1; wr1 = exp2(-h_sharp*wr1); wr1 = max(wr1 - s_sharp, -0.4*s_sharp);
float wr2 = 2.5 - fpx; wr2*=wr2; wr2 = exp2(-h_sharp*wr2); wr2 = max(wr2 - s_sharp, -wr2);
float wt = 1.0/(wl2+wl1+wct+wr1+wr2);
vec3 l2 = texture(linearize_pass, pC4 -off2).xyz;
vec3 l1 = texture(linearize_pass, pC4 -offx).xyz;
vec3 ct = texture(linearize_pass, pC4 ).xyz;
vec3 r1 = texture(linearize_pass, pC4 +offx).xyz;
vec3 r2 = texture(linearize_pass, pC4 +off2).xyz;
vec3 color1 = (l2*wl2 + l1*wl1 + ct*wct + r1*wr1 + r2*wr2)*wt; float hsharp_tl, hsharp_tr, hsharp_bl, hsharp_br, hsharp_tc, hsharp_bc;
if (h_smart == 0.0)
{
hsharp_tl = h_sharp; hsharp_tr = h_sharp; hsharp_bl = h_sharp; hsharp_br = h_sharp; hsharp_tc = h_sharp; hsharp_bc = h_sharp;
}
else
{
// reading differences for smoothing
vec3 diffs_top = COMPAT_TEXTURE(PassPrev4Texture, pC4 ).xyz;
vec3 diffs_bot = COMPAT_TEXTURE(PassPrev4Texture, pC4 + offy).xyz;
if(TATE > 0.5)
{
diffs_top.x = floor(10.0*diffs_top.z)*0.11111; diffs_top.y = fract(10.0*diffs_top.z)*1.11111;
diffs_bot.x = floor(10.0*diffs_bot.z)*0.11111; diffs_bot.y = fract(10.0*diffs_bot.z)*1.11111;
}
float ls = mix (4.5, 2.25, h_smart);
hsharp_tl = mix(h_sharp, ls, diffs_top.x);
hsharp_tr = mix(h_sharp, ls, diffs_top.y);
hsharp_bl = mix(h_sharp, ls, diffs_bot.x);
hsharp_br = mix(h_sharp, ls, diffs_bot.y);
hsharp_tc = hsharp_tl;
hsharp_bc = hsharp_bl;
if (fpx == 0.5) { hsharp_tc = 0.5*(hsharp_tl + hsharp_tr); hsharp_bc = 0.5*(hsharp_bl + hsharp_br); }
if (fpx > 0.5) { hsharp_tc = hsharp_tr; hsharp_bc = hsharp_bl; }
}
float wl2 = 1.5 + fpx; wl2*=wl2; float twl2 = exp2(-hsharp_tl*wl2); twl2 = max(twl2 - s_sharp, -twl2); float bwl2 = exp2(-hsharp_bl*wl2); bwl2 = max(bwl2 - s_sharp, -bwl2);
float wl1 = 0.5 + fpx; wl1*=wl1; float twl1 = exp2(-hsharp_tl*wl1); twl1 = max(twl1 - s_sharp, -0.4*s_sharp); float bwl1 = exp2(-hsharp_bl*wl1); bwl1 = max(bwl1 - s_sharp, -0.4*s_sharp);
float wct = 0.5 - fpx; wct*=wct; float twct = exp2(-hsharp_tc*wct); twct = max(twct - s_sharp, s_sharp); float bwct = exp2(-hsharp_bc*wct); bwct = max(bwct - s_sharp, s_sharp);
float wr1 = 1.5 - fpx; wr1*=wr1; float twr1 = exp2(-hsharp_tr*wr1); twr1 = max(twr1 - s_sharp, -0.4*s_sharp); float bwr1 = exp2(-hsharp_br*wr1); bwr1 = max(bwr1 - s_sharp, -0.4*s_sharp);
float wr2 = 2.5 - fpx; wr2*=wr2; float twr2 = exp2(-hsharp_tr*wr2); twr2 = max(twr2 - s_sharp, -twr2); float bwr2 = exp2(-hsharp_br*wr2); bwr2 = max(bwr2 - s_sharp, -bwr2);
float wtt = 1.0/(twl2+twl1+twct+twr1+twr2);
float wtb = 1.0/(bwl2+bwl1+bwct+bwr1+bwr2);
vec3 l2 = COMPAT_TEXTURE(PassPrev3Texture, pC4 -off2).xyz;
vec3 l1 = COMPAT_TEXTURE(PassPrev3Texture, pC4 -offx).xyz;
vec3 ct = COMPAT_TEXTURE(PassPrev3Texture, pC4 ).xyz;
vec3 r1 = COMPAT_TEXTURE(PassPrev3Texture, pC4 +offx).xyz;
vec3 r2 = COMPAT_TEXTURE(PassPrev3Texture, pC4 +off2).xyz;
vec3 color1 = (l2*twl2 + l1*twl1 + ct*twct + r1*twr1 + r2*twr2)*wtt;
if (sharp) color1 = clamp(color1, min(min(l1,r1),ct), max(max(l1,r1),ct)); if (sharp) color1 = clamp(color1, min(min(l1,r1),ct), max(max(l1,r1),ct));
l2 = texture(linearize_pass, pC4 -off2 +offy).xyz; l2 = COMPAT_TEXTURE(PassPrev3Texture, pC4 -off2 +offy).xyz;
l1 = texture(linearize_pass, pC4 -offx +offy).xyz; l1 = COMPAT_TEXTURE(PassPrev3Texture, pC4 -offx +offy).xyz;
ct = texture(linearize_pass, pC4 +offy).xyz; ct = COMPAT_TEXTURE(PassPrev3Texture, pC4 +offy).xyz;
r1 = texture(linearize_pass, pC4 +offx +offy).xyz; r1 = COMPAT_TEXTURE(PassPrev3Texture, pC4 +offx +offy).xyz;
r2 = texture(linearize_pass, pC4 +off2 +offy).xyz; r2 = COMPAT_TEXTURE(PassPrev3Texture, pC4 +off2 +offy).xyz;
vec3 color2 = (l2*wl2 + l1*wl1 + ct*wct + r1*wr1 + r2*wr2)*wt; vec3 color2 = (l2*bwl2 + l1*bwl1 + ct*bwct + r1*bwr1 + r2*bwr2)*wtb;
if (sharp) color2 = clamp(color2, min(min(l1,r1),ct), max(max(l1,r1),ct)); if (sharp) color2 = clamp(color2, min(min(l1,r1),ct), max(max(l1,r1),ct));
// calculating scanlines // calculating scanlines
float f = (TATE < 0.5) ? fp.y : fp.x; float f = (TATE < 0.5) ? fp.y : fp.x;
vec3 w1 = sw(f,color1); float shape1 = mix(scanline1, scanline2, f);
vec3 w2 = sw(1.0-f,color2); float shape2 = mix(scanline1, scanline2, 1.0-f);
if (gsl == 1.0) { w1 = sw2(1.0-f,color1); w2 = sw2(f,color2);} float wt1 = st(f, shape1);
float wt2 = st(1.0-f, shape2);
vec3 color0 = color1*wt1 + color2*wt2;
vec3 ctmp = color0/(wt1+wt2);
vec3 tmp = pow(ctmp, vec3(1.0/gamma_out));
vec3 w1,w2 = vec3(0.0);
vec3 cref1 = mix(ctmp, color1, beam_size);
vec3 cref2 = mix(ctmp, color2, beam_size);
vec3 shift = vec3(-vertmask, vertmask, -vertmask);
vec3 f1 = clamp(vec3(f) + shift*0.5*(1.0+f), 0.0, 1.0);
vec3 f2 = clamp(vec3(1.0-f) - shift*0.5*(2.0-f), 0.0, 1.0);
if (gsl == 0.0) { w1 = sw0(f1,cref1,shape1); w2 = sw0(f2,cref2,shape2);} else
if (gsl == 1.0) { w1 = sw1(f1,cref1,shape1); w2 = sw1(f2,cref2,shape2);} else
if (gsl == 2.0) { w1 = sw2(f1,cref1,shape1); w2 = sw2(f2,cref2,shape2);}
vec3 color = color1*w1 + color2*w2; vec3 color = color1*w1 + color2*w2;
vec3 ctmp = color/(w1+w2);
color*=brightboost;
color = pow(color, vec3(1.0/gamma_out)); color = min(color, 1.0);
float l = length(color);
color = normalize(pow(color + vec3(eps), vec3(saturation,saturation,saturation)))*l;
color*=brightboost;
color = gamma_correct(color,ctmp);
color = pow(color, vec3(gamma_out));
color = min(color, 1.0);
// Apply Mask // Apply Mask
color *= (TATE < 0.5) ? Mask(gl_FragCoord.xy * 1.000001) : color *= (TATE < 0.5) ? Mask(gl_FragCoord.xy * 1.000001,tmp) :
Mask(gl_FragCoord.yx * 1.000001); Mask(gl_FragCoord.yx * 1.000001,tmp);
vec3 Bloom = texture(Source, pos).xyz; color = min(color,1.0);
color *= (TATE < 0.5) ? SlotMask(gl_FragCoord.xy * 1.000001,tmp) :
SlotMask(gl_FragCoord.yx * 1.000001,tmp);
vec3 Bloom = COMPAT_TEXTURE(Texture, pos).xyz;
color+=glow*Bloom; color+=glow*Bloom;
color = min(color, 1.0);
color = pow(color, vec3(1.0/gamma_out)); color = pow(color, vec3(1.0/gamma_out));
FragColor = vec4(color*corner(pos0), 1.0); FragColor = vec4(color*corner(pos0), 1.0);
} }

View file

@ -6,10 +6,15 @@ layout(push_constant) uniform Push
vec4 OriginalSize; vec4 OriginalSize;
vec4 OutputSize; vec4 OutputSize;
uint FrameCount; uint FrameCount;
float WP; float WP;
} params; } params;
#pragma parameter WP "D65 to D50 strength %" 0.0 -100.0 100.0 5.0 #pragma parameter WP "Color Temperature %" 0.0 -100.0 100.0 5.0
#define WP params.WP
#define COMPAT_TEXTURE(c,d) texture(c,d)
#define TEX0 vTexCoord
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
{ {
@ -32,26 +37,46 @@ layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor; layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source; layout(set = 0, binding = 2) uniform sampler2D Source;
const mat3 D65 = mat3 ( const mat3 D65_to_XYZ = mat3 (
0.5767309, 0.2973769, 0.0270343, 0.4306190, 0.2220379, 0.0201853,
0.1855540, 0.6273491, 0.0706872, 0.3415419, 0.7066384, 0.1295504,
0.1881852, 0.0752741, 0.9911085); 0.1783091, 0.0713236, 0.9390944);
const mat3 D50 = mat3 ( const mat3 XYZ_to_D65 = mat3 (
1.7552599, -0.5441336, 0.0063467, 3.0628971, -0.9692660, 0.0678775,
-0.4836786, 1.5068789, -0.0175761, -1.3931791, 1.8760108, -0.2288548,
-0.2530000, 0.0215528, 1.2256959); -0.4757517, 0.0415560, 1.0693490);
const mat3 D50_to_XYZ = mat3 (
0.4552773, 0.2323025, 0.0145457,
0.3675500, 0.7077956, 0.1049154,
0.1413926, 0.0599019, 0.7057489);
const mat3 XYZ_to_D50 = mat3 (
2.9603944, -0.9787684, 0.0844874,
-1.4678519, 1.9161415, -0.2545973,
-0.4685105, 0.0334540, 1.4216174);
void main() void main()
{ {
vec3 color = texture(Source, vTexCoord.xy).rgb; vec3 color = COMPAT_TEXTURE(Source, TEX0.xy).rgb;
float p = 2.4;
vec3 c65 = D65*color; color = pow(color, vec3(p));
vec3 c50 = D50*c65;
float m = params.WP/100.0; vec3 warmer = D50_to_XYZ*color;
warmer = XYZ_to_D65*warmer;
color = (1.0-m)*color + m*c50; vec3 cooler = D65_to_XYZ*color;
cooler = XYZ_to_D50*cooler;
float m = abs(WP)/100.0;
vec3 comp = (WP < 0.0) ? cooler : warmer;
color = mix(color, comp, m);
color = pow(color, vec3(1.0/p));
FragColor = vec4(color,1.0); FragColor = vec4(color,1.0);
} }

View file

@ -0,0 +1,126 @@
#version 450
/*
CRT - Guest - Dr. Venom - Pass1
Copyright (C) 2018-2019 guest(r) - guest.r@gmail.com
Incorporates many good ideas and suggestions from Dr. Venom.
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.
*/
layout(push_constant) uniform Push
{
vec4 SourceSize;
vec4 OriginalSize;
vec4 OutputSize;
uint FrameCount;
float h_sharp;
float s_sharp;
float h_smart;
} params;
#pragma parameter h_sharp "Horizontal sharpness" 5.00 1.5 20.0 0.25
#define h_sharp params.h_sharp
#pragma parameter s_sharp "Substractive sharpness" 0.05 0.0 0.20 0.01
#define s_sharp params.s_sharp
#pragma parameter h_smart "Smart Horizontal Smoothing" 0.0 0.0 1.0 0.1
#define h_smart params.h_smart
#define SourceSize params.SourceSize
layout(std140, set = 0, binding = 0) uniform UBO
{
mat4 MVP;
} global;
#pragma stage vertex
layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 vTexCoord;
void main()
{
gl_Position = global.MVP * Position;
vTexCoord = TexCoord * 1.00001;
}
#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 SmoothPass;
#define COMPAT_TEXTURE(c,d) texture(c,d)
#define PassPrev2Texture SmoothPass
void main()
{
vec2 ps = SourceSize.zw;
vec2 OGL2Pos = vTexCoord * SourceSize.xy;
vec2 fp = fract(OGL2Pos);
vec2 dx = vec2(ps.x,0.0);
vec2 dy = vec2(0.0, ps.y);
vec2 pC4 = floor(OGL2Pos) * ps + 0.5*ps;
// Reading the texels
vec2 x2 = 2.0*dx;
vec2 y2 = 2.0*dy;
bool sharp = (s_sharp > 0.0);
float hsharp_tl, hsharp_tr, hsharp_tc; float s_sharpl = s_sharp; float s_sharpr = s_sharp; float s_sharpc = s_sharp;
if (h_smart == 0.0)
{
hsharp_tl = h_sharp; hsharp_tr = h_sharp; hsharp_tc = h_sharp;
}
else
{
// reading differences for smoothing
vec2 diffs = COMPAT_TEXTURE(PassPrev2Texture, pC4).xy;
float ls = mix (4.25, 2.25, h_smart);
hsharp_tl = mix(h_sharp, ls, diffs.x);
hsharp_tr = mix(h_sharp, ls, diffs.y);
s_sharpl = mix(s_sharp, 0.0, diffs.x);
s_sharpr = mix(s_sharp, 0.0, diffs.y);
hsharp_tc = hsharp_tl;
if (fp.x == 0.5) { hsharp_tc = 0.5*(hsharp_tl + hsharp_tr); s_sharpc = 0.5*(s_sharpl + s_sharpr); }
if (fp.x > 0.5) { hsharp_tc = hsharp_tr; }
}
float wl2 = 1.5 + fp.x; wl2*=wl2; float twl2 = exp2(-hsharp_tl*wl2); twl2 = max(twl2 - s_sharpl, -twl2);
float wl1 = 0.5 + fp.x; wl1*=wl1; float twl1 = exp2(-hsharp_tl*wl1); twl1 = max(twl1 - s_sharpl, -0.4*s_sharpl);
float wct = 0.5 - fp.x; wct*=wct; float twct = exp2(-hsharp_tc*wct); twct = max(twct - s_sharpc, s_sharpc);
float wr1 = 1.5 - fp.x; wr1*=wr1; float twr1 = exp2(-hsharp_tr*wr1); twr1 = max(twr1 - s_sharpr, -0.4*s_sharpr);
float wr2 = 2.5 - fp.x; wr2*=wr2; float twr2 = exp2(-hsharp_tr*wr2); twr2 = max(twr2 - s_sharpr, -twr2);
float wtt = 1.0/(twl2+twl1+twct+twr1+twr2);
vec3 l2 = COMPAT_TEXTURE(Source, pC4 -x2).xyz;
vec3 l1 = COMPAT_TEXTURE(Source, pC4 -dx).xyz;
vec3 ct = COMPAT_TEXTURE(Source, pC4 ).xyz;
vec3 r1 = COMPAT_TEXTURE(Source, pC4 +dx).xyz;
vec3 r2 = COMPAT_TEXTURE(Source, pC4 +x2).xyz;
vec3 color = (l2*twl2 + l1*twl1 + ct*twct + r1*twr1 + r2*twr2)*wtt;
if (sharp) color = clamp(color, 0.8*min(min(l1,r1),ct), 1.2*max(max(l1,r1),ct));
FragColor = vec4(color, 1.0);
}

View file

@ -0,0 +1,328 @@
#version 450
/*
CRT - Guest - Dr. Venom - Pass2
Copyright (C) 2018-2019 guest(r) - guest.r@gmail.com
Incorporates many good ideas and suggestions from Dr. Venom.
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.
*/
layout(push_constant) uniform Push
{
float brightboost, IOS, gsl, scanline1, scanline2, beam_min, beam_max, s_power, beam_size, shadowMask,
masksize, vertmask, slotmask, slotwidth, double_slot, mcut, maskDark, maskLight, CGWG, gamma_out;
} params;
#pragma parameter brightboost "Bright boost" 1.30 0.50 2.00 0.01
#define brightboost params.brightboost // adjust brightness
#pragma parameter IOS "Smart Y Integer Scaling" 0.0 0.0 1.0 1.0
#define IOS params.IOS // smart integer scaling
#pragma parameter gsl "Scanline Type" 1.0 0.0 2.0 1.0
#define gsl params.gsl // Alternate scanlines
#pragma parameter scanline1 "Scanline beam shape low" 8.0 1.0 15.0 1.0
#define scanline1 params.scanline1 // scanline param, vertical sharpness
#pragma parameter scanline2 "Scanline beam shape high" 8.0 5.0 23.0 1.0
#define scanline2 params.scanline2 // scanline param, vertical sharpness
#pragma parameter beam_min "Scanline dark" 1.25 0.5 2.0 0.05
#define beam_min params.beam_min // dark area beam min - narrow
#pragma parameter beam_max "Scanline bright" 1.05 0.5 2.0 0.05
#define beam_max params.beam_max // bright area beam max - wide
#pragma parameter s_power "Scanline intensity" 1.0 0.5 2.5 0.05
#define s_power params.s_power // scanline intensity
#pragma parameter beam_size "Increased bright scanline beam" 0.65 0.0 1.0 0.05
#define beam_size params.beam_size // increased max. beam size
#pragma parameter shadowMask "CRT Mask: 0:CGWG, 1-4:Lottes, 5-6:'Trinitron'" 5.0 -1.0 6.0 1.0
#define shadowMask params.shadowMask // Mask Style
#pragma parameter masksize "CRT Mask Size (2.0 is nice in 4k)" 1.0 1.0 2.0 1.0
#define masksize params.masksize // Mask Size
#pragma parameter vertmask "PVM Like Colors" 0.05 0.0 0.25 0.01
#define vertmask params.vertmask // Vertical mask
#pragma parameter slotmask "Slot Mask Strength" 0.0 0.0 1.0 0.05
#define slotmask params.slotmask // Slot Mask ON/OFF
#pragma parameter slotwidth "Slot Mask Width" 2.0 2.0 6.0 0.5
#define slotwidth params.slotwidth // Slot Mask Width
#pragma parameter double_slot "Slot Mask Height: 2x1 or 4x1" 1.0 1.0 2.0 1.0
#define double_slot params.double_slot // Slot Mask Height
#pragma parameter mcut "Mask 5&6 cutoff" 0.2 0.0 0.5 0.05
#define mcut params.mcut // Mask 5&6 cutoff
#pragma parameter maskDark "Mask Dark" 0.5 0.0 2.0 0.05
#define maskDark params.maskDark // Dark "Phosphor"
#pragma parameter maskLight "Mask Light" 1.5 0.0 2.0 0.05
#define maskLight params.maskLight // Light "Phosphor"
#pragma parameter CGWG "CGWG Mask Str." 0.3 0.0 1.0 0.05
#define CGWG params.CGWG // CGWG Mask Strength
#pragma parameter gamma_out "Gamma out" 2.4 1.0 3.5 0.05
#define gamma_out params.gamma_out // output gamma
layout(std140, set = 0, binding = 0) uniform UBO
{
mat4 MVP;
vec4 SourceSize;
vec4 OutputSize;
uint FrameCount;
} global;
#define SourceSize global.SourceSize
#define OutputSize global.OutputSize
#define FrameCount global.FrameCount
#define COMPAT_TEXTURE(c,d) texture(c,d)
#define gl_FragCoord (vTexCoord.xy * OutputSize.xy)
#define InputSize SourceSize
#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 * 1.00001;
}
#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source;
#define eps 1e-10
float st(float x, float scanline)
{
return exp2(-scanline*x*x);
}
vec3 sw0(vec3 x, vec3 color, float scanline)
{
vec3 tmp = mix(vec3(beam_min),vec3(beam_max), color);
vec3 ex = x*tmp;
return exp2(-scanline*ex*ex);
}
vec3 sw1(vec3 x, vec3 color, float scanline)
{
float mx = max(max(color.r, color.g),color.b);
x = mix (x, beam_min*x, max(x-0.4*mx,0.0));
vec3 tmp = mix(vec3(1.2*beam_min),vec3(beam_max), color);
vec3 ex = x*tmp;
float br = clamp(0.8*beam_min - 1.0, 0.2, 0.45);
return exp2(-scanline*ex*ex)/(1.0-br+br*color);
}
vec3 sw2(vec3 x, vec3 color, float scanline)
{
vec3 tmp = mix(vec3(2.75*beam_min),vec3(beam_max), color);
tmp = mix(vec3(beam_max), tmp, pow(x, vec3(max(max(color.r, color.g),color.b)+0.3)));
vec3 ex = x*tmp;
return exp2(-scanline*ex*ex)/(0.6 + 0.4*color);
}
// Shadow mask (1-4 from PD CRT Lottes shader).
vec3 Mask(vec2 pos, vec3 c)
{
pos = floor(pos/masksize);
vec3 mask = vec3(maskDark, maskDark, maskDark);
// No mask
if (shadowMask == -1.0)
{
mask = vec3(1.0);
}
// Phosphor.
else if (shadowMask == 0.0)
{
pos.x = fract(pos.x*0.5);
float mc = 1.0 - CGWG;
if (pos.x < 0.5) { mask.r = 1.1; mask.g = mc; mask.b = 1.1; }
else { mask.r = mc; mask.g = 1.1; mask.b = mc; }
}
// Very compressed TV style shadow mask.
else if (shadowMask == 1.0)
{
float line = maskLight;
float odd = 0.0;
if (fract(pos.x/6.0) < 0.5)
odd = 1.0;
if (fract((pos.y + odd)/2.0) < 0.5)
line = maskDark;
pos.x = fract(pos.x/3.0);
if (pos.x < 0.333) mask.r = maskLight;
else if (pos.x < 0.666) mask.g = maskLight;
else mask.b = maskLight;
mask*=line;
}
// Aperture-grille.
else if (shadowMask == 2.0)
{
pos.x = fract(pos.x/3.0);
if (pos.x < 0.333) mask.r = maskLight;
else if (pos.x < 0.666) mask.g = maskLight;
else mask.b = maskLight;
}
// Stretched VGA style shadow mask (same as prior shaders).
else if (shadowMask == 3.0)
{
pos.x += pos.y*3.0;
pos.x = fract(pos.x/6.0);
if (pos.x < 0.333) mask.r = maskLight;
else if (pos.x < 0.666) mask.g = maskLight;
else mask.b = maskLight;
}
// VGA style shadow mask.
else if (shadowMask == 4.0)
{
pos.xy = floor(pos.xy*vec2(1.0, 0.5));
pos.x += pos.y*3.0;
pos.x = fract(pos.x/6.0);
if (pos.x < 0.333) mask.r = maskLight;
else if (pos.x < 0.666) mask.g = maskLight;
else mask.b = maskLight;
}
// Alternate mask 5
else if (shadowMask == 5.0)
{
float mx = max(max(c.r,c.g),c.b);
vec3 maskTmp = vec3( min( 1.25*max(mx-mcut,0.0)/(1.0-mcut) ,maskDark + 0.2*(1.0-maskDark)*mx));
float adj = 0.80*maskLight - 0.5*(0.80*maskLight - 1.0)*mx + 0.75*(1.0-mx);
mask = maskTmp;
pos.x = fract(pos.x/2.0);
if (pos.x < 0.5)
{ mask.r = adj;
mask.b = adj;
}
else mask.g = adj;
}
// Alternate mask 6
else if (shadowMask == 6.0)
{
float mx = max(max(c.r,c.g),c.b);
vec3 maskTmp = vec3( min( 1.5*max(mx-mcut,0.0)/(1.0-mcut) ,maskDark + 0.225*(1.0-maskDark)*mx));
float adj = 0.80*maskLight - 0.5*(0.80*maskLight - 1.0)*mx + 0.75*(1.0-mx);
mask = maskTmp;
pos.x = fract(pos.x/3.0);
if (pos.x < 0.333) mask.r = adj;
else if (pos.x < 0.666) mask.g = adj;
else mask.b = adj;
}
return mask;
}
float SlotMask(vec2 pos, vec3 c)
{
if (slotmask == 0.0) return 1.0;
float mx = pow(max(max(c.r,c.g),c.b),1.33);
float mlen = slotwidth*2.0;
float px = fract(pos.x/mlen);
float py = floor(fract(pos.y/(2.0*double_slot))*2.0*double_slot);
float slot_dark = mix(1.0-slotmask, 1.0-0.80*slotmask, mx);
float slot = 1.0 + 0.7*slotmask*(1.0-mx);
if (py == 0.0 && px < 0.5) slot = slot_dark; else
if (py == double_slot && px >= 0.5) slot = slot_dark;
return slot;
}
float Overscan2(float pos, float dy){
pos=pos*2.0-1.0;
pos*=dy;
return pos*0.5+0.5;
}
void main()
{
vec2 texcoord = vTexCoord;
if (IOS == 1.0){
float ofactor = OutputSize.y/InputSize.y;
float intfactor = round(ofactor);
float diff = ofactor/intfactor;
texcoord.y = Overscan2(texcoord.y*(SourceSize.y/InputSize.y), diff)*(InputSize.y/SourceSize.y);
}
vec2 ps = SourceSize.zw;
vec2 OGL2Pos = texcoord * SourceSize.xy - vec2(0.0,0.5);
vec2 fp = fract(OGL2Pos);
vec2 dx = vec2(ps.x,0.0);
vec2 dy = vec2(0.0, ps.y);
vec2 pC4 = floor(OGL2Pos) * ps + 0.5*ps;
vec3 color1 = COMPAT_TEXTURE(Source, pC4 ).xyz;
vec3 color2 = COMPAT_TEXTURE(Source, pC4 +dy).xyz;
// calculating scanlines
float f = fp.y;
float shape1 = mix(scanline1, scanline2, f);
float shape2 = mix(scanline1, scanline2, 1.0-f);
float wt1 = st(f, shape1);
float wt2 = st(1.0-f, shape2);
vec3 color0 = color1*wt1 + color2*wt2;
vec3 ctmp = color0/(wt1+wt2);
vec3 tmp = pow(ctmp, vec3(1.0/gamma_out));
vec3 w1,w2 = vec3(0.0);
vec3 cref1 = mix(ctmp, color1, beam_size);
vec3 cref2 = mix(ctmp, color2, beam_size);
vec3 shift = vec3(-vertmask, vertmask, -vertmask);
vec3 f1 = clamp(vec3(f) + shift*0.5*(1.0+f), 0.0, 1.0);
vec3 f2 = clamp(vec3(1.0-f) - shift*0.5*(2.0-f), 0.0, 1.0);
if (gsl == 0.0) { w1 = sw0(f1,cref1,shape1); w2 = sw0(f2,cref2,shape2);} else
if (gsl == 1.0) { w1 = sw1(f1,cref1,shape1); w2 = sw1(f2,cref2,shape2);} else
if (gsl == 2.0) { w1 = sw2(f1,cref1,shape1); w2 = sw2(f2,cref2,shape2);}
vec3 color = color1*pow(w1, vec3(s_power)) + color2*pow(w2, vec3(s_power));
color*=brightboost;
color = min(color, 1.0);
// Apply Mask
color *= Mask(gl_FragCoord.xy * 1.000001,tmp);
color = min(color,1.0);
color *= SlotMask(gl_FragCoord.xy * 1.000001,tmp);
color = pow(color, vec3(1.0/gamma_out));
FragColor = vec4(color, 1.0);
}

View file

@ -0,0 +1,39 @@
#version 450
layout(push_constant) uniform Push
{
vec4 SourceSize;
vec4 OriginalSize;
vec4 OutputSize;
uint FrameCount;
float GAMMA_INPUT;
} params;
#pragma parameter GAMMA_INPUT "Gamma Input" 2.4 0.1 5.0 0.05
#define GAMMA_INPUT params.GAMMA_INPUT
layout(std140, set = 0, binding = 0) uniform UBO
{
mat4 MVP;
} global;
#pragma stage vertex
layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 vTexCoord;
void main()
{
gl_Position = global.MVP * Position;
vTexCoord = TexCoord;
}
#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Original;
void main()
{
FragColor = pow(texture(Original, vTexCoord), vec4(GAMMA_INPUT));
}

View file

@ -0,0 +1,84 @@
#version 450
/*
Smart Smoothing Difference Shader
Copyright (C) 2019 guest(r) - guest.r@gmail.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
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.
*/
#pragma name SmoothPass
layout(push_constant) uniform Push
{
vec4 SourceSize;
vec4 OriginalSize;
vec4 OutputSize;
uint FrameCount;
float STH;
} params;
#pragma parameter STH "Smart Smoothing Threshold" 0.7 0.4 1.2 0.05
#define STH params.STH
#define SourceSize params.SourceSize
#define COMPAT_TEXTURE(c,d) texture(c,d)
layout(std140, set = 0, binding = 0) uniform UBO
{
mat4 MVP;
} global;
#pragma stage vertex
layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 vTexCoord;
void main()
{
gl_Position = global.MVP * Position;
vTexCoord = TexCoord;
}
#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source;
float df (vec3 A, vec3 B)
{
float diff = length(A-B);
float luma = clamp(length(0.5*min(A,B) + 0.25*(A+B) + 1e-8), 0.0001, 1.0);
float diff1 = diff/luma;
return 1.0 - clamp(7.0*(max(1.5*diff,diff1)-STH), 0.0, 1.0);
}
void main()
{
vec2 dx = vec2(SourceSize.z, 0.0);
vec2 dy = vec2(0.0, SourceSize.w);
vec3 l1 = COMPAT_TEXTURE(Source, vTexCoord.xy -dx).xyz;
vec3 ct = COMPAT_TEXTURE(Source, vTexCoord.xy ).xyz;
vec3 r1 = COMPAT_TEXTURE(Source, vTexCoord.xy +dx).xyz;
float dl = df(ct, l1);
float dr = df(ct, r1);
float resx = dl; float resy = dr;
FragColor = vec4(resx,resy,1.0,1.0);
}

View file

@ -2,14 +2,11 @@
layout(push_constant) uniform Push layout(push_constant) uniform Push
{ {
vec4 SourceSize;
vec4 OriginalSize;
vec4 OutputSize;
uint FrameCount;
float GAMMA_INPUT; float GAMMA_INPUT;
} params; } params;
#pragma parameter GAMMA_INPUT "Gamma Input" 2.4 0.1 5.0 0.05 #pragma parameter GAMMA_INPUT "Gamma Input" 2.4 0.1 5.0 0.05
#define GAMMA_INPUT params.GAMMA_INPUT
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
{ {
@ -30,9 +27,12 @@ void main()
#pragma stage fragment #pragma stage fragment
layout(location = 0) in vec2 vTexCoord; layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor; layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D temp_pass; layout(set = 0, binding = 2) uniform sampler2D AfterglowPass;
#define PassPrev3Texture AfterglowPass
#define COMPAT_TEXTURE(c,d) texture(c,d)
void main() void main()
{ {
FragColor = pow(vec4(texture(temp_pass, vTexCoord)), vec4(params.GAMMA_INPUT)); FragColor = pow(vec4(COMPAT_TEXTURE(PassPrev3Texture, vTexCoord)), vec4(GAMMA_INPUT));
} }

View file

@ -0,0 +1 @@
LUT's kindly provided by torridgristle.

View file

@ -0,0 +1,104 @@
#version 450
layout(push_constant) uniform Push
{
vec4 SourceSize;
vec4 OriginalSize;
vec4 OutputSize;
uint FrameCount;
float TNTC;
} params;
#pragma parameter TNTC "LUT Colors" 0.0 0.0 3.0 1.0
#define TNTC params.TNTC
layout(std140, set = 0, binding = 0) uniform UBO
{
mat4 MVP;
} global;
#pragma stage vertex
layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 vTexCoord;
void main()
{
gl_Position = global.MVP * Position;
vTexCoord = TexCoord;
}
#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source;
layout(set = 0, binding = 3) uniform sampler2D SamplerLUT1;
layout(set = 0, binding = 4) uniform sampler2D SamplerLUT2;
layout(set = 0, binding = 5) uniform sampler2D SamplerLUT3;
#define LUT_Size 32.0
#define COMPAT_TEXTURE(c,d) texture(c,d)
const mat3 D65_to_XYZ = mat3 (
0.4306190, 0.2220379, 0.0201853,
0.3415419, 0.7066384, 0.1295504,
0.1783091, 0.0713236, 0.9390944);
const mat3 XYZ_to_D50 = mat3 (
2.9603944, -0.9787684, 0.0844874,
-1.4678519, 1.9161415, -0.2545973,
-0.4685105, 0.0334540, 1.4216174);
// This shouldn't be necessary but it seems some undefined values can
// creep in and each GPU vendor handles that differently. This keeps
// all values within a safe range
vec4 mixfix(vec4 a, vec4 b, float c)
{
return (a.z < 1.0) ? mix(a, b, c) : a;
}
void main()
{
vec4 imgColor = COMPAT_TEXTURE(Source, vTexCoord.xy);
float red = ( imgColor.r * (LUT_Size - 1.0) + 0.499999 ) / (LUT_Size * LUT_Size);
float green = ( imgColor.g * (LUT_Size - 1.0) + 0.499999 ) / LUT_Size;
float blue1 = (floor( imgColor.b * (LUT_Size - 1.0) ) / LUT_Size) + red;
float blue2 = (ceil( imgColor.b * (LUT_Size - 1.0) ) / LUT_Size) + red;
float mixer = clamp(max((imgColor.b - blue1) / (blue2 - blue1), 0.0), 0.0, 32.0);
vec4 color1, color2, res;
if (int(TNTC) == 1)
{
color1 = COMPAT_TEXTURE( SamplerLUT1, vec2( blue1, green ));
color2 = COMPAT_TEXTURE( SamplerLUT1, vec2( blue2, green ));
res = mixfix(color1, color2, mixer);
float mx = max(res.r,max(res.g,res.b));
float l = mix(length(imgColor.rgb), length(res.rgb), max(mx-0.5,0.0));
res.rgb = mix(imgColor.rgb, res.rgb, clamp(25.0*(mx-0.02),0.0,1.0));
res.rgb = normalize(res.rgb+1e-10)*l;
vec3 cooler = D65_to_XYZ*res.rgb;
cooler = XYZ_to_D50*cooler;
res.rgb = mix(res.rgb, cooler, 0.25);
}
else if (int(TNTC) == 2)
{
color1 = COMPAT_TEXTURE( SamplerLUT2, vec2( blue1, green ));
color2 = COMPAT_TEXTURE( SamplerLUT2, vec2( blue2, green ));
res = mixfix(color1, color2, mixer);
float l = mix(length(imgColor.rgb), length(res.rgb), 0.4);
res.rgb = normalize(res.rgb + 1e-10)*l;
}
else if (int(TNTC) == 3)
{
color1 = COMPAT_TEXTURE( SamplerLUT3, vec2( blue1, green ));
color2 = COMPAT_TEXTURE( SamplerLUT3, vec2( blue2, green ));
res = mixfix(color1, color2, mixer);
res.rgb = pow(res.rgb, vec3(1.0/1.20));
float mx = max(res.r,max(res.g,res.b));
res.rgb = mix(imgColor.rgb, res.rgb, clamp(25.0*(mx-0.05),0.0,1.0));
float l = length(imgColor.rgb);
res.rgb = normalize(res.rgb + 1e-10)*l;
}
FragColor = vec4(mix(imgColor.rgb, res.rgb, min(TNTC,1.0)),1.0);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -0,0 +1,80 @@
shaders = 11
shader0 = ../ntsc/shaders/ntsc-pass1-composite-2phase.slang
shader1 = ../ntsc/shaders/ntsc-pass2-2phase-gamma.slang
filter_linear0 = false
filter_linear1 = false
scale_type_x0 = source
scale_type_y0 = source
scale_x0 = 4.0
scale_y0 = 1.0
frame_count_mod0 = 2
float_framebuffer0 = true
scale_type1 = source
scale_x1 = 0.5
scale_y1 = 1.0
shader2 = ../crt/shaders/guest/lut/lut.slang
filter_linear2 = false
scale_type2 = source
scale2 = 1.0
textures = "SamplerLUT1;SamplerLUT2;SamplerLUT3"
SamplerLUT1 = ../crt/shaders/guest/lut/sony_trinitron1.png
SamplerLUT1_linear = true
SamplerLUT2 = ../crt/shaders/guest/lut/sony_trinitron2.png
SamplerLUT2_linear = true
SamplerLUT3 = ../crt/shaders/guest/lut/other1.png
SamplerLUT3_linear = true
shader3 = ../crt/shaders/guest/d65-d50.slang
filter_linear3 = false
scale_type3 = source
scale3 = 1.0
alias3 = WhitePointPass
shader4 = ../crt/shaders/guest/afterglow.slang
filter_linear4 = false
scale_type4 = source
scale4 = 1.0
alias4 = AfterglowPass
shader5 = ../crt/shaders/guest/avg-lum0.slang
filter_linear5 = false
scale_type5 = source
scale5 = 1.0
shader6 = ../crt/shaders/guest/avg-lum.slang
filter_linear6 = false
scale_type6 = source
scale6 = 1.0
mipmap_input6 = true
alias6 = AvgLumPass
shader7 = ../crt/shaders/guest/linearize.slang
filter_linear7 = false
scale_type7 = source
scale7 = 1.0
float_framebuffer7 = true
alias7 = LinearizePass
shader8 = ../crt/shaders/guest/blur_horiz.slang
filter_linear8 = false
scale_type8 = source
scale8 = 1.0
float_framebuffer8 = true
shader9 = ../crt/shaders/guest/blur_vert.slang
filter_linear9 = false
scale_type9 = source
scale9 = 1.0
float_framebuffer9 = true
shader10 = ../crt/shaders/guest/crt-guest-dr-venom.slang
filter_linear10 = true
scale_type10 = viewport
scale_x10 = 1.0
scale_y10 = 1.0