crt-rgb-to-crt
This shader combines the current frame, the previous frame, screen mask, and diffusion into the final render.
It is a relatively complex shader, and certainly if there are features that aren't needed for a given use case, the shader could be simplified.
Index
Input Textures/Samplers
Uniform Buffer Values
Input Textures/Samplers
- g_currentFrameTexture
-
g_currentFrameTextureType
texture(platform-specific)Description
This is the RGB current frame texture, i.e. the image that will be displayed on the virtual CRT screen. - g_currentFrameSampler
-
g_currentFrameSamplerType
sampler(platform-specific, does not exist on some platforms)Description
The sampler to use to sample g_currentFrameTexture. - g_previousFrameTexture
-
g_previousFrameTextureType
texture(platform-specific)Description
This is the previous frame's texture (i.e. last frame's g_currentFrameTexture). - g_previousFrameSampler
-
g_previousFrameSamplerType
sampler(platform-specific, does not exist on some platforms)Description
The sampler to use to sample g_previousFrameTexture. - g_screenMaskTexture
-
g_screenMaskTextureType
texture(platform-specific)Description
This texture is the output of the generate-screen-texture shader, containing the (scaled, tiled, and antialiased) mask texture in the rgb channels and the edge-of-screen mask value in the alpha channel. It is expected to have been generated at our output resolution (i.e. it's 1:1 pixels with our output render target), using the same values of g_viewScale,g_overscanScale,g_overscanOffset, andg_distortionas this shader is given. - g_screenMaskSampler
-
g_screenMaskSamplerType
sampler(platform-specific, does not exist on some platforms)Description
The sampler to use to sample g_screenMaskTexture. - g_diffusionTexture
-
g_diffusionTextureType
texture(platform-specific)Description
This texture contains a tonemapped/blurred version of the input texture, to emulate the diffusion of the light from the phosphors through the glass on the front of a CRT screen. - g_diffusionSampler
-
g_diffusionSamplerType
sampler(platform-specific, does not exist on some platforms)Description
The sampler to use to sample g_diffusionTexture.
Uniform Buffer Values
- g_viewScale
-
float2 g_viewScaleType
float2Description
NOTE: this value is expected to match the equivalent value in generate-screen-texture.
This value describes how to scale the screen to account for different aspect ratios between the output dimensions and the emulated visible CRT dimensions (i.e. excluding any overscan-clipped content).
This shader is intended to render a screen of the correct shape regardless of the output render target shape, effectively letterboxing or pillarboxing as needed (i.e. rendering a 4:3 screen to a 16:9 render target).
In the event the output render target is wider than the intended screen, the screen needs to be scaled down horizontally to pillarbox, usually like:
x = (renderTargetWidth / renderTargetHeight) * (crtScreenHeight / crtScreenWidth) y = 1.0if the output render target is taller than the intended screen, it will end up letterboxed using something like:
x = 1.0 y = (renderTargetHeight / renderTargetWidth) * (crtScreenWidth / crtScreenHeight) - g_overscanScale
-
float2 g_overscanScaleType
float2Description
NOTE: this value is expected to match the equivalent value in generate-screen-texture.
If overscan emulation is intended (where the edges of the screen cover up some of the picture), then this is the amount of signal texture scaling needed to account for that.
Given an overscan value named
overscanAmountthat is (where the given values are in texels):overscanAmount.x = overscanLeft + overscanRight overscanAmount.y = overscanTop + overscanBottomthe value of
g_overscanScaleshould end up being:(inputImageSize.xy - overscanAmount.xy) * 0.5 / inputImageSize.xy - g_overscanOffset
-
float2 g_overscanOffsetType
float2Description
NOTE: this value is expected to match the equivalent value in generate-screen-texture.
the texture coordinate offset to adjust for overscan. Because the screen coordinates are
[-1..1]instead of[0..1], this is the offset needed to recenter the value.Given an overscan value named
overscanAmountthat is (where the given values are in texels):overscanDifference.x = overscanLeft - overscanRight overscanDifference.y = overscanTop - overscanBottomthe value of
g_overscanScaleshould end up being:overscanDifference.xy * 0.5 / inputImageSize.xy - g_distortion
-
float2 g_distortionType
float2Description
NOTE: this value is expected to match the equivalent value in generate-screen-texture.
The amount along each axis to apply the virtual-curved screen distortion. Usually a value in
[0..1], where0indicates no curvature (a flat screen) and1indicates "quite curved" - g_backgroundColor
-
float4 g_backgroundColorType
float4Description
The RGBA color of the area around the screen. - g_phosphorPersistence
-
float g_phosphorPersistenceType
floatDescription
How much of the previous frame's brightness to keep.
0means "we don't use the previous frame at all" and1means "the previous frame is at full brightness".In many CRTs, the phosphor persistence is short enough that it would be effectively 0 at 50-60fps (As a CRT's phospors could potentially be completely faded out by then). However, for some cases (for instance, interlaced video or for actual NES/SNES/probably other console output) it is generally preferable to turn on a little bit of persistance to lessen temporal flickering on an LCD screen as it can tend to look bad depending on the panel.
[Author's Note: seriously, check out https://www.youtube.com/watch?v=kA8CIY0DeS8 which is what my LCD panel was doing *after* the flickering interlace test truck I was using had been gone for 10 minutes]
- g_scanlineCount
-
float g_scanlineCountType
floatDescription
How many scanlines there are in this field of the input (where a field is either the even or odd scanlines of an interlaced frame, or the entirety of a progressive-scan frame). In other words, the height of the input texture, in texels. - g_scanlineStrength
-
float g_scanlineStrengthType
floatDescription
The strength of the separation between scanlines. 0means "no scanline separation at all" and1means "separate the scanlines as much as possible" - on high-enough resolution output render target (at 4k for sure)1means "fully black between scanlines", but to reduce aliasing that amount of separation will diminish at lower output resolutions. - g_curEvenOddTexelOffset
-
float g_curEvenOddTexelOffsetType
floatDescription
This is the scanline-space coordinate offset to use to adjust the input texture coordinate's y value based on whether this is a (1-based) odd frame or an even frame (in the context of interlacing). It will be 0.5(shifting the texture up half a scanline) for an odd frame and-0.5(shifting the texture down half a scanline) for an even frame. - g_prevEvenOddTexelOffset
-
float g_prevEvenOddTexelOffsetType
floatDescription
This value corresponds to the value that
g_curEvenOddTexelOffsethad on the previous frame.This should match
g_curEvenOddTexelOffsetfor a progressive-scan signal and should be-g_curEvenOddTexelOffsetif interlaced. - g_diffusionStrength
-
float g_diffusionStrengthType
floatDescription
This is how much diffusion to apply, blending in the diffusion texture which is an emulation of the light from the screen scattering in the glass on the front of the CRT - 0means "no diffusion" and1means "a whole lot of diffusion." - g_maskStrength
-
float g_maskStrengthType
floatDescription
How much we want to blend in the mask. 0means "mask is not visible" and1means "mask is fully visible." - g_maskDepth
-
float g_maskDepthType
floatDescription
The darkness of the darkest part of the mask. 0means the area between the RGB sections is black,0.9means the spaces between are nearly white.