PlainOldPants's Shader Presets

Which is why I want to get my hands on original hardware again myself. Seeing Virtua Racing like that indeed throws me off, that pic alone makes me want to see how it outputs on a model 1 Gens with RF output. Composite didn’t exist to me back in the 90’s literally until the 5th generation consoles came on the scene with the composite cable packaged in the box, every system I owned before that all came packaged with the RF cable so that was my experience. I have the main 3 systems of the 5th generation (saturn, ps1 and n64) right now all with their respective original composite cables and a crt to play any one of them for testing purposes, it’s the systems before that generation that I haven’t seen in ages on a crt that I need to see again on real hardware.

I can’t load Virtua Racing on my EverDrive X3 since it needs some special chip, but here’s the 240p test suite with 320px and 256px resolutions. https://youtube.com/watch?v=tN-B6PNGwLI It is a “1 phase” pattern.

We can also see that this RF-only 1989 CRT has no comb filter, because the rainbow banding doesn’t disappear on the checkerboard pattern. CRTs with a comb filter filter out the rainbow banding from checkerboard patterns, but not from vertical bar patterns.

2 Likes

Least I know which game I’m getting first when I get a Mega Drive again. I’m more curious than ever to see Virtua Racing on a crt playing on the actual system. Guess it will still vary on the kind of crt I hook it up to as well.

1 Like

This is why I made sure to qualify my statement and have in the past questioned whether or not the logic behind determining the correct phase for the systems used by the NTSC shaders was in fact correct.

I’m sure I can dig up my old posts with those questions.

So definitely no offense taken here. We’re actually on the same page.

Hi @PlainOldPants, as for Sega Master System, I’ve tried using your Patchy-Genesis.slangp inside ntsc folder, but for some reason, it didn’t look like I remember. I had a Master System in the 90’s. Surprisingly, using Patchy-snes.slangp I managed to get something very good and it remind me exactly the sms visual of that time. I had to change some params, though, because the default interference/noise was just too much for what I remember. It’s important to tell that at the time I was used to fine tunning my RF consoles to the best settings, so noise was minimized and my father had a 20" Panasonic CRT TV at the time, and it probably was too good in picture.

So, here’s my preset for master system the way I remember. Noise is noticeable only in some dark color shades. Fringing is subtle, so that it doesn’t distract you. No idea if I’m doing something stupid about the parameters, but here it is, anyway:

