For my project, I've been working on a kind of 80s style sci-fi monitor display.In game, this is going to be handled by a single texture effect with a GLSL shader.
Different sections of the texture will be cut down and used on different view screens. Here's a preview of how it looks in action:
Screen capture in Linux Mint is always a bit buggy. :( Or maybe it's because my computer is over ten years old...
Here's another set of screens with different colors and contents, for the planet that the player gets to visit in the first episode (you can see in this preview how the "alert effect" is activated to change colors of the scan):
You can see the original effect I'm trying to duplicate in the Star Trek movies:
Anyway, it's a nice set of old school effects, and I'm going to explain how they are achieved in a game engine with a GLSL shader (In this case, GODOT, and awesome free game engine).
First you need to set up the different layers of your image. You can use three separate greyscale images if you like, but it won't make things better AFAIK.
Red layer is the text crawl and scan effect:
You can see how the scan is acheived with a gradient, and the same is done with the text, shading from white to black. Make sure the gradient is done with linear interpolation, or it won't scan evenly over time.
Next is green, which controls a pulsing effect on the waveforms and some other effects, like pulsing buttons:
Again, they are treated like gradients, shaded from the center outwards.
Lastly is the blue channel, which is not animated, and represents background elements:
This one can be modified with blur effects to get that classic CRT glow... don't use any post processing on the other channels though, because it will make their effects turn out wonky.When combined into one image with three channels it looks like this:
You can use more textures or even try using the alpha channel to get more effects, it's up to you. I left it at 2 because it was already starting to get a bit busy. Less is sometimes more.
Now lets' look at some of the GLSL code:
shader_type spatial;
render_mode unshaded, blend_add;
uniform sampler2D lcars;
uniform float alert;
We are writing a spatial shader, and we want it to be unshaded and "additive" so that it will glow over the background elements. I'm going to be using modeled props for the screens and I want to see only the glowing elements of the shader. Where it's black, the underlying screen prop should show through.
lcars is the name of the viewscreens in Star Trek. Here it's the name of our RGB image. The float, alert, is to blend between two colors, so we can have the scanner effect come out in red, or hide it or have it come in a different color. See the second gif above to see how that works.
The next bit is a little more complicated.
There are several steps here that need to be taken in order to get the effect to come out right. I'm just going to be showing the basic text crawl /scan effect, which you can then modify for your own needs.
vec4 lc = texture(lcars, UV);
float crawl = 1.0 - fract(TIME * 0.5);
float t2 = lc.r;
float c1 = smoothstep(crawl * 0.8, crawl, t2);
float c2 = smoothstep(crawl + 0.1, crawl, t2);
float c3 = mix(0.0, c2, c1);
float c4 = c1 * 0.5;
float c5 = max(c3, c4);
vec3 alert_off = vec3(c5 * 0.2, c5 * 0.4, c5 * 0.5);
vec3 alert_on = vec3(c5, 0.0, 0.0);
vec3 text_crawl = mix(alert_off, alert_on, alert);
We start out by getting our texture. We only need one part here, the red channel. We're going to be working with floats.
Next we need to use the TIME built-in object to make the animation work.
frac will return just the fraction part of time. So it will always give a figure between 0.0 and 0.9999.. This will keep the effect repeating.
We want to to go "up" instead of down, so we want a value of 1.0 - fract(TIME).
Scaling time (in this case by 0.5) will make the effect cycle faster or slower. TIME * 4.0 would be really fast. TIME * 0.1 would be much slower.
We're going to use smoothstep to remap the gradient:
c1 maps the gradient from 1.0 to 0.0. You can stick with this basic effect if you like. It will make the text crawl work, but it's all just appearing.
We want it to glow as it appears and then fade away. So we use c2 as a negative filter. With smoothstep, if you set the first argument higher than the second one, it will invert the output when mapping the values (1.0 to 0.0). You could do this instead of inverting the crawl value... but you still need one negative and one positive gradient.
We then mix these with black (0.0) so that c3 will create a pulse that rides the edge of the gradient. Again, you can use this effect as you like. If you want the text to only display as it prints and then fade to black, you could use c3 as the final value.
I don't want that though, so I mix c3 with a weaker form of c1 to get the final effect.
Finally, I want to be able to change from a blue color to a red color effect when alert is set to 1.0. So I set two vec3 and mix between them with the alert uniform.
If you want the effect to pulse instead of crawl, you can use sin(TIME) instead of frac(TIME). That's what I used for the waveform effects.
Once you've put together each of your effects with the background color, just mix them together into a final vec3.
For my own shader, I put all this in a function (get_pixel), then called it twice. Adding a slight UV offset (UV + 0.001) and putting the elements together in a different order (get_pixel().brg instead of .rgb) gives a nice CRT chromatic aberration effect that duplicates the feel of some 80s sci-fi special effects.
As a last mention, you can really increase the quality of the effect by using uncompressed textures... but it might not be worth the benefit, since it will use a lot more resources once you've got a few of these shaders in your game.Otherwise, use VIDEO RAM mode for textures and turn off filter and mipmaps to avoid the worst artifacts.
Here's a shot of how that looks when compared to uncompressed textures:It's up to you whether you can live with the artifacts generated. It's honestly still probably better than the quality you could expect from a real CRT monitor, so it might be worth just going with it.
Note: all these screenshots were created in a project running GLES2. Post processing effects such as bloom will change how they look in GLES3, so you need to choose different values for colors. You could use uniforms to set them on the fly when you switch modes, or you could write different shaders for different modes.
Comments
Post a Comment