English Amiga Board

English Amiga Board (https://eab.abime.net/index.php)
-   support.WinUAE (https://eab.abime.net/forumdisplay.php?f=5)
-   -   Adding a "non-lineair" scanline option to WinUAE (https://eab.abime.net/showthread.php?t=63009)

Dr.Venom 04 February 2012 16:45

Adding a "non-lineair" scanline option to WinUAE
 
Hi Toni,

The discussion in the 'New Filter' thread (http://eab.abime.net/showthread.php?t=62541) got me thinking about the current scanline effect implementation for LCD/LED monitors. Below is a suggestion on how to possibly improve on it.

The current implementation in the tab filter -> extra settings allows for setting "Scanline Transparancy" from 0-100 on a lineair scale. It lowers intensity of the whole scanline by the X% transparancy set. This seems adequate, but on closer inspection, real CRT scanlines show an effect that might need the emulation to go one step further.

As observed in the new filter thread, in reality on a CRT scanline "texture" is dependant on the brightness of the underlying pixels. Clear white almost doesn't show scanlines from normal viewing distance on a CRT, but e.g. more dark red or blue has clearly visible scanline texture. A nice example illustrating this is the protograph in the Commodore Horizons magazine from a CRT screen showing the famous "Tutankhamun" picture. Shown on the picture of page 31 of the march 1986 issue:

Mag = Commodore Horizons
Issue = March 1986
Page = 31

http://amr.abime.net/issue_2704_pages

In the example picture the bright gold on the forehead and right scheek is almost solid with no scanline effect, while the more dim colors, like the darker blue show clear scanline effect.

This effect seems to be a result of the phosphor glow of traditional CRT screens and basicly makes "scanlines" on a real CRT a per pixel dependant non-lineair effect. And, in view of that, might classify the current scanline implementation as a bit of a "short-cut" to the real thing (i.e. by using a lineair transparancy scaler for the whole scanline).

As such, I'm wondering if it would be possible to add a scanline option that utilizes the suggested per pixel non-lineair transparancy scaler, or something similar? Such that bright white only has about 10% transparancy (almost no visible "scanline") and such that with each step in brightness of the underlying source pixel, the transparancy is increased in a non-lineair/quadratic way, i.e. darker colors turn increasingly faster to a solid black. Just as is shown in the "Tutankhamun" example. The end-result would (IMHO) lead to more real scanline effect emulation than the current implementation.

I don't know if it's possible, but would you consider adding such an option to WinUAE? (And to be clear, this is about more accurate emulation of the built-in scanline options, not to start a generic thread about "what filter is best and what would you like").

Toni Wilen 04 February 2012 17:02

Only way to do it dynamically is to create pixel shader scanline "filter". Software version would be painfully slow.

Note that shader code can be "stacked", previous code writes to temp buffer that next one reads and so on.. (RGB mask or current scanline is already separate pass on top of selected filter)

I can write the shader code but only if someone else creates the algorithm.

Diduz 15 March 2012 19:08

Hello guys, hello Toni! I've been using WinUae for ages and it's GREAT. :great
Diduz from Italy here.
Yesterday I tried a special build of DosBox ( http://ykhwong.x-y.net/ ) which features a very good CRT emulation shader for Direct 3D. It's really good and it looks to me exactly what Dr. Venom was talking about. ;)
I know it's not strictly WinUae-related, but I think it could look good in the Amiga Emulator.

The files CRT.D3D.bright.fx and CRT.D3D.fx are located in the SHADERS subdirectory and seem to be under GPL.

Pixelfan 25 April 2012 00:33

Cheap trick
 
Hi,

I thought this sounds interesting, so I tried some things out. Actually, you can achieve a similar effect by rather cheap transformations:

Code:

red = red > 127 ? red - (255 - red) : 0;
grn = grn > 127 ? grn - (255 - grn) : 0;
blu = blu > 127 ? blu - (255 - blu) : 0;

Here is an example of how it looks on a 3x scaled cutout of the Turrican title screen:

http://eab.abime.net/picture.php?alb...pictureid=2214

Notice how there are almost no scanlines in the white areas but clearly visible black scanlines in the darker sections of the image.

Should not be too expensive if you implement it like that.

Best regards,
Pixelfan

Retro-Nerd 25 April 2012 01:20

Looks really nice, Pixelfan. :great

Pixelfan 25 April 2012 08:41

Alternatively something like this:

Code:

red = (red * red) >> 8;
grn = (grn * grn) >> 8;
blu = (blu * blu) >> 8;

That requires 16-bit integers and multiplication. However, no conditional statements needed.

Result looks similar.

Pixelfan 25 April 2012 11:12

Hi Toni,

Quote:

Originally Posted by Toni Wilen (Post 800474)
Note that shader code can be "stacked", previous code writes to temp buffer that next one reads and so on.. (RGB mask or current scanline is already separate pass on top of selected filter)

Can you quote a simple example of shader code, e.g. for 2x scaling with linear interpolation? I would like to get a better impression of how it works.

Does it iterate through the pixels of the output image? Can it access arbitrary pixels of the input image?

Best regards,
Pixelfan

Toni Wilen 25 April 2012 19:11

Check existing shader code (package available from winuae.net). I am not 100% sure how they work either :)

It can access any source pixel (but method isn't very intuitive in my opinion). Destination pixels are not available without multiple passes.

Pixelfan 25 April 2012 23:47

I did some more refinements:

http://eab.abime.net/picture.php?alb...pictureid=2216

Here is the python code that I used to scale the image:

Code:

from PIL import Image
img = Image.open("turrican_input.png")
imgsize = img.size
outsize = (3*imgsize[0]-1, 3*imgsize[1])
out = Image.new('RGB', outsize)

for y in range(0, outsize[1]):
  for x in range(0, outsize[0]):
    (red,grn,blu) = img.getpixel((x/3,y/3))
    if x % 3 == 2:
      # every 3rd target pixel is horizontally interpolated
      next = img.getpixel((x/3+1,y/3))
      red = (red >> 1) + (next[0] >> 1)
      grn = (grn >> 1) + (next[1] >> 1)
      blu = (blu >> 1) + (next[2] >> 1)
    if y % 3 != 1:
      # each source line is represented by 3 target lines
      # only the 2nd target line has the original brightness
      # brightness of 1st and 3rd target line is adjusted
      brightest = max(red,grn,blu)
      red = (red * brightest) >> 8
      grn = (grn * brightest) >> 8
      blu = (blu * brightest) >> 8
    out.putpixel((x,y), (red,grn,blu))

out.save("turrican_output.png")

Here is a magnified section of the output image to give you a better impression of what the algorithm actually does:

http://eab.abime.net/picture.php?alb...pictureid=2217

Best regards,
Pixelfan

Pixelfan 27 April 2012 12:36

I have refined my scanline filter further more such that it will keep the original brightness impression of the original image.

Here is a comparison of an 3x scaled image without any filtering and after applying my scanline filter (which also does some horizontal interpolation):

http://eab.abime.net/picture.php?alb...pictureid=2219

I think now it comes very close to what the games looked like on my CRT monitor.

viddi 27 April 2012 14:20

Great work, Mr. Pixel! :great

Pixelfan 27 April 2012 21:20

Quote:

Originally Posted by viddi (Post 815008)
Great work, Mr. Pixel! :great

Thank you.

I am trying to understand the shader programming language in order to use this with WinUAE.

Pixelfan 29 April 2012 21:43

Hi Toni,

Quote:

Originally Posted by Toni Wilen (Post 800474)
Only way to do it dynamically is to create pixel shader scanline "filter".

I played a bit around with the D3D filters and tried to create one of my own.

Unfortunately, I am unable to separate lines cleanly as needed for the scanline effect. Even the 2xSaI+Scanlines which is delivered in your filter package looks totally weird:

http://eab.abime.net/albumsthumb/2/5...?dl=1335728532

What settings are required to get the 2xSaI+Scanlines filter working correctly?

Best regards,
Pixelfan

Toni Wilen 29 April 2012 22:03

Quote:

Originally Posted by Pixelfan (Post 815410)
What settings are required to get the 2xSaI+Scanlines filter working correctly?

Not sure if this fixed it but make sure you use 2.4.1 betas (or 2.3.3), 2.4.0 uses wrong size for internal filter texture.

Pixelfan 29 April 2012 22:12

Hi Toni,

thanks for your reply. However, I am already using Public Beta Beta 9, 2012.04.22.

Should I switch back to 2.3.3?

Something else: What is the intended size of the internal filter texture? Does it depend on the "horiz. size" and "vert. size" settings in the filter tab?

Best regards,
Pixelfan

Pixelfan 30 April 2012 00:01

Hi Toni,

This is really strange. In the D3D shader, I need to multiply the normalized vertical coordinate with 577 in order to get the correct unnormalized line number.

As normalized coordinates reach from 0.0 to 1.0, this would correspond to unnormalized line numbers 0 to 577 which makes a total of 578 lines. However, I thought that the maximum vertical resolution of the OCS was 576.

Furthermore, if I set the horiz. size and vert. size to 3x in the filter tab, I would have expected that the line number in the D3D shader increases to something between 864 an 866. However, none of these multipliers result in clean scanline. Thus, the number of lines seems to be something else.

By the way: why is there no preselector for 3x size in the filter tab?

Best regards,
Pixelfan

Pixelfan 30 April 2012 01:08

All,

I implemented a very simple D3D shader version of my non-linear scanline algorithm:

Code:

#include "shader.code"

float scaling : SCALING = 2.0;

// multiplicator to transform normalized Y coordinates to denormalized line numbers
float rs_numlines = 577.0;

// this controls the brightness correction
// use 1/2 if every 2nd line is a scanline
// use 1/3 if every 3rd line is a scanline
float rs_scanfrac = 0.5;

string name : NAME = "Retroscan";
string combineTechique : COMBINETECHNIQUE =  "Retroscan";

// **VS**

VERTEX_STUFF_W S_VERTEX (float3 p : POSITION, float2 tc : TEXCOORD0)
{
  VERTEX_STUFF_W OUT = (VERTEX_STUFF_W)0;

  OUT.coord = mul(float4(p,1),WorldViewProjection);
  OUT.CT = tc;

  return OUT;
}

// **PS**

float4 S_FRAGMENT ( in VERTEX_STUFF_W VAR ) : COLOR
{
  // extract the current pixel from the source texture
  float3 pixel = tex2D(s_p, VAR.CT ).xyz;

  // pre-calculate constant value that is used in the brightness calculation
  float rs_val = (1.0 - rs_scanfrac) / (2.0 * rs_scanfrac);

  // adjust the brightness for the pixels that are not part of a scanline
  pixel = sqrt(pixel / rs_scanfrac + rs_val * rs_val) - rs_val;

  // transform normalized Y coordinates to denormalized line numbers
  int rs_line = int(VAR.CT.y * rs_numlines);

  // only execute for scanlines
  if (rs_line % 2 == 1)
  {
    // decrease brightness for the pixels that are part of a scanline
    pixel = pixel * pixel;
  }

  return float4(pixel,0);
}

technique Retroscan
{
  pass P0
  {
    VertexShader = compile vs_3_0 S_VERTEX();
    PixelShader  = compile ps_3_0 S_FRAGMENT();
  } 
}

Unfortunately, it only gives clean results with the following settings:

http://eab.abime.net/albumsthumb/2/a...?dl=1335740688

http://eab.abime.net/albumsthumb/2/8...?dl=1335740688

I hope that Toni can get it working cleanly with other resolutions und fullscreen mode as well, because it looks really good from my point of view.

Once it works with other resolutions, I can also add some horizontal interpolation which I used in the pictures from my previous posts.

Best regards,
Pixelfan

bLAZER 30 April 2012 02:01

Good work, those scanlines look verrry nice.

Pixelfan 30 April 2012 10:35

Hi Toni,

I noticed that there are some filters which do not use D3D. For example, the hq3x filter.

How are these filters implemented?

Best regards,
Pixelfan

Toni Wilen 30 April 2012 11:42

Quote:

Originally Posted by Pixelfan (Post 815471)
I noticed that there are some filters which do not use D3D. For example, the hq3x filter.

They are built-in, pure software, very slow.

Quote:

Originally Posted by Pixelfan (Post 815435)
This is really strange. In the D3D shader, I need to multiply the normalized vertical coordinate with 577 in order to get the correct unnormalized line number.

use TEXELSIZE parameter, it contains 1.0/width and 1.0/height values.

Quote:

As normalized coordinates reach from 0.0 to 1.0, this would correspond to unnormalized line numbers 0 to 577 which makes a total of 578 lines. However, I thought that the maximum vertical resolution of the OCS was 576.
Probably some rounding. It is not guaranteed to be exact.

Quote:

Furthermore, if I set the horiz. size and vert. size to 3x in the filter tab, I would have expected that the line number in the D3D shader increases to something between 864 an 866. However, none of these multipliers result in clean scanline. Thus, the number of lines seems to be something else.
Use the 1x-4x setting next to filter select menu. It sets internal texture size multiplier.

Quote:

By the way: why is there no preselector for 3x size in the filter tab?
Because it isn't really needed. This option only scales the image, original texture is still the same. See above.


All times are GMT +2. The time now is 21:31.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.

Page generated in 0.05086 seconds with 11 queries