shaders = "16"
feedback_pass = "0"
shader0 = "shaders_slang/ntsc/shaders/patchy-ntsc/patchy-ntsc-encode-y-c.slang"
filter_linear0 = "false"
wrap_mode0 = "clamp_to_border"
frame_count_mod0 = "1000"
mipmap_input0 = "false"
alias0 = ""
float_framebuffer0 = "true"
srgb_framebuffer0 = "false"
scale_type_x0 = "source"
scale_x0 = "4.000000"
scale_type_y0 = "source"
scale_y0 = "1.000000"
shader1 = "shaders_slang/ntsc/shaders/patchy-ntsc/patchy-ntsc-combine-y-c.slang"
filter_linear1 = "false"
wrap_mode1 = "clamp_to_border"
frame_count_mod1 = "1000"
mipmap_input1 = "false"
alias1 = ""
float_framebuffer1 = "true"
srgb_framebuffer1 = "false"
scale_type_x1 = "source"
scale_x1 = "1.000000"
scale_type_y1 = "source"
scale_y1 = "1.000000"
shader2 = "shaders_slang/ntsc/shaders/patchy-ntsc/patchy-ntsc-noise.slang"
filter_linear2 = "false"
wrap_mode2 = "clamp_to_border"
frame_count_mod2 = "1000"
mipmap_input2 = "false"
alias2 = ""
float_framebuffer2 = "true"
srgb_framebuffer2 = "false"
scale_type_x2 = "source"
scale_x2 = "1.000000"
scale_type_y2 = "source"
scale_y2 = "1.000000"
shader3 = "shaders_slang/ntsc/shaders/patchy-ntsc/patchy-ntsc-separate-y-c.slang"
filter_linear3 = "false"
wrap_mode3 = "clamp_to_border"
frame_count_mod3 = "1000"
mipmap_input3 = "false"
alias3 = ""
float_framebuffer3 = "true"
srgb_framebuffer3 = "false"
scale_type_x3 = "source"
scale_x3 = "1.000000"
scale_type_y3 = "source"
scale_y3 = "1.000000"
shader4 = "shaders_slang/ntsc/shaders/patchy-ntsc/patchy-ntsc-decode-y-rmy-bmy.slang"
filter_linear4 = "false"
wrap_mode4 = "clamp_to_border"
frame_count_mod4 = "1000"
mipmap_input4 = "false"
alias4 = ""
float_framebuffer4 = "true"
srgb_framebuffer4 = "false"
scale_type_x4 = "source"
scale_x4 = "1.000000"
scale_type_y4 = "source"
scale_y4 = "1.000000"
shader5 = "shaders_slang/ntsc/shaders/patchy-ntsc/patchy-ntsc-eotf.slang"
filter_linear5 = "false"
wrap_mode5 = "clamp_to_border"
frame_count_mod5 = "1000"
mipmap_input5 = "false"
alias5 = ""
float_framebuffer5 = "true"
srgb_framebuffer5 = "false"
scale_type_x5 = "source"
scale_x5 = "1.000000"
scale_type_y5 = "source"
scale_y5 = "1.000000"
shader6 = "shaders_slang/ntsc/shaders/patchy-ntsc/trilinearLUT-switchable.slang"
filter_linear6 = "false"
wrap_mode6 = "clamp_to_border"
frame_count_mod6 = "1000"
mipmap_input6 = "false"
alias6 = ""
float_framebuffer6 = "true"
srgb_framebuffer6 = "false"
scale_type_x6 = "source"
scale_x6 = "1.000000"
scale_type_y6 = "source"
scale_y6 = "1.000000"
shader7 = "shaders_slang/ntsc/shaders/patchy-ntsc/linear-to-srgb.slang"
filter_linear7 = "false"
wrap_mode7 = "clamp_to_border"
frame_count_mod7 = "1000"
mipmap_input7 = "false"
alias7 = ""
float_framebuffer7 = "true"
srgb_framebuffer7 = "false"
scale_type_x7 = "source"
scale_x7 = "1.000000"
scale_type_y7 = "source"
scale_y7 = "1.000000"
shader8 = "shaders_slang/crt/shaders/crt-royale/src-fast/crt-royale-first-pass-linearize-crt-gamma-bob-fields.slang"
filter_linear8 = "false"
wrap_mode8 = "clamp_to_border"
mipmap_input8 = "false"
alias8 = "ORIG_LINEARIZED"
float_framebuffer8 = "false"
srgb_framebuffer8 = "true"
scale_type_x8 = "source"
scale_x8 = "1.000000"
scale_type_y8 = "source"
scale_y8 = "1.000000"
shader9 = "shaders_slang/crt/shaders/crt-royale/src-fast/crt-royale-scanlines-vertical-interlacing.slang"
filter_linear9 = "true"
wrap_mode9 = "clamp_to_border"
mipmap_input9 = "false"
alias9 = "VERTICAL_SCANLINES"
float_framebuffer9 = "false"
srgb_framebuffer9 = "true"
scale_type_x9 = "source"
scale_x9 = "1.000000"
scale_type_y9 = "viewport"
scale_y9 = "1.000000"
shader10 = "shaders_slang/crt/shaders/crt-royale/src-fast/crt-royale-mask-resize-vertical.slang"
filter_linear10 = "true"
wrap_mode10 = "clamp_to_border"
mipmap_input10 = "false"
alias10 = ""
float_framebuffer10 = "false"
srgb_framebuffer10 = "false"
scale_type_x10 = "absolute"
scale_x10 = "64"
scale_type_y10 = "viewport"
scale_y10 = "0.062500"
shader11 = "shaders_slang/crt/shaders/crt-royale/src-fast/crt-royale-mask-resize-horizontal.slang"
filter_linear11 = "false"
wrap_mode11 = "clamp_to_border"
mipmap_input11 = "false"
alias11 = "MASK_RESIZE"
float_framebuffer11 = "false"
srgb_framebuffer11 = "false"
scale_type_x11 = "viewport"
scale_x11 = "0.062500"
scale_type_y11 = "source"
scale_y11 = "1.000000"
shader12 = "shaders_slang/crt/shaders/crt-royale/src-fast/crt-royale-scanlines-horizontal-apply-mask.slang"
filter_linear12 = "true"
wrap_mode12 = "clamp_to_border"
mipmap_input12 = "false"
alias12 = "MASKED_SCANLINES"
float_framebuffer12 = "false"
srgb_framebuffer12 = "true"
scale_type_x12 = "viewport"
scale_x12 = "1.000000"
scale_type_y12 = "viewport"
scale_y12 = "1.000000"
shader13 = "shaders_slang/crt/shaders/crt-royale/src-fast/crt-royale-brightpass.slang"
filter_linear13 = "true"
wrap_mode13 = "clamp_to_border"
mipmap_input13 = "false"
alias13 = "BRIGHTPASS"
float_framebuffer13 = "false"
srgb_framebuffer13 = "true"
scale_type_x13 = "viewport"
scale_x13 = "1.000000"
scale_type_y13 = "viewport"
scale_y13 = "1.000000"
shader14 = "shaders_slang/crt/shaders/crt-royale/src-fast/crt-royale-bloom-vertical.slang"
filter_linear14 = "true"
wrap_mode14 = "clamp_to_border"
mipmap_input14 = "false"
alias14 = ""
float_framebuffer14 = "false"
srgb_framebuffer14 = "true"
scale_type_x14 = "source"
scale_x14 = "1.000000"
scale_type_y14 = "source"
scale_y14 = "1.000000"
shader15 = "shaders_slang/crt/shaders/crt-royale/src-fast/crt-royale-bloom-horizontal-reconstitute.slang"
filter_linear15 = "true"
wrap_mode15 = "clamp_to_edge"
mipmap_input15 = "false"
alias15 = ""
float_framebuffer15 = "false"
srgb_framebuffer15 = "true"
scale_type_x15 = "source"
scale_x15 = "1.000000"
scale_type_y15 = "source"
scale_y15 = "1.000000"

