- We start by encoding the low resolution input image as an NTSC signal. Each input line is converted into voltage over time, in the same format an NTSC signal would be sent across a wire (except for the sync and color pulse stuff).
- A 'cable reflection' shader smears the signal out a little to the right. I'm not sure how much it looks like cable reflection, but it does kind of evoke the streaking artifacts you see on some old TVs.
- The luma is split out of the signal, and then used in the NTSC decoding process. This is also where the standard OSD parameters (brightness, contrast, sharpness, etc) are applied. Now our image is RGB again.
- The image is projected onto a curved tube. This step also takes care of tracing the scan lines and applying the phosphor pattern.
- The phosphors from the previous frame are decayed, and the new values are accumulated. This allows for ghosting of moving images.
- A standard post-processing stack is applied (bloom, glare, and tone mapping). This give users a taste of the eye-burning glow produced by a real CRT. (Do you remember when staying up late to play games caused physical pain? Kids these days are soft.)
Naturally, there are a few problems. Moire AUGH, TEH MOIRE. The combination of the scanlines and the phosphor texture make a little bit of moire pretty much unavoidable. Tuning the brightness, contrast, bloom, scaling, or NTSC parameters can produce moire, or move it from one place to another. The good news is that it looks far worse in screen shots than it does on a running game. (I cranked it up for the screen shot above… it's not that ghastly under normal circumstances). Crosstalk Crosstalk between chroma and luma is an key part of the effect, so it's a feature, not a bug. The problem is getting it to look bad in a 'good' way. A band-stop FIR filter can be used to chop out the chroma signal, but it's tough to find the right balance between soft (filter too wide) and stripy (filter too narrow). Phosphor Resolution My original goal was to have RGB phosphors visible in the image when you examined it up close. That's really hard, because if you make the phosphors small enough to look realistic, the RGB pattern blurs out and all you can see is a sort of vertical striping. If you don't mipmap or supersample the phosphors, you again get more moire. These examples have the phosphor texture enlarged and strengthened to exaggerate the problem. I wasn't able to get individual phosphors to look good at 720, and they are only barely tolerable at 1080. Balance Cranking all these techniques to the max gives you a delightfully bad video signal, which is also no fun to look at for more than 10 seconds. There is also a fair bit of interplay between the parameters: adjusting the scanline gap changes the brightness, and so on. Tuning all this can be a touchy process. Below are the parameters that control the effect. As you can see, there are a lot of ways I can screw things up. Up Next In the future, I'll get into the technical details and show you what the shaders look like. If you're interested, go to pureenergygames.com and subscribe to the RSS feed! [This piece was reprinted from #AltDevBlogADay, a shared blog initiative started by @mike_acton devoted to giving game developers of all disciplines a place to motivate each other to write regularly about their personal game development passions.]