Okey, let’s try to make something cool. Do you remember the Fallout’s Pipboy? I’m loving it and always wanted to have one.
So, I want to make it similar, from scratch where I have one plane (2 triangles) and one texture. And FLSL of course )
Our future result:
What do we need?
 Slightly bend texture because it is CRT.

Tint it green

Place interlace effect

And show frequency waves
The first is pure math. I need kind of a function, that changes UV from one point to another.
Offset of every point depends on distance from it to the center (AO). The more this distance is, the more is offset.
Function shouldn’t be linear: density in the center is less than near the borders.
So, I built a function that meets the given criteria:
The complete transformation is:
float2 ruv = iUV0; ruv = 0.5; ruv*=screenSize;
ruv is our new UV, then we move UV coordinate system from 0..1 to 0.5..0.5 – because points need to be moved in direction of center.
float d = length(ruv.xy); const float max_radius = 0.70711;
max_radius – is a distance to corner. It is sqrt of 0.5.
float modified = sin((d/max_radius/2.5)*PI)/1.55; ruv += ruv*(dmodified);
Here is our function. Then we move the point by adding UV.
ruv*=(2.2distort); ruv += 0.5;
Bend value and we going back to normal coordinates from 0 to 1.
So, these are all transformations.
Let’s color it.
I can remove repeated texture by setting it to black. It is not a very good way, but it works )
float modifier = (ruv.x>=0)*(ruv.y>=0)*(ruv.x<=1)*(ruv.y<=1); output fragment = color*modifier;
Grayscale it
float modifier = (ruv.x>=0)*(ruv.y>=0)*(ruv.x<=1)*(ruv.y<=1); float4 finalColor = grayscaleLightnessColor(color)*modifier output fragment = finalColor*modifier;
Tint it to given color
output fragment = finalColor*modifier*tint;
Place interlace effect
float interlace = 1+clamp(sin(ruv.y*PI*inerlaceFrequency)*0.25,0.0,0.25)*interlaceIntensity; output fragment = finalColor*modifier*tint*interlace;
And make flicks – one big with low frequency and small flicks with high frequency
float flicks = 1; flicks += sin((ruv.y+time.x*5)*PI*3.5)*0.2; flicks += sin((ruv.y+time.x)*PI*2)*0.2; flicks *= flickIntensity; output fragment = finalColor*modifier*tint*interlace*flicks;
That’s it. The complete shader:
use namespace flare; use namespace flare.transforms; use namespace flare.filters; param float4 tint <ui = "color"> = float4(0.7,1,0.7,1); param float4 backColor <ui = "color"> = float4(0.7,1,0.7,1); sampler2D texture2; param float screenSize = 1.1; param float distort = 1.1; param float flickIntensity = 1; param float interlaceIntensity = 1; param float inerlaceFrequency = 200; param TIME time; float grayscaleLightness(float4 color) { return max(max(color.r,color.g),color.b)+min(min(color.r,color.g),color.b)/2; } float4 grayscaleLightnessColor(float4 color) { return float4(grayscaleLightness(color)); } technique main { output vertex = transform(); float2 ruv = iUV0; ruv = 0.5; ruv*=screenSize; float d = length(ruv.xy); const float max_radius = 0.70711; float modified = sin((d/max_radius/2.5)*PI)/1.55; ruv += ruv*(dmodified); ruv*=(2.2distort); ruv += 0.5; float darklevel = clamp((1d)*1.4,0,1); float4 color = sampler2D( texture2, ruv); float modifier = (ruv.x>=0)*(ruv.y>=0)*(ruv.x<=1)*(ruv.y<=1); float4 finalColor = grayscaleLightnessColor(color)*modifier float interlace = 1+clamp(sin(ruv.y*PI*inerlaceFrequency)*0.25,0.0,0.25)*interlaceIntensity; float flicks = 1; flicks += sin((ruv.y+time.x*5)*PI*3.5)*0.2; flicks += sin((ruv.y+time.x)*PI*2)*0.2; flicks *= flickIntensity; output fragment = finalColor*modifier*tint*interlace*flicks; }