pn_signal_res = "4.000000"
pn_width_uncropped = "256.000000"
pn_height_uncropped = "240.000000"
pn_rgb_blur_enable = "1.000000"
pn_scanline_dur = "47.700000"
pn_color_init_offset = "0.000000"
pn_color_line_offset = "0.333333"
pn_color_screen_offset = "0.333333"
pn_color_screen_offset_modulo = "2.000000"
pn_modulator_luma_filter_type = "-1.000000"
pn_modulator_chroma_filter_type = "0.000000"
pn_demodulator_std = "0.000000"
pn_gamma_type = "0.000000"
pn_connection_type = "-1.000000"
pn_noise_severity = "0.400000"
pn_noise_counter = "200.000000"

beam_min_sigma = "0.150000"
beam_max_sigma = "0.270000"
mask_type = "1.000000"


textures = "PhosphorSamplerLUT1;PhosphorSamplerLUT2;PhosphorSamplerLUT3;PhosphorSamplerLUT4;PhosphorSamplerLUT5;PhosphorSamplerLUT6;mask_grille_texture_small;mask_slot_texture_small;mask_shadow_texture_small"
PhosphorSamplerLUT1 = "shaders_slang/ntsc/shaders/patchy-ntsc/P22_80s_D65.png"
PhosphorSamplerLUT1_wrap_mode = "clamp_to_border"
PhosphorSamplerLUT1_mipmap = "false"
PhosphorSamplerLUT2 = "shaders_slang/ntsc/shaders/patchy-ntsc/P22_90s_D65.png"
PhosphorSamplerLUT2_wrap_mode = "clamp_to_border"
PhosphorSamplerLUT2_mipmap = "false"
PhosphorSamplerLUT3 = "shaders_slang/ntsc/shaders/patchy-ntsc/P22_J_D65.png"
PhosphorSamplerLUT3_wrap_mode = "clamp_to_border"
PhosphorSamplerLUT3_mipmap = "false"
PhosphorSamplerLUT4 = "shaders_slang/ntsc/shaders/patchy-ntsc/TrinitronP22_D65.png"
PhosphorSamplerLUT4_wrap_mode = "clamp_to_border"
PhosphorSamplerLUT4_mipmap = "false"
PhosphorSamplerLUT5 = "shaders_slang/ntsc/shaders/patchy-ntsc/P22_J_D93.png"
PhosphorSamplerLUT5_wrap_mode = "clamp_to_border"
PhosphorSamplerLUT5_mipmap = "false"
PhosphorSamplerLUT6 = "shaders_slang/ntsc/shaders/patchy-ntsc/TrinitronP22_D93.png"
PhosphorSamplerLUT6_wrap_mode = "clamp_to_border"
PhosphorSamplerLUT6_mipmap = "false"
mask_grille_texture_small = "shaders_slang/crt/shaders/crt-royale/TileableLinearApertureGrille15Wide8And5d5SpacingResizeTo64BGR.png"
mask_grille_texture_small_wrap_mode = "clamp_to_border"
mask_grille_texture_small_mipmap = "false"
mask_slot_texture_small = "shaders_slang/crt/shaders/crt-royale/TileableLinearSlotMaskTall15Wide9And4d5Horizontal9d14VerticalSpacingResizeTo64BGRshifted.png"
mask_slot_texture_small_wrap_mode = "clamp_to_border"
mask_slot_texture_small_mipmap = "false"
mask_shadow_texture_small = "shaders_slang/crt/shaders/crt-royale/TileableLinearShadowMaskEDPResizeTo64.png"
mask_shadow_texture_small_wrap_mode = "clamp_to_border"
mask_shadow_texture_small_mipmap = "false"

