Another lightweight shader idea


#1

Just an idea I came up with after playing around with scanline overlays.

I think this might make for a good lightweight shader option that’s easy to use. This should be able to do very bold and dynamic scanlines or very light scanlines, depending on preference.

Parameter settings:

Retroarch vertical resolution- choose 896, 960 or 1120 to match the resolution being used (or auto-detect? “If Retroarch vertical resolution is 896/960, use A overlays for scanline beam width variation. If resolution is 1120, use B overlays for scanline beam width variation”)

Scanline beam width variation- choose between overlays 1-4 for 896/960. Choose between overlays 1-9 for 1120. Higher numbers = more beam width variation, more glow/bloom

Scanline overlay opacity: 0-100%

Add TVout-tweaks-multipass shader code.

Add dotmask shader code.

Scanline overlay patterns (numbers represent % black, 100 is full black). This is what gets selected by “scanline beam width variation”:

896/960 resolution (4x vertical scale):

1)
100
0
0
100

2)
50
0
50
100

3)
55
0
55
90

4)
60
0
60
80


1120 resolution (5x vertical scale):

1)
100
0
0
0
100

2)
100
0
0
100
100

3)
100
25
0
25
100

4)
95
30
0
30
95

5)
90
35
0
35
90

6)
85
40
0
40
85

7)
80
45
0
45
80

8)
75
50
0
50
75

9)
70
55
0
55
70

#2

bump; does anyone with shader skillz feel like taking a stab at this?

Basically, the user would see two options “scanline variation” and “scanline opacity” (labels subject to change).

At 4x vertical scale, “scanline variation” would select between scanline patterns 1-4 (see above patterns for 896/960 resolution) and at 5x vertical scale it would select between scanline patterns 1-9.

Scanline opacity would just adjust the opacity of the entire scanline pattern/overlay.

With these two options you would have fully customizable scanlines at 4x or 5x vertical scale in a single simple shader. You could add as much or as little beam width variation as desired and make the scanlines as solid or transparent as desired.

I’d like to see this happen because doing this with overlays causes a bigger performance penalty than doing this via a shader, and the current lightweight scanline options (“scanline,” “interlacing,” “zfast_crt,” etc.) lack the options for beam width variation.


#3

Just out of curiosity, could you expand on this? I use overlays for scanlines and this caught my attention. Thanks.


#4

As far as I know, it’s just faster to do this through a shader.


#5

Rather than make an equation what results in your given values I decided to use indexes and drive it with modulo’d texCoord.y * targetSize.y but it might be slower than ideal with how I made it.

Here’s a demo Quark formatted GLSL shader. https://mega.nz/#!ZkdmFC6Y!7lT05_j81V0WfR96NQz-b0DvEBC6B0fcpYMHhWVYwuk

I’m not sure it’s really all that useful, you can just modify a fract or modulo generated scanline to get approximately these values, it’s just a matter of modifying contrast and brightness. Getting exactly these, I assume, arbitrary values isn’t going to make it better than any other method as far as I reckon. It doesn’t tackle issues like screen darkening or scanline width that adjusts to brightness or anything perceptually-focused.

However, it is a unique idea as far as I know and something could be learned from it. It was a good exercise too.


#6

You obviously know a lot more about this stuff than I do! Could you maybe expand on this with an example?

I picked those values because they add up to a 50% reduction in luminance per scanline (at least, I think that’s the case). So, adjusted to 100% opacity you get an exact 50% reduction in brightness per line, which was somewhat arbitrarily chosen as an “ideal” brightness for scanlines (it seems that the better the CRT gets, the closer you get to a 1:1 ratio of scanline darkness to visible lines). By adjusting the opacity you can get anywhere from a 0-50% reduction in brightness.

Screen darkening isn’t something I wanted to tackle with this idea, and this shader would definitely require an adjustment of the LCD backlight (to 100%, if necessary).

These scanlines should adjust in width in relation to brightness; at least, that’s what I’m going for. By darkening the top/bottom edges of the scanline a certain amount, darker colored lines should appear thinner. At least, that’s the goal- to have scanlines that adjust in width in relation to brightness, and to be able to easily adjust the amount of scanline width variation.

I’m trying to avoid anything that will cause clipping or crushed blacks, which means avoiding increasing the contrast or raising the black level as a way to compensate for lost brightness from scanlines. The only way (that I know of) to accomplish this is to crank up the display backlight. There’s probably a bit of wiggle room when it comes to increasing contrast, but not much if the display is already calibrated for maximum contrast ratio.

Having said all that, I have no idea if there’s a better way to accomplish what I’m trying to do, here. Perhaps you have some ideas?

In MAME HLSL, I think you could accomplish what I’m going for with these:

scanline_variation

scanline_bright_offset

scanline_alpha

and maybe:

scanline_bright_scale (but this might result in clipping)


#7

Oh, I understand now! The brightness is meant to set the scanline overlay pattern. I must have skimmed over it this morning.

