04 February 2012, 16:45 | #1 |
Registered User
Join Date: Jul 2008
Location: Netherlands
Posts: 485
|
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"). |
04 February 2012, 17:02 | #2 |
WinUAE developer
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,505
|
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. |
15 March 2012, 19:08 | #3 |
Posts: n/a
|
Hello guys, hello Toni! I've been using WinUae for ages and it's 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. |
25 April 2012, 00:33 | #4 |
Registered User
Join Date: Apr 2012
Location: Germany
Posts: 12
|
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; 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 Last edited by Pixelfan; 25 April 2012 at 08:41. |
25 April 2012, 01:20 | #5 |
Missile Command Champion
Join Date: Aug 2005
Location: Germany
Age: 52
Posts: 12,438
|
Looks really nice, Pixelfan.
|
25 April 2012, 08:41 | #6 |
Registered User
Join Date: Apr 2012
Location: Germany
Posts: 12
|
Alternatively something like this:
Code:
red = (red * red) >> 8; grn = (grn * grn) >> 8; blu = (blu * blu) >> 8; Result looks similar. Last edited by Pixelfan; 25 April 2012 at 08:47. |
25 April 2012, 11:12 | #7 | |
Registered User
Join Date: Apr 2012
Location: Germany
Posts: 12
|
Hi Toni,
Quote:
Does it iterate through the pixels of the output image? Can it access arbitrary pixels of the input image? Best regards, Pixelfan |
|
25 April 2012, 19:11 | #8 |
WinUAE developer
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,505
|
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. |
25 April 2012, 23:47 | #9 |
Registered User
Join Date: Apr 2012
Location: Germany
Posts: 12
|
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") Best regards, Pixelfan Last edited by Pixelfan; 26 April 2012 at 10:30. |
27 April 2012, 12:36 | #10 |
Registered User
Join Date: Apr 2012
Location: Germany
Posts: 12
|
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): I think now it comes very close to what the games looked like on my CRT monitor. |
27 April 2012, 14:20 | #11 |
Moderator
Join Date: Apr 2006
Location: Germany
Age: 44
Posts: 4,007
|
Great work, Mr. Pixel!
|
27 April 2012, 21:20 | #12 |
Registered User
Join Date: Apr 2012
Location: Germany
Posts: 12
|
|
29 April 2012, 21:43 | #13 | |
Registered User
Join Date: Apr 2012
Location: Germany
Posts: 12
|
Hi Toni,
Quote:
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: What settings are required to get the 2xSaI+Scanlines filter working correctly? Best regards, Pixelfan |
|
29 April 2012, 22:03 | #14 |
WinUAE developer
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,505
|
|
29 April 2012, 22:12 | #15 |
Registered User
Join Date: Apr 2012
Location: Germany
Posts: 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 Last edited by Pixelfan; 29 April 2012 at 22:18. |
30 April 2012, 00:01 | #16 |
Registered User
Join Date: Apr 2012
Location: Germany
Posts: 12
|
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 |
30 April 2012, 01:08 | #17 |
Registered User
Join Date: Apr 2012
Location: Germany
Posts: 12
|
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(); } } 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 Last edited by Pixelfan; 30 April 2012 at 10:50. |
30 April 2012, 02:01 | #18 |
Awesome to the max
Join Date: Mar 2007
Location: Gothenburg / Sweden
Age: 47
Posts: 1,006
|
Good work, those scanlines look verrry nice.
|
30 April 2012, 10:35 | #19 |
Registered User
Join Date: Apr 2012
Location: Germany
Posts: 12
|
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 |
30 April 2012, 11:42 | #20 | |||||
WinUAE developer
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,505
|
Quote:
Quote:
Quote:
Quote:
Quote:
|
|||||
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
"Reminder "Lincs Amiga User Group aka "LAG" Meet Sat 5th of January 2013" | rockape | News | 4 | 30 January 2013 00:06 |
Shadow of the third moon - crashes on "Disk" option | PopoCop | support.Games | 7 | 26 December 2012 18:11 |
The "Match a500 speed" Option only works if CPU is set to Mc68000. | Sp_ | support.WinUAE | 9 | 15 December 2008 17:36 |
|
|