Screens: https://ibb.co/album/V3mb4p

3 Likes

There is no good NTSC Master System footage online at all. All the Master System gameplay videos on YouTube either are over RGB, over a Genesis’s composite, over an unspecified console’s (probably a Genesis’s) composite, or just recorded by a camera in shitty quality. I just need someone to upload a video capture of the SMS, preferrably an earlier one without the CXA1145. Prove to me that the NTSC SMS isn’t some 4chan hoax.

I can’t find a schematic for the NTSC Master System either, but there is a schematic for the PAL master system floating around. It has the same Sony CXA1145 setup as the early Genesis consoles, with the same inductor/capacitor filters on the signal, but I’ve read elsewhere that earlier NTSC Master Systems have a superior circuit using an older Sony chip.

That doesn’t necessarily mean that late NTSC Master System consoles had the same composite as the Genesis. Considering the Master System has a width of 256 pixels, there’s a good possibility it has the same phase pattern as the SNES, just with reduced artifacts and increased blur.

What that does mean @Hyllian is that you probably want to turn off the bilinear RGB blur (that’s really just a SNES thing), and change the modulator luma filter type to -2 (if that’s even in my latest upload), unless this looks too different from what you remember. For colors that look more like Grade, you can change my shader’s white point to 9300K, enable chromatic adaptation, and set the phosphors to either P22-J or Trinitron P22.

There are also 2 more tiny fixes I need to make in my code, particularly the Master System’s “blue lift” and the exact right SNES color carrier frequency–My 3-phase pattern currently is just slightly wrong. Once I do these 2 fixes, I’ll upload my latest version. This update is also going to calibrate the optional US red pushes better than before, and it’s going to add Grade’s 8500K white point.

1 Like

The No Swear Gamer records from hardware, you could ask him about specifics via Youtube.

Here’s another composite capture, from Japanese hardware: https://www.youtube.com/watch?v=9MHZDmmnkao

And here is another composite capture.The description says it’s “the original Master System”, there are also links where the same game (Shinobi) is demonstrated using the composite outputs of the Analogue NT Mini and the Genesis 1. https://www.youtube.com/watch?v=qLWZoEgjNnU

3 Likes

Thank you a lot. I saw a couple from The No Swear Gamer and didn’t know whether it was an original SMS or a Genesis, but those other 2 are probably original SMS consoles. They look like they’re the same as the Genesis’ video signal, except, comparing these two videos https://www.youtube.com/watch?v=creDKP43oCI https://www.youtube.com/watch?v=qLWZoEgjNnU the SMS and Genesis have different colors.

