mirror of
https://github.com/lihop/godot-xterm.git
synced 2024-11-21 17:20:25 +01:00
Add retro term example scene
Uses: - Larger (size 39) font for 80x24 rows. - World environment with glow enabled. - Retro green color scheme based on https://superuser.com/a/1206781 - CRT Shader by Peter Höglund (pend00), released under CC-0 license. Downloaded from https://godotshaders.com/shader/vhs-and-crt-monitor-effect/
This commit is contained in:
parent
1083c13276
commit
0cb458b3d2
4 changed files with 385 additions and 0 deletions
301
examples/retro_term/retro_term.tscn
Normal file
301
examples/retro_term/retro_term.tscn
Normal file
|
@ -0,0 +1,301 @@
|
|||
[gd_scene load_steps=6 format=2]
|
||||
|
||||
[ext_resource path="res://examples/menu/menu.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://themes/retro_green.tres" type="Theme" id=2]
|
||||
|
||||
[sub_resource type="Shader" id=1]
|
||||
code = "/*
|
||||
Shader from Godot Shaders - the free shader library.
|
||||
godotshaders.com/shader/VHS-and-CRT-monitor-effect
|
||||
|
||||
This shader is under CC0 license. Feel free to use, improve and
|
||||
change this shader according to your needs and consider sharing
|
||||
the modified result to godotshaders.com.
|
||||
*/
|
||||
|
||||
shader_type canvas_item;
|
||||
|
||||
//*** IMPORTANT! ***/
|
||||
// - If you are using this shader to affect the node it is applied to set 'overlay' to false (unchecked in the instepctor).
|
||||
// - If you are using this shader as an overlay, and want the shader to affect the nodes below in the Scene hierarchy,
|
||||
// set 'overlay' to true (checked in the inspector).
|
||||
// On Mac there is potentially a bug causing this to not work properly. If that is the case and you want to use the shader as an overlay
|
||||
// change all \"overlay ? SCREEN_TEXTURE : TEXTURE\" to only \"SCREEN_TEXTURE\" on lines 129-140, and \"vec2 uv = overlay ? warp(SCREEN_UV) : warp(UV);\"
|
||||
// to \"vec2 uv = warp(SCREEN_UV);\" on line 98.
|
||||
uniform bool overlay = false;
|
||||
|
||||
uniform float scanlines_opacity : hint_range(0.0, 1.0) = 0.4;
|
||||
uniform float scanlines_width : hint_range(0.0, 0.5) = 0.25;
|
||||
uniform float grille_opacity : hint_range(0.0, 1.0) = 0.3;
|
||||
uniform vec2 resolution = vec2(640.0, 480.0); // Set the number of rows and columns the texture will be divided in. Scanlines and grille will make a square based on these values
|
||||
|
||||
uniform bool pixelate = true; // Fill each square (\"pixel\") with a sampled color, creating a pixel look and a more accurate representation of how a CRT monitor would work.
|
||||
|
||||
uniform bool roll = true;
|
||||
uniform float roll_speed = 8.0; // Positive values are down, negative are up
|
||||
uniform float roll_size : hint_range(0.0, 100.0) = 15.0;
|
||||
uniform float roll_variation : hint_range(0.1, 5.0) = 1.8; // This valie is not an exact science. You have to play around with the value to find a look you like. How this works is explained in the code below.
|
||||
uniform float distort_intensity : hint_range(0.0, 0.2) = 0.05; // The distortion created by the rolling effect.
|
||||
|
||||
uniform float noise_opacity : hint_range(0.0, 1.0) = 0.4;
|
||||
uniform float noise_speed = 5.0; // There is a movement in the noise pattern that can be hard to see first. This sets the speed of that movement.
|
||||
|
||||
uniform float static_noise_intensity : hint_range(0.0, 1.0) = 0.06;
|
||||
|
||||
uniform float aberration : hint_range(-1.0, 1.0) = 0.03; // Chromatic aberration, a distortion on each color channel.
|
||||
uniform float brightness = 1.4; // When adding scanline gaps and grille the image can get very dark. Brightness tries to compensate for that.
|
||||
uniform bool discolor = true; // Add a discolor effect simulating a VHS
|
||||
|
||||
uniform float warp_amount :hint_range(0.0, 5.0) = 1.0; // Warp the texture edges simulating the curved glass of a CRT monitor or old TV.
|
||||
uniform bool clip_warp = false;
|
||||
|
||||
uniform float vignette_intensity = 0.4; // Size of the vignette, how far towards the middle it should go.
|
||||
uniform float vignette_opacity : hint_range(0.0, 1.0) = 0.5;
|
||||
|
||||
// Used by the noise functin to generate a pseudo random value between 0.0 and 1.0
|
||||
vec2 random(vec2 uv){
|
||||
uv = vec2( dot(uv, vec2(127.1,311.7) ),
|
||||
dot(uv, vec2(269.5,183.3) ) );
|
||||
return -1.0 + 2.0 * fract(sin(uv) * 43758.5453123);
|
||||
}
|
||||
|
||||
// Generate a Perlin noise used by the distortion effects
|
||||
float noise(vec2 uv) {
|
||||
vec2 uv_index = floor(uv);
|
||||
vec2 uv_fract = fract(uv);
|
||||
|
||||
vec2 blur = smoothstep(0.0, 1.0, uv_fract);
|
||||
|
||||
return mix( mix( dot( random(uv_index + vec2(0.0,0.0) ), uv_fract - vec2(0.0,0.0) ),
|
||||
dot( random(uv_index + vec2(1.0,0.0) ), uv_fract - vec2(1.0,0.0) ), blur.x),
|
||||
mix( dot( random(uv_index + vec2(0.0,1.0) ), uv_fract - vec2(0.0,1.0) ),
|
||||
dot( random(uv_index + vec2(1.0,1.0) ), uv_fract - vec2(1.0,1.0) ), blur.x), blur.y) * 0.5 + 0.5;
|
||||
}
|
||||
|
||||
// Takes in the UV and warps the edges, creating the spherized effect
|
||||
vec2 warp(vec2 uv){
|
||||
vec2 delta = uv - 0.5;
|
||||
float delta2 = dot(delta.xy, delta.xy);
|
||||
float delta4 = delta2 * delta2;
|
||||
float delta_offset = delta4 * warp_amount;
|
||||
|
||||
return uv + delta * delta_offset;
|
||||
}
|
||||
|
||||
// Adds a black border to hide stretched pixel created by the warp effect
|
||||
float border (vec2 uv){
|
||||
float radius = min(warp_amount, 0.08);
|
||||
radius = max(min(min(abs(radius * 2.0), abs(1.0)), abs(1.0)), 1e-5);
|
||||
vec2 abs_uv = abs(uv * 2.0 - 1.0) - vec2(1.0, 1.0) + radius;
|
||||
float dist = length(max(vec2(0.0), abs_uv)) / radius;
|
||||
float square = smoothstep(0.96, 1.0, dist);
|
||||
return clamp(1.0 - square, 0.0, 1.0);
|
||||
}
|
||||
|
||||
// Adds a vignette shadow to the edges of the image
|
||||
float vignette(vec2 uv){
|
||||
uv *= 1.0 - uv.xy;
|
||||
float vignette = uv.x * uv.y * 15.0;
|
||||
return pow(vignette, vignette_intensity * vignette_opacity);
|
||||
}
|
||||
|
||||
void fragment()
|
||||
{
|
||||
vec2 uv = overlay ? warp(SCREEN_UV) : warp(UV); // Warp the uv. uv will be used in most cases instead of UV to keep the warping
|
||||
vec2 text_uv = uv;
|
||||
vec2 roll_uv = vec2(0.0);
|
||||
float time = roll ? TIME : 0.0;
|
||||
|
||||
|
||||
// Pixelate the texture based on the given resolution.
|
||||
if (pixelate)
|
||||
{
|
||||
text_uv = ceil(uv * resolution) / resolution;
|
||||
}
|
||||
|
||||
// Create the rolling effect. We need roll_line a bit later to make the noise effect.
|
||||
// That is why this runs if roll is true OR noise_opacity is over 0.
|
||||
float roll_line = 0.0;
|
||||
if (roll || noise_opacity > 0.0)
|
||||
{
|
||||
// Create the areas/lines where the texture will be distorted.
|
||||
roll_line = smoothstep(0.3, 0.9, sin(uv.y * roll_size - (time * roll_speed) ) );
|
||||
// Create more lines of a different size and apply to the first set of lines. This creates a bit of variation.
|
||||
roll_line *= roll_line * smoothstep(0.3, 0.9, sin(uv.y * roll_size * roll_variation - (time * roll_speed * roll_variation) ) );
|
||||
// Distort the UV where where the lines are
|
||||
roll_uv = vec2(( roll_line * distort_intensity * (1.-UV.x)), 0.0);
|
||||
}
|
||||
|
||||
vec4 text;
|
||||
if (roll)
|
||||
{
|
||||
// If roll is true distort the texture with roll_uv. The texture is split up into RGB to
|
||||
// make some chromatic aberration. We apply the aberration to the red and green channels accorging to the aberration parameter
|
||||
// and intensify it a bit in the roll distortion.
|
||||
text.r = texture(SCREEN_TEXTURE, text_uv + roll_uv * 0.8 + vec2(aberration, 0.0) * .1).r;
|
||||
text.g = texture(SCREEN_TEXTURE, text_uv + roll_uv * 1.2 - vec2(aberration, 0.0) * .1 ).g;
|
||||
text.b = texture(SCREEN_TEXTURE, text_uv + roll_uv).b;
|
||||
text.a = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If roll is false only apply the aberration without any distorion. The aberration values are very small so the .1 is only
|
||||
// to make the slider in the Inspector less sensitive.
|
||||
text.r = texture(SCREEN_TEXTURE, text_uv + vec2(aberration, 0.0) * .1).r;
|
||||
text.g = texture(SCREEN_TEXTURE, text_uv - vec2(aberration, 0.0) * .1).g;
|
||||
text.b = texture(SCREEN_TEXTURE, text_uv).b;
|
||||
text.a = 1.0;
|
||||
}
|
||||
|
||||
float r = text.r;
|
||||
float g = text.g;
|
||||
float b = text.b;
|
||||
|
||||
uv = warp(UV);
|
||||
|
||||
// CRT monitors don't have pixels but groups of red, green and blue dots or lines, called grille. We isolate the texture's color channels
|
||||
// and divide it up in 3 offsetted lines to show the red, green and blue colors next to each other, with a small black gap between.
|
||||
if (grille_opacity > 0.0){
|
||||
|
||||
float g_r = smoothstep(0.85, 0.95, abs(sin(uv.x * (resolution.x * 3.14159265))));
|
||||
r = mix(r, r * g_r, grille_opacity);
|
||||
|
||||
float g_g = smoothstep(0.85, 0.95, abs(sin(1.05 + uv.x * (resolution.x * 3.14159265))));
|
||||
g = mix(g, g * g_g, grille_opacity);
|
||||
|
||||
float b_b = smoothstep(0.85, 0.95, abs(sin(2.1 + uv.x * (resolution.x * 3.14159265))));
|
||||
b = mix(b, b * b_b, grille_opacity);
|
||||
|
||||
}
|
||||
|
||||
// Apply the grille to the texture's color channels and apply Brightness. Since the grille and the scanlines (below) make the image very dark you
|
||||
// can compensate by increasing the brightness.
|
||||
text.r = clamp(r * brightness, 0.0, 1.0);
|
||||
text.g = clamp(g * brightness, 0.0, 1.0);
|
||||
text.b = clamp(b * brightness, 0.0, 1.0);
|
||||
|
||||
// Scanlines are the horizontal lines that make up the image on a CRT monitor.
|
||||
// Here we are actual setting the black gap between each line, which I guess is not the right definition of the word, but you get the idea
|
||||
float scanlines = 0.5;
|
||||
if (scanlines_opacity > 0.0)
|
||||
{
|
||||
// Same technique as above, create lines with sine and applying it to the texture. Smoothstep to allow setting the line size.
|
||||
scanlines = smoothstep(scanlines_width, scanlines_width + 0.5, abs(sin(uv.y * (resolution.y * 3.14159265))));
|
||||
text.rgb = mix(text.rgb, text.rgb * vec3(scanlines), scanlines_opacity);
|
||||
}
|
||||
|
||||
// Apply the banded noise.
|
||||
if (noise_opacity > 0.0)
|
||||
{
|
||||
// Generate a noise pattern that is very stretched horizontally, and animate it with noise_speed
|
||||
float noise = smoothstep(0.4, 0.5, noise(uv * vec2(2.0, 200.0) + vec2(10.0, (TIME * (noise_speed))) ) );
|
||||
|
||||
// We use roll_line (set above) to define how big the noise should be vertically (multiplying cuts off all black parts).
|
||||
// We also add in some basic noise with random() to break up the noise pattern above. The noise is sized according to
|
||||
// the resolution value set in the inspector. If you don't like this look you can
|
||||
// change \"ceil(uv * resolution) / resolution\" to only \"uv\" to make it less pixelated. Or multiply resolution with som value
|
||||
// greater than 1.0 to make them smaller.
|
||||
roll_line *= noise * scanlines * clamp(random((ceil(uv * resolution) / resolution) + vec2(TIME * 0.8, 0.0)).x + 0.8, 0.0, 1.0);
|
||||
// Add it to the texture based on noise_opacity
|
||||
text.rgb = clamp(mix(text.rgb, text.rgb + roll_line, noise_opacity), vec3(0.0), vec3(1.0));
|
||||
}
|
||||
|
||||
// Apply static noise by generating it over the whole screen in the same way as above
|
||||
if (static_noise_intensity > 0.0)
|
||||
{
|
||||
text.rgb += clamp(random((ceil(uv * resolution) / resolution) + fract(TIME)).x, 0.0, 1.0) * static_noise_intensity;
|
||||
}
|
||||
|
||||
// Apply a black border to hide imperfections caused by the warping.
|
||||
// Also apply the vignette
|
||||
text.rgb *= border(uv);
|
||||
text.rgb *= vignette(uv);
|
||||
// Hides the black border and make that area transparent. Good if you want to add the the texture on top an image of a TV or monitor.
|
||||
if (clip_warp)
|
||||
{
|
||||
text.a = border(uv);
|
||||
}
|
||||
|
||||
// Apply discoloration to get a VHS look (lower saturation and higher contrast)
|
||||
// You can play with the values below or expose them in the Inspector.
|
||||
float saturation = 0.5;
|
||||
float contrast = 1.2;
|
||||
if (discolor)
|
||||
{
|
||||
// Saturation
|
||||
vec3 greyscale = vec3(text.r + text.g + text.b) / 3.;
|
||||
text.rgb = mix(text.rgb, greyscale, saturation);
|
||||
|
||||
// Contrast
|
||||
float midpoint = pow(0.5, 2.2);
|
||||
text.rgb = (text.rgb - vec3(midpoint)) * contrast + midpoint;
|
||||
}
|
||||
|
||||
COLOR = text;
|
||||
}"
|
||||
|
||||
[sub_resource type="ShaderMaterial" id=2]
|
||||
shader = SubResource( 1 )
|
||||
shader_param/overlay = true
|
||||
shader_param/scanlines_opacity = 0.4
|
||||
shader_param/scanlines_width = 0.25
|
||||
shader_param/grille_opacity = 0.3
|
||||
shader_param/resolution = Vector2( 768, 240 )
|
||||
shader_param/pixelate = false
|
||||
shader_param/roll = true
|
||||
shader_param/roll_speed = 8.0
|
||||
shader_param/roll_size = 15.0
|
||||
shader_param/roll_variation = 1.8
|
||||
shader_param/distort_intensity = 0.05
|
||||
shader_param/noise_opacity = 0.4
|
||||
shader_param/noise_speed = 5.0
|
||||
shader_param/static_noise_intensity = 0.06
|
||||
shader_param/aberration = 0.0
|
||||
shader_param/brightness = 2.5
|
||||
shader_param/discolor = true
|
||||
shader_param/warp_amount = 1.0
|
||||
shader_param/clip_warp = false
|
||||
shader_param/vignette_intensity = 0.4
|
||||
shader_param/vignette_opacity = 0.5
|
||||
|
||||
[sub_resource type="Environment" id=3]
|
||||
background_mode = 4
|
||||
glow_enabled = true
|
||||
glow_intensity = 1.0
|
||||
glow_strength = 1.15
|
||||
glow_blend_mode = 0
|
||||
|
||||
[node name="RetroTerm" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
theme = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="."]
|
||||
show_behind_parent = true
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color( 0.156863, 0.156863, 0.156863, 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Menu" parent="." instance=ExtResource( 1 )]
|
||||
margin_left = 30.0
|
||||
margin_top = 30.0
|
||||
|
||||
[node name="CanvasLayer" type="CanvasLayer" parent="."]
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="CanvasLayer"]
|
||||
modulate = Color( 0, 1, 0.4, 1 )
|
||||
material = SubResource( 2 )
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||
environment = SubResource( 3 )
|
35
themes/retro_green.tres
Normal file
35
themes/retro_green.tres
Normal file
|
@ -0,0 +1,35 @@
|
|||
[gd_resource type="Theme" load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_xterm/resources/xrdb_theme.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/godot_xterm/themes/fonts/hack/hack_regular-3.003.ttf" type="DynamicFontData" id=2]
|
||||
|
||||
[sub_resource type="DynamicFont" id=1]
|
||||
size = 39
|
||||
extra_spacing_bottom = 1
|
||||
font_data = ExtResource( 2 )
|
||||
|
||||
[resource]
|
||||
Terminal/colors/Background = Color( 0.156863, 0.156863, 0.156863, 1 )
|
||||
Terminal/colors/Black = Color( 0, 1, 0.4, 1 )
|
||||
Terminal/colors/Blue = Color( 0, 1, 0.4, 1 )
|
||||
Terminal/colors/Cursor = Color( 0, 1, 0.4, 1 )
|
||||
Terminal/colors/Cyan = Color( 0, 1, 0.4, 1 )
|
||||
"Terminal/colors/Dark Grey" = Color( 0, 1, 0.4, 1 )
|
||||
Terminal/colors/Foreground = Color( 0, 1, 0.4, 1 )
|
||||
Terminal/colors/Green = Color( 0, 1, 0.4, 1 )
|
||||
"Terminal/colors/Light Blue" = Color( 0, 1, 0.4, 1 )
|
||||
"Terminal/colors/Light Cyan" = Color( 0, 1, 0.4, 1 )
|
||||
"Terminal/colors/Light Green" = Color( 0, 1, 0.4, 1 )
|
||||
"Terminal/colors/Light Grey" = Color( 0, 1, 0.4, 1 )
|
||||
"Terminal/colors/Light Magenta" = Color( 0, 1, 0.4, 1 )
|
||||
"Terminal/colors/Light Red" = Color( 0, 1, 0.4, 1 )
|
||||
"Terminal/colors/Light Yellow" = Color( 0, 1, 0.4, 1 )
|
||||
Terminal/colors/Magenta = Color( 0, 1, 0.4, 1 )
|
||||
Terminal/colors/Red = Color( 0, 1, 0.4, 1 )
|
||||
Terminal/colors/White = Color( 0, 1, 0.4, 1 )
|
||||
Terminal/colors/Yellow = Color( 0, 1, 0.4, 1 )
|
||||
Terminal/fonts/Bold = null
|
||||
"Terminal/fonts/Bold Italic" = null
|
||||
Terminal/fonts/Italic = null
|
||||
Terminal/fonts/Regular = SubResource( 1 )
|
||||
script = ExtResource( 1 )
|
36
themes/retro_green.xresources
Normal file
36
themes/retro_green.xresources
Normal file
|
@ -0,0 +1,36 @@
|
|||
! special
|
||||
*.foreground: #00ff66
|
||||
*.background: #282828
|
||||
*.cursorColor: #00ff66
|
||||
|
||||
! black
|
||||
*.color0: #00ff66
|
||||
*.color8: #00ff66
|
||||
|
||||
! red
|
||||
*.color1: #00ff66
|
||||
*.color9: #00ff66
|
||||
|
||||
! green
|
||||
*.color2: #00ff66
|
||||
*.color10: #00ff66
|
||||
|
||||
! yellow
|
||||
*.color3: #00ff66
|
||||
*.color11: #00ff66
|
||||
|
||||
! blue
|
||||
*.color4: #00ff66
|
||||
*.color12: #00ff66
|
||||
|
||||
! magenta
|
||||
*.color5: #00ff66
|
||||
*.color13: #00ff66
|
||||
|
||||
! cyan
|
||||
*.color6: #00ff66
|
||||
*.color14: #00ff66
|
||||
|
||||
! white
|
||||
*.color7: #00ff66
|
||||
*.color15: #00ff66
|
13
themes/retro_green.xresources.import
Normal file
13
themes/retro_green.xresources.import
Normal file
|
@ -0,0 +1,13 @@
|
|||
[remap]
|
||||
|
||||
importer="godot_xterm_xrdb_importer"
|
||||
type="Theme"
|
||||
path="res://.import/retro_green.xresources-3110df277701da17f502f808acb29c51.res"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://themes/retro_green.xresources"
|
||||
dest_files=[ "res://.import/retro_green.xresources-3110df277701da17f502f808acb29c51.res" ]
|
||||
|
||||
[params]
|
||||
|
Loading…
Reference in a new issue