Modulo will kind of count up along a rising value like the current pixel position * vertical resolution and then output a repeating pattern of 0123012301230123 if modulo’d by 4 or 012340123401234 if modulo’d by 5. Then you take this, scale it down to fit within 0-1 by dividing it by the highest value plus 1 like “0 1 2 3” becomes “0 0.25 0.5 0.75” and this is done instead of dividing it by the highest value on its own because it’s end up “0 0.333 0.666 1” and when we use Absolute Value (to reflect this rising from zero then immediately back to zero and rising back up into a more triangular shape where it goes up and down smoothly) the 0 and 1 would both have the same value. Then with this you have a basic building block for a scanline overlay. From here you can make it brighter by inverting it, squaring it, and inverting it again, or adding a number to it and clipping it, or multiplying it and clipping it, all sorts of things.

Anyway, to control the scanline index with the brightness in a way that interpolates between them so it doesn’t just jump between values would be something along the lines of multiplying the 0-1 brightness by the number of indexes, flooring it to a whole number, subtracting that floored number from the original brightness, and using that difference to control the mix between the scanline at the floored value and the next value up.

This is real messy and more complicated than it’d need to be.

Instead I guess I could take those values, put them into the Desmos website’s graphing calculator, and try to find an equation that’ll smoothly interpolate between them when given a single number and I could switch between 3 or 4 or so different equations using the old index method so each horizontal line uses a different equation.

Edit: I looked at it and I realized the values don’t seem to make much sense.

As it gets brighter it gets darker? Is that intended?


#8

Here’s the 4px one I turned into some equations driven by max(Picture.x,max(Picture.y,Picture.z)) as Brightness:

if (Index4 == 0){ Scanline = mix(Brightness*-1.5+1,Brightness*0.15+0.45,min(Brightness*3,1.0)); }
if (Index4 == 1){ Scanline = 0; }
if (Index4 == 2){ Scanline = mix(Brightness*1.5,Brightness*0.15+0.45,min(Brightness*3,1.0)); }
if (Index4 == 3){ Scanline = mix(1.0,Brightness*-0.3+1.1,min(Brightness*3,1.0)); }

It looks fine, but not exceptional enough for me to do the 5px one as well. Could probably approximate it by lowering the contrast of the scanline pattern in relation to brightness without the 4 different equations.


#9

I apologize for doing a poor job of explaining myself. :sweat_smile:

Some things are just a lot easier to explain with pictures. Here are the scanline patterns I’m referring to in my initial post. The user would select one of these with the “scanline beam width variation” setting (setting names subject to change). The patterns range from little/no variation (for example: 100/0/0/100 would be no variation) to a lot of variation (example: 60/0/60/80 at 4x vertical scale). I think, at 5x vertical scale, #6 or #7 looks pretty good. #8 or #9 starts to look a bit strange.

Note: there are two overlays each for the 4x vertical scale overlays, since games can be either 896 or 960 pixels vertical at 4x scale. I thought about also making a set that was 1200 pixels vertical for 5x scale, but I don’t like how much of the image gets cropped on a 1080p display (which is what these are intended for).


#10

Sorry, not quite :persevere:. It’d just be one pattern that gets used at a time, but the user would set the pattern with the “scanline width variation” option.

Although, what you’re saying here is a neat idea, and something which has occured to me in the past. Have several patterns and have the brightness of the pixel determine the pattern that gets used. That might also be worth exploring at some point.


#11

Oh, then the first one should do that.


#12

I’ll check out the demo shader when I get home!

you can just modify a fract or modulo generated scanline to get approximately these values,

yep, it’s a very simple concept and should be very easy to code for those with the necessary know-how, but AFAIK there’s no current option that does just this in a single lightweight shader, so I think it could actually prove to be pretty useful.

Would “scanline.glsl” be an example using a modulo-generated scanline? It seems like the desired results could be achieved with this shader, but to the layperson/average user it’s not very clear what the settings do or how to alter them to achieve the desired results, and I’m not sure you can actually alter the amount of beam width variation without altering the code itself. Of course, I could be completely wrong about this.


#13

Looking at the code it don’t use modulo, it uses sin() but it might do what you want. Sine Comp B controls the scanline overlay’s contrast, Brightness controls how dark or bright it is overall before cranking up the contrast. Sine Comp A adds vertical lines.


#14

Hmm. I tried playing around with “scanline” and “scanlines-sine-abs,” but neither had the options to easily adjust the amount of scanline width variability.

In MAME HLSL, I think you would just use “scanline bright offset” and “scanline variation” to accomplish this. Actually, now that MAME HLSL has been converted, I think a scanline shader just using the scanline options from MAME HLSL would achieve the desired result and might be a good idea.

I checked out the demo shader you posted, but was unable to figure out how to get the scanlines to line up with the pixels correctly, probably as a result of the blur (is there a way to disable that?). It’s probably moot, though.


#15

Ah, change Index4 and Index5 to

int Index4 = int(mod(1-texCoord.y*targetSize.y,4));
int Index5 = int(mod(1-texCoord.y*targetSize.y,5));