@Hyllian I’m questioning your memory a little bit. All of these videos have the Genesis “1-phase” pattern.

I did a quick search and found a PC-Engine video: https://www.youtube.com/watch?v=-sCRJ8ZhoUk It is a “2-phase” pattern.

For PS1, I’m not even going to look up videos. I’m just going to capture my real hardware.

I won’t start working on this stuff just yet. I have other things I need to dedicate more time to at the moment. All I’ll do for now is that tiny 3-phase fix and Grade’s SMS non-linear blue lift. After those things, one more thing in addition to trying to match these consoles is copying cgwg-famicom-geom’s adaptive comb filter.

(Edit: I’m already forgetting the color gamut conversions that I discussed with Chthon last month. The plan is to bake the entire color grading process into an LUT, including the demodulator settings, the gamma, and the phosphor gamut. It’ll be a big jump in quality, but… at that point, someone may as well get a CRT-compatible (!) colorimeter and just sample an entire LUT that way.)

2 Likes

Dunno if useful, but have you seen the composite filter/output comparisons over at the CRTdatabase with the Genesis related tables? For some reason, the original article where the Retrotink’s Notch filter is featured doesn’t seem to be there anymore, (here archived) but there are now explicit comb filter search values there, the filter pictures/tables are still available for Panasonic-ct-20sl15 and Panasonic-ct-20sl14j Edit: They info has now also been taken out from the Panasonic CRT articles.

1 Like

I can’t say my memory is correct. In fact, I doubt I can recover all these details from 30 years ago. :stuck_out_tongue: You have a point.

BTW, dunno if it’s helpful, some schematics you can find here. There are some for sega systems and others for nes and atari clones made in Brazil.

1 Like

I’ve been procrastinating on this for too long. Tonight, I’m going to sit down and make the very small fixes that I promised about a week ago.

In case anyone is wondering why development on this shader project has slowed down:

(Spoiler)

The correct answer is 2.

1 Like

You sure the answer is not 42?

Hey there, hello boss. Sorry, haven’t made the time to check last version and Noise changes.

I found this new VHS record: Do you know if this VHS 1993 looking in Sonic 2 is actually achievable with current preset version? @sonkun @guest.r

As its stated in description, this is recorded from 1993 with Model 1 Genesis, RF cable, Rainbows and intense blurry looking. This is the perfect way to portray games from that decade. Would love to see it in action around here.

Audio is Mono and output rate seem like 16000 hz to me, in retroarch options.

Jump to 11:18 for rainbows and dithering

1 Like

Seems doable by turning up the saturation and blurring the image up:

1 Like

Nice!

And this bug with Super sonic next to the signpost. I remember even this happening in a kids TV show where kids played through the phone buttons number. It really could break all game experience if this ever happened!

12:32

1 Like

Do remember that VHS can also have wow & flutter, tracking, dirty head and dropout artifacts due to physical tape or magnetic degradation.

You might need to add the VHS shader to simulate some of those “effects”.

2 Likes

Edit: I just realized that this update might have accidentally altered the Genesis artifacts, but I’m not sure. I might do another update soon to fix this, but I don’t have time at this exact moment.

This update has limited compatibility with presets made for the previous version. The shader passes are changed, so you will have to re-append all your presets. The only settings you need to update are “Tint”, “Color”, and “R-Y/B-Y lowpass type”.

This is a minor update doing several small fixes and improvments. The main things are slightly more accurate 3-phase, better red push default settings, the 8500K whitepoint, the SMS blue lift from Grade, and better performance. I recommend appending (in order) afterglow-update0 and crt-royale-fast. Consider prepending allowed-settings, to bring commonly used settings to the top of the list. https://www.mediafire.com/file/wgg42omjr7da398/patchy-8500k-2024-10-16.zip/file

I am going to put together a document going over this shader’s very long list of settings. Even though there are so many settings, only a few are really used. I’ve been short on time to work on this project lately, but I think this in particular can get done soon enough.

For those planning to make presets with this, I have a few suggestions. First, the settings to look similar-ish to Grade (but slightly more accurate) are Trinitron P22, 8500K, enable chromatic adaptation, r-y/g-y/b-y preset 0, and brightness 0.1. Second, if you use Grade’s BT.1886, you have to disable Auto Contrast and use the “color ramps” test pattern to set your contrast manually. Third, this update changed the default “R-Y/B-Y Lowpass Type” from 2 to 1 to reduce shadows and smearing, but you might consider changing it back to 2 for a more RF-like look. Fourth, for SMS, I recommend picking either one of the two patchy-genesis options, disabling “Genesis Jailbars on Solid Backgrounds”, and changing “Genesis Plus GX color fix” to SMS (2). A couple generic 2phase presets were added for consoles like PC-Engine and PlaySattion 1.

Detailed changelog and future goals

Full list of changes:

  • Added a generic “2-phase” preset based on Maister NTSC / NTSC Adaptive. It is not based on any particular console, but it’s currently recommended for PlayStation 1. The “hi-res” version is meant for consoles with a horizontal resolution of about 420 or higher.
  • Updated default Saturation (Color) and Hue Rotation (Tint) settings for US jungle chips. They look better now, but many people might think they’re all oversaturated.
  • Sped up the noise generation, but it’s still a laggy piece of shit.
  • Added more white point options, including 8500K for those who are used to Dogway’s Grading Shader.
  • Can do chromatic adaptation with Trinitron P22 with white point 8500K. Make sure you use the specific 8500K option, not a custom CCT. Still, I prefer having chromatic adaptation off, because chromatic adaptation changes the appearance so much.
  • Fixed the leaky integrator R-Y B-Y lowpass leaving behind a jailbar pattern in the signal.
  • The leaky integrator on R-Y/B-Y is no longer the default. If you want the distinct chroma smear to the right, change the R-Y/B-Y lowpass filter type to 2, which is the leaky integrator.
  • Changed default R-Y B-Y lowpass to a windowed sinc, and updated its default settings.
  • Widened the decoder preset lowpasses to filter out the chroma signal more completely. Before, it was only just wide enough to make the chroma signal unnoticeable on many CRT shaders. Now, it’s much harder to notice even when using the signal shader alone.
  • Halved the signal resolution for Genesis presets, giving better performance. The updates to the R-Y/B-Y lowpass were done because of this, because the Genesis would look wrong if you lowpassed in the old way.
  • Added internal 3-phase and 2-phase settings taken from Maister NTSC / NTSC Adaptive. This fixes the SNES being slightly off. (I remember hearing somewhere that N64 has a similar 3-phase signal, but I don’t trust this.)
  • Copied Grade’s Sega Master System blue lift. I haven’t properly put together an SMS preset, but for now, I recommend loading either the genesis-plus-gx or genesis-blastem preset (both work for this), turning off “Genesis Jailbars on Solid Backgrounds”, and changing the “Genesis Plus GX Color Fix” to 2 (SMS).
  • Updated patchy-color a little bit to have the SMS blue lift and the updated saturation and tint settings. Patchy-color is a side thing that I’ve been paying little attention to, and that’s made very obvious by its messy code and missing features.
  • Included bandstop and “anti-highpass” filters that both suck because they attenuate high frequencies so much. “Anti-highpass” especially is bad because it can cause some frequencies to get negated.

Goals for my next update are:

  • Clean up the freaking code. Especially patchy-color. Compatibility with older presets might have to be broken severely.
  • Better handling of varying horizontal resolutions.
  • More accurate Genesis jailbars, by screenshotting a video capture, averaging all the lines, and using as a lookup table.
  • More accurate match of Genesis color carrier settings. Currently, it’s just a little bit off.
  • Make presets for PS1, SMS, and PC-Engine.
  • Add an adaptive comb filter, probably heavily based on cgwg-famicom-geom’s.
  • Add experimental PAL support.
  • Add experimental support for LUTs that include the entire demodulate+eotf+phosphor+oetf process baked together, thanks to Chthon’s program called gamutthingy. Some fixes will have to be made to this later.
  • Add R-Y/B-Y clamping levels, preferrably from same chips.
  • Search up a bunch of demodulator chips on CRT-database and elsewhere, and pool together the results.

Other future goals:

  • If not already done, update gamutthingy to allow RGB resultant values over 255, and automatically darken the entire LUT by a constant factor to make the whole gamut fit from 0 to 255.
  • Bake the entire color grading process into an LUT, resulting in better performance and better colors. Improving my video signal is a higher priority for now.
  • At that point, may as well get a CRT-compatible (!) colorimeter and make an LUT based on a real CRT, and/or try doing it by eye.
  • More accurate EOTF, and other color accuracy improvements.
  • Get more CRTs.
  • Add support for hardcoded filters, like from Maister NTSC.
  • See if it’s possible to create filters based directly on the inductor/capacitor circuits in the original Genesis. Up to this point, everything’s been done by eye.
  • Better adaptive comb filtering.
  • More accurate noise.

I just saw these posts about VHS. From some brief searching online, VHS compresses the video an awful lot. The tape itself contains a different kind of composite video signal which uses a much lower chroma subcarrier frequency, and a VCR has to convert standard composite video both to and from this VHS composite signal. This would mean, to update this shader to support VHS, I would make it modulate and demodulate the signal three times, using at least 4 additional shader passes.

3 Likes

I’ve spent these past 2 months focusing only on my university coursework. Even over the fall break, I was just spending most of the day working on course projects or studying. I just feel so relieved now, now that my most stressful, overwhelming university semester ever is finally over. No more of that servers-within-servers-within-servers nonsense.

Just this past week, I was able to get a cheap used colorimeter on eBay. My latest update here is a hasty attempt to use this colorimeter to approximate my 1989 RCA ColorTrak’s colors in a shader, with all of the imperfections that a consumer CRT has. The NES colors turned out nice, but the Genesis didn’t turn out quite right. This colorimeter likely has drifted over time.

This update has many other random changes too, which I made during what little free time I had.

This is also my last planned update to patchy-ntsc. I’m planning to ditch patchy-ntsc entirely and make another shader from scratch, which I hope will have much more bearable performance, cleaner code, better accuracy, and better familiarity and ease-of-use for other LibRetro shader users. This shader still can do much, much better with accuracy, since it currently is just doing rough guesses at the signal’s filtering/effects using windowed sinc functions, while it could benefit well from hardcoded LUTs or arrays instead, as seen in Maister NTSC and NTSC Adaptive. Plus, there are several improvements that just can’t be added into patchy-ntsc, such as Chthon’s full gamutthingy LUTs. By this update, patchy-ntsc has just gotten too patchy, with such high performance requirements and such messy, unmaintainable, unoptimized code.

In this release, I’ve decided not to include any CRT presets. Anytime I would append a “sanitized” CRT preset, the result would change too much. I recommend appending an interpolation shader, such as bicubic or b-spline.

Download at https://www.mediafire.com/file/idunzdx47lur8xb/colortrak_2024_12_16.zip/file and place all these folders directly inside your “shaders” folder, which contains another folder called “shaders_slang”.

I’ve also sampled an NES palette from this 1989 RCA ColorTrak, albeit with noise throwing off the results slightly. In comparison to the palette that I eyeballed from my 1995 Toshiba CE20D10 (which I no longer have), this is drastically different. Were all late-80s/early-90s CRTs like this? Since I couldn’t sample the D-column of the palette in the 240p test suite, I reused the grays from the 00 column, whereas in the shader preset pack above, I used simple bilinear interpolation to approximate guess the gray axis and de-emphasized colors. https://www.mediafire.com/file/98t1kvwl2x30s2c/colorimeter_palette.pal/file Note: This palette already is based on the final output colors. If you use it with a CRT shader, make sure you set both input gamma and output gamma to 2.2, and make sure any gamut-affecting settings just pass the color through. For instance, in crt-hyllian, set LUT to off.

Edit (2024-12-20): I have now done this same procedure on my 2000 Panasonic CT-36D30B. I will post the palettes and data in a bit. It allows you to set the white point to “warm”, “normal”, or “cool”, but funny enough, “warm” is actually the standard white (D65), whereas “normal” is 9300K, and “cool” is ~14000-15000K. All 3 had the same demodulation settings. Seeing as my 1989 RCA was about 9300K too, I think this is a pattern.

My methodology for reversing this CRT’s NTSC gamut correction

Spoiler (click to show/hide)

To try to replicate the colors for consoles other than NES, I measured three things. I am making several assumptions about how this CRT works which might throw off the result.

First, I sampled my CRT’s phosphors. I used the bottom row of the NES palette with high saturation and low brightness to isolate each individual phosphor. The results averaged to the following:

Red: x: 0.598576833333333, y: 0.35618925 Green: x: 0.303930178571429, y: 0.593650071428571 Blue: x: 0.153156090909091, y: 0.0663752121212122

(Edit: I’ve since used this same colorimeter to measure the phosphors and white points on my other CRT (which let me pick “warm”, “normal”, and “cool”), and the results were close to standard. The colorimeter is probably right. Regardless, I’m going to re-measure this 1989 CRT, just to be safe.)

Notice how this gamut mostly fits nicely into sRGB, with little need for gamut compression. This is great for my shader project, but I’m still doubting this colorimeter’s accuracy.

With this information, I’m able to represent any color from the CRT as a linear combination of these 3 phosphors, in linear space.

Second, I sampled a grayscale. I connected a cheap HDMI-to-composite converter to my laptop, and used HCFR to be able to easily sample the full grayscale from 0 to 255, but with only one sample per gray level, to save time.

Both the HCFR software and the HDMI-to-composite converter may have been altering the colors. I found that the input colors from 0-15 and 236-255 were getting clamped, which meant that something was interpreting my RGB as being in limited space from 16 to 235. With further trial-and-error, I found out that the grayscale approximated a gamma of about 2.1, which is about 2.4*2.2/2.5, meaning that something was correcting from sRGB gamma to NTSC gamma, while my CRT was outputting directly with approximately 2.4 gamma with no further corrections. The grayscale from the CRT did not have a steady white point (as expected from a consumer unit), so in Excel, I converted each xyY point into XYZ, and then into a linear combination of the 3 phosphors.

Once I had the full grayscale, I was able to take any color from the CRT, represent it as the 3 phosphors in linear-light space, and invert the CRT’s EOTF (a.k.a. gamma) to get the internal RGB values.

Graph of the grayscale: https://www.desmos.com/calculator/uoiwfketdn (Edit: This isn’t the right graph. If you want to see the grayscale, represented as linear Y luminance values for each phosphor, you can find it in my shader code, in patchy-ntsc-eotf.slang.)

Third, I sampled a full chroma cycle (500 colors) in YIQ space, keeping Y and sqrt(I^2 + Q^2) constant. I did this before realizing that the 16-235 clamp and the 2.2/2.5 gamma correction were happening, but when I graphed the data without correcting for those things, the result still formed very clean sine waves. The graph showed very clearly that this CRT is doing an ordinary R-Y/B-Y demodulation to correct the colors, as I saw in a number of chips’ documentation. I found that R-Y, G-Y, and B-Y were at these offsets and gains:

R-Y: offset 54.5168223778 degrees, gain 47.170890387 G-Y: offset 214.599290038 degrees, gain 15.5833234335 B-Y: offset 317.451910996 degrees, gain 52.5768429019 (I = 0 degrees, Q = 90 degrees, chroma radius: 0.1 (0 to 1) or 25.5 (0 to 255)) Gains are in RGB space. I had forgotten to take into account the 16-235 clamp and the 2.2/2.5 gamma correction, so the numbers are a bit off. Simply multiplying the gains by (235.0 - 16.0) / 255.0 makes the result more accurate.

Graph of R, G, and B in the full chroma cycle: https://www.desmos.com/calculator/kkazpj4z1a

The result had R-Y about 97 degrees off from B-Y, at about 0.9 relative amplitude, while G-Y was about 237 degrees off from B-Y at about 0.3 relative amplitude. This is similar to Sony’s JP axes in the CXA2025AS and CXA1644AS. This makes sense with the CRT’s white (mostly in the brighter half of the grayscale) being steadily near (x=0.28, y=0.295), which is close to 9300K, the reference white used in the Japanese NTSC standard at the time.

6 Likes

I really like the idea and am interested in a fast version. It does some unique things with the signal.

1 Like

Yay, Pants is back. Thank goodness.

1 Like