├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── assets ├── fonts │ └── VCR_OSD_MONO.ttf ├── hdri │ └── skidpan_2k.hdr ├── models │ ├── mon9A24.tmp │ └── monke.obj ├── shaders │ ├── chromatic_aberration.gdshader │ ├── fisheye.gdshader │ ├── grain.gdshader │ ├── sharpen.gdshader │ ├── vhs_color_bleed.gdshader │ ├── vhs_wiggle.gdshader │ └── vignette.gdshader ├── simple_fpsplayer │ ├── Player.gd │ ├── Player.tscn │ └── ability_grab.gd └── textures │ └── dark.png ├── camcordericon.png ├── icon.svg ├── project.godot ├── scenes ├── demo_scene.tscn └── post_processing_stack.tscn ├── screenshot.PNG └── scripts └── ui └── date.gd /.gitattributes: -------------------------------------------------------------------------------- 1 | # Normalize EOL for all files that Git considers text files. 2 | * text=auto eol=lf 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Godot 4+ specific ignores 2 | .godot/ 3 | 4 | # Godot-specific ignores 5 | .import/ 6 | export.cfg 7 | export_presets.cfg 8 | 9 | # Imported translations (automatically generated from CSV files) 10 | *.translation 11 | 12 | # Mono-specific ignores 13 | .mono/ 14 | data_*/ 15 | mono_crash.*.json 16 | 17 | # Kenney ignores 18 | build/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 cyanideoneup 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hi8 Godot Demo 2 | 3 | Example project for a multi-pass shader meant to simulate 8mm tape recording artifacts. Feel free to modify or use however you see fit. 4 | 5 | ![ScreenShot](screenshot.PNG) 6 | -------------------------------------------------------------------------------- /assets/fonts/VCR_OSD_MONO.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyanideoneup/Godot-Hi-8-Demo/bf69fa61d049d9314ea77d409f7e8cada3626911/assets/fonts/VCR_OSD_MONO.ttf -------------------------------------------------------------------------------- /assets/hdri/skidpan_2k.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyanideoneup/Godot-Hi-8-Demo/bf69fa61d049d9314ea77d409f7e8cada3626911/assets/hdri/skidpan_2k.hdr -------------------------------------------------------------------------------- /assets/shaders/chromatic_aberration.gdshader: -------------------------------------------------------------------------------- 1 | shader_type canvas_item; 2 | 3 | uniform int levels = 3; 4 | uniform float spread = 0.01; 5 | uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap; 6 | 7 | 8 | void fragment(){ 9 | vec3 sum; 10 | COLOR.rgb = vec3(0); 11 | vec2 offset = (UV - vec2(0.5))*vec2(1,-1); 12 | for(int i = 0; i < levels; i++){ 13 | float t = 2.0*float(i)/float(levels-1); // range 0.0->2.0 14 | vec3 slice = vec3(1.0-t, 1.0 - abs(t - 1.0), t - 1.0); 15 | slice = max(slice, 0.0); 16 | sum += slice; 17 | vec2 slice_offset = (t-1.0)*spread*offset; 18 | COLOR.rgb += slice * texture(SCREEN_TEXTURE, SCREEN_UV + slice_offset).rgb; 19 | } 20 | COLOR.rgb /= sum; 21 | } -------------------------------------------------------------------------------- /assets/shaders/fisheye.gdshader: -------------------------------------------------------------------------------- 1 | // CREDIT: https://pastebin.com/YmRfSVpG 2 | // Converted from https://www.shadertoy.com/view/td2GzW 3 | shader_type canvas_item; 4 | uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap; 5 | 6 | // Anti fish eye (negative amount) / fish eye (positive) 7 | uniform float effect_amount : hint_range(-2.5, 2.5) = 1.0; 8 | 9 | void fragment() { 10 | // glsl -> godot shader 11 | vec2 iResolution = 1.0 / SCREEN_PIXEL_SIZE; 12 | vec4 fragCoord = FRAGCOORD; 13 | 14 | //normalized coords 15 | vec2 p = fragCoord.xy / iResolution.x; 16 | 17 | //screen proroption 18 | float prop = iResolution.x / iResolution.y; 19 | 20 | //center coords 21 | vec2 m = vec2(0.5, 0.5 / prop); 22 | 23 | //vector from center to current fragment 24 | vec2 d = p - m; 25 | 26 | // distance of pixel from center 27 | float r = sqrt(dot(d, d)); 28 | 29 | float power = effect_amount; 30 | 31 | //radius of 1:1 effect 32 | float bind; 33 | 34 | //stick to borders 35 | if (power > 0.0) 36 | bind = sqrt(dot(m, m)); 37 | else { 38 | if (prop < 1.0) 39 | bind = m.x; 40 | else 41 | bind = m.y; 42 | } 43 | 44 | vec2 uv; 45 | //fisheye 46 | if (power > 0.0) 47 | uv = m + normalize(d) * tan(r * power) * bind / tan( bind * power); 48 | //antifisheye 49 | else if (power < 0.0) 50 | uv = m + normalize(d) * atan(r * -power * 10.0) * bind / atan(-power * bind * 10.0); 51 | //no effect for power = 1.0 52 | else 53 | uv = p; 54 | uv.y *= prop; 55 | 56 | vec3 col = texture(SCREEN_TEXTURE, uv).rgb; 57 | 58 | COLOR = vec4(col, 1.0); 59 | } -------------------------------------------------------------------------------- /assets/shaders/grain.gdshader: -------------------------------------------------------------------------------- 1 | // CREDIT: https://godotshaders.com/shader/grain-old-movie/ 2 | shader_type canvas_item; 3 | // set max strength to your liking here=20.0, step_size=0.1 4 | uniform float strength:hint_range(0, 20.0, 0.1)=16; 5 | 6 | void fragment() { 7 | 8 | // Screen Color 9 | vec4 screen = texture(TEXTURE, SCREEN_UV); 10 | vec2 iResolution = 1.0 / SCREEN_PIXEL_SIZE; 11 | vec2 uv = FRAGCOORD.xy / iResolution.xy; 12 | 13 | // Random noise 14 | float x = (uv.x + 4.0 ) * (uv.y + 4.0 ) * (TIME * 10.0); 15 | // Add grain to Screen 16 | screen = screen+vec4(mod((mod(x, 13.0) ) * (mod(x, 123.0) ), 0.01)-0.005) * strength; 17 | 18 | screen = 1.0 - screen; 19 | COLOR = screen; 20 | 21 | } -------------------------------------------------------------------------------- /assets/shaders/sharpen.gdshader: -------------------------------------------------------------------------------- 1 | shader_type canvas_item; 2 | 3 | // High Pass Sharpening Filter 4 | // Adjust the strength to control the sharpness effect 5 | uniform sampler2D SCREEN_TEXTURE: hint_screen_texture, filter_linear; 6 | uniform float strength : hint_range(0.0, 10.0) = 1.0; 7 | 8 | void fragment() { 9 | vec2 uv = SCREEN_UV; 10 | 11 | vec2 step = SCREEN_PIXEL_SIZE; 12 | 13 | vec3 texA = texture( SCREEN_TEXTURE, uv + vec2(-step.x, -step.y) * 1.5 ).rgb; 14 | vec3 texB = texture( SCREEN_TEXTURE, uv + vec2( step.x, -step.y) * 1.5 ).rgb; 15 | vec3 texC = texture( SCREEN_TEXTURE, uv + vec2(-step.x, step.y) * 1.5 ).rgb; 16 | vec3 texD = texture( SCREEN_TEXTURE, uv + vec2( step.x, step.y) * 1.5 ).rgb; 17 | 18 | vec3 around = 0.25 * (texA + texB + texC + texD); 19 | vec3 center = texture( SCREEN_TEXTURE, uv ).rgb; 20 | 21 | float sharpness = strength; 22 | 23 | vec3 col = center + (center - around) * sharpness; 24 | 25 | COLOR = vec4(col,1.0); 26 | } 27 | -------------------------------------------------------------------------------- /assets/shaders/vhs_color_bleed.gdshader: -------------------------------------------------------------------------------- 1 | // CREDIT: hunterk on the RetroArch GitHub 2 | // https://github.com/exokitxr/emukit/blob/f3b41ed82eb5e870e3b7d7f6ffdf99f311ec37c2/assets/frontend/bundle/shaders/shaders_glsl/vhs/shaders/vhs.glsl 3 | // Original author on ShaderToy 4 | // https://www.shadertoy.com/view/XlsczN 5 | shader_type canvas_item; 6 | 7 | group_uniforms Wiggle; 8 | uniform float wiggle : hint_range(0.0, 1.5, 0.01) = 0.03; 9 | uniform float wiggle_speed : hint_range(0.0, 100.0, 1.0) = 25; 10 | group_uniforms Smear; 11 | uniform float smear : hint_range(0.0, 2.0) = 1.0; 12 | 13 | uniform sampler2D Source : hint_screen_texture, filter_linear_mipmap, repeat_disable; 14 | 15 | group_uniforms Blur; 16 | uniform int blur_samples : hint_range(3, 15, 1) = 15; 17 | 18 | float onOff(float a, float b, float c, float framecount) { 19 | return step(c, sin((framecount * 0.001) + a * cos((framecount * 0.001) * b))); 20 | } 21 | 22 | vec2 jumpy(vec2 uv, float framecount) { 23 | vec2 look = uv; 24 | float window = 1.0 / (1.0 + 80.0 * (look.y - mod(framecount / 4.0, 1.0)) * (look.y - mod(framecount / 4.0, 1.0))); 25 | look.x += 0.05 * sin(look.y * 10.0 + framecount) / 20.0 * onOff(4.0, 4.0, 0.3, framecount) * (0.5 + cos(framecount * 20.0)) * window; 26 | float vShift = (0.1 * wiggle) * 0.4 * onOff(2.0, 3.0, 0.9, framecount) * (sin(framecount) * sin(framecount * 20.0) + (0.5 + 0.1 * sin(framecount * 200.0) * cos(framecount))); 27 | look.y = mod(look.y - 0.01 * vShift, 1.0); 28 | return look; 29 | } 30 | 31 | vec2 Circle(float Start, float Points, float Point) { 32 | float Rad = (3.141592 * 2.0 * (1.0 / Points)) * (Point + Start); 33 | return vec2(-(.3 + Rad), cos(Rad)); 34 | } 35 | 36 | vec3 rgb2yiq(vec3 c) { 37 | return vec3( 38 | (0.2989 * c.x + 0.5959 * c.y + 0.2115 * c.z), 39 | (0.5870 * c.x - 0.2744 * c.y - 0.5229 * c.z), 40 | (0.1140 * c.x - 0.3216 * c.y + 0.3114 * c.z) 41 | ); 42 | } 43 | 44 | vec3 yiq2rgb(vec3 c) { 45 | return vec3( 46 | (1.0 * c.x + 1.0 * c.y + 1.0 * c.z), 47 | (0.956 * c.x - 0.2720 * c.y - 1.1060 * c.z), 48 | (0.6210 * c.x - 0.6474 * c.y + 1.7046 * c.z) 49 | ); 50 | } 51 | 52 | vec3 Blur(vec2 uv, float d, int samples) { 53 | vec3 sum = vec3(0.0); 54 | float W = 1.0 / float(samples); 55 | for (int i = 0; i < samples; ++i) { 56 | float t = (sin(TIME * 5.0 + uv.y * 5.0)) / 10.0; 57 | 58 | t = 0.0; 59 | vec2 PixelOffset = vec2(d + 0.0005 * t, 0); 60 | 61 | float Start = 2.0 / float(samples); 62 | vec2 Scale = 0.66 * 4.0 * 2.0 * PixelOffset.xy; 63 | 64 | vec3 N = texture(Source, uv + Circle(Start, float(samples), float(i)) * Scale).rgb; 65 | sum += N * W; 66 | } 67 | return sum; 68 | } 69 | 70 | void fragment() { 71 | vec2 uv = UV; 72 | 73 | float d=0.1-round(mod(TIME/3.0,1.0))*.1; 74 | uv = jumpy(uv, mod(TIME * wiggle_speed, 7.0)); 75 | 76 | float s = 0.0001 * -d + 0.0001 * wiggle *(sin(TIME * wiggle_speed)); 77 | float e = min(.30,pow(max(0.0,cos(uv.y*4.0+.3)-.75)*(s+0.5)*1.0,3.0))*25.0; 78 | float r = (TIME*(2.0*s)); 79 | uv.x += abs(r*pow(min(.003,(-uv.y+(.01*mod(TIME, 5.0))))*3.0,2.0)) * wiggle; 80 | 81 | d = 0.051+abs(sin(s/4.0)); 82 | float c = max(0.0001,.002*d) * smear; 83 | vec4 final; 84 | 85 | final.rgb = Blur(uv, c + c * uv.x, blur_samples); 86 | float y = rgb2yiq(final.rgb).r; 87 | 88 | uv.x += 0.01 * d; 89 | c *= 6.0; 90 | final.rgb = Blur(uv, c, blur_samples); 91 | float i = rgb2yiq(final.rgb).g; 92 | 93 | uv.x += 0.005 * d; 94 | c *= 2.50; 95 | final.rgb = Blur(uv, c, blur_samples); 96 | float q = rgb2yiq(final.rgb).b; 97 | final.rgb = yiq2rgb(vec3(y, i, q)) - pow(s + e * 2.0, 3.0); 98 | 99 | final.a = 1.0; 100 | 101 | COLOR = final; 102 | } 103 | -------------------------------------------------------------------------------- /assets/shaders/vhs_wiggle.gdshader: -------------------------------------------------------------------------------- 1 | shader_type canvas_item; 2 | 3 | uniform sampler2D SCREEN_TEXTURE: hint_screen_texture, filter_linear; 4 | uniform sampler2D NOISE_TEXTURE: repeat_enable; 5 | uniform float strength: hint_range(0.0, 5, 0.1) = 5.0; 6 | uniform float uv_scaling: hint_range (0.0, 1.0, 0.05) = 1.0; 7 | uniform vec2 movement_direction = vec2(1, 1); 8 | uniform float movement_speed: hint_range (0.0, 0.5, 0.01) = 0.5; 9 | 10 | void fragment() { 11 | vec2 uv = SCREEN_UV; 12 | vec2 movement_factor = movement_direction * movement_speed * TIME; 13 | float noise_value = texture(NOISE_TEXTURE, uv*uv_scaling + movement_factor).r - 0.5; 14 | uv += noise_value * SCREEN_PIXEL_SIZE * strength; 15 | COLOR = texture(SCREEN_TEXTURE, uv); 16 | } -------------------------------------------------------------------------------- /assets/shaders/vignette.gdshader: -------------------------------------------------------------------------------- 1 | shader_type canvas_item; 2 | // CREDIT: https://godotshaders.com/shader/vignette/ 3 | uniform float alpha = 1.0; 4 | uniform float inner_radius = 0.0; 5 | uniform float outer_radius = 1.0; 6 | 7 | void fragment() { 8 | float x = abs(UV.r-.5)*2.0; 9 | float y = abs(UV.g-.5)*2.0; 10 | float q = 1.0-(1.0-sqrt(x*x+y*y)/outer_radius)/(1.0-inner_radius); 11 | COLOR = vec4(0, 0, 0, q*alpha); 12 | } -------------------------------------------------------------------------------- /assets/simple_fpsplayer/Player.gd: -------------------------------------------------------------------------------- 1 | extends CharacterBody3D 2 | 3 | const ACCEL = 10 4 | const DEACCEL = 30 5 | 6 | const SPEED = 5.0 7 | const SPRINT_MULT = 2 8 | const JUMP_VELOCITY = 4.5 9 | const MOUSE_SENSITIVITY = 0.06 10 | 11 | # Get the gravity from the project settings to be synced with RigidDynamicBody nodes. 12 | var gravity = ProjectSettings.get_setting("physics/3d/default_gravity") 13 | 14 | var camera 15 | var rotation_helper 16 | var dir = Vector3.ZERO 17 | var flashlight 18 | 19 | func _ready(): 20 | camera = $rotation_helper/Camera3D 21 | rotation_helper = $rotation_helper 22 | flashlight = $rotation_helper/Camera3D/flashlight_player 23 | 24 | Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN) 25 | Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) 26 | 27 | func _input(event): 28 | # This section controls your player camera. Sensitivity can be changed. 29 | if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED: 30 | rotation_helper.rotate_x(deg_to_rad(event.relative.y * MOUSE_SENSITIVITY * -1)) 31 | self.rotate_y(deg_to_rad(event.relative.x * MOUSE_SENSITIVITY * -1)) 32 | 33 | var camera_rot = rotation_helper.rotation 34 | camera_rot.x = clampf(camera_rot.x, -1.4, 1.4) 35 | rotation_helper.rotation = camera_rot 36 | 37 | # Release/Grab Mouse for debugging. You can change or replace this. 38 | if Input.is_action_just_pressed("ui_cancel"): 39 | if Input.get_mouse_mode() == Input.MOUSE_MODE_VISIBLE: 40 | Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) 41 | else: 42 | Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) 43 | 44 | # Flashlight toggle. Defaults to F on Keyboard. 45 | if event is InputEventKey: 46 | if event.pressed and event.keycode == KEY_F: 47 | if flashlight.is_visible_in_tree() and not event.echo: 48 | flashlight.hide() 49 | elif not event.echo: 50 | flashlight.show() 51 | 52 | func _physics_process(delta): 53 | var moving = false 54 | # Add the gravity. Pulls value from project settings. 55 | if not is_on_floor(): 56 | velocity.y -= gravity * delta 57 | 58 | # Handle Jump. 59 | if Input.is_action_just_pressed("ui_accept") and is_on_floor(): 60 | velocity.y = JUMP_VELOCITY 61 | 62 | # This just controls acceleration. Don't touch it. 63 | var accel 64 | if dir.dot(velocity) > 0: 65 | accel = ACCEL 66 | moving = true 67 | else: 68 | accel = DEACCEL 69 | moving = false 70 | 71 | 72 | # Get the input direction and handle the movement/deceleration. 73 | # As good practice, you should replace UI actions with a custom keymap depending on your control scheme. These strings default to the arrow keys layout. 74 | var input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_backward") 75 | var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized() * accel * delta 76 | if Input.is_key_pressed(KEY_SHIFT): 77 | direction = direction * SPRINT_MULT 78 | else: 79 | pass 80 | 81 | if direction: 82 | velocity.x = direction.x * SPEED 83 | velocity.z = direction.z * SPEED 84 | else: 85 | velocity.x = move_toward(velocity.x, 0, SPEED) 86 | velocity.z = move_toward(velocity.z, 0, SPEED) 87 | 88 | move_and_slide() 89 | -------------------------------------------------------------------------------- /assets/simple_fpsplayer/Player.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=3 uid="uid://dgpjxoygnvyy4"] 2 | 3 | [ext_resource type="Script" path="res://assets/simple_fpsplayer/Player.gd" id="1_1fhis"] 4 | [ext_resource type="Script" path="res://assets/simple_fpsplayer/ability_grab.gd" id="2_gwqkd"] 5 | 6 | [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_euj4i"] 7 | 8 | [sub_resource type="CameraAttributesPractical" id="CameraAttributesPractical_uj8wo"] 9 | auto_exposure_enabled = true 10 | auto_exposure_speed = 2.5 11 | auto_exposure_min_sensitivity = 50.0 12 | auto_exposure_max_sensitivity = 200.0 13 | 14 | [node name="Player" type="CharacterBody3D"] 15 | disable_mode = 2 16 | floor_max_angle = 0.802851 17 | script = ExtResource("1_1fhis") 18 | 19 | [node name="body" type="CollisionShape3D" parent="."] 20 | shape = SubResource("CapsuleShape3D_euj4i") 21 | 22 | [node name="rotation_helper" type="Node3D" parent="."] 23 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0) 24 | 25 | [node name="Camera3D" type="Camera3D" parent="rotation_helper"] 26 | attributes = SubResource("CameraAttributesPractical_uj8wo") 27 | fov = 90.0 28 | 29 | [node name="flashlight_player" type="SpotLight3D" parent="rotation_helper/Camera3D"] 30 | visible = false 31 | light_energy = 3.0 32 | light_bake_mode = 0 33 | spot_range = 10.0 34 | spot_angle = 15.0 35 | spot_angle_attenuation = 1.56917 36 | 37 | [node name="ability_grab" type="RayCast3D" parent="rotation_helper/Camera3D"] 38 | target_position = Vector3(0, 0, -2) 39 | script = ExtResource("2_gwqkd") 40 | 41 | [node name="GrabPosition3D" type="Marker3D" parent="rotation_helper/Camera3D/ability_grab"] 42 | transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -2) 43 | -------------------------------------------------------------------------------- /assets/simple_fpsplayer/ability_grab.gd: -------------------------------------------------------------------------------- 1 | extends RayCast3D 2 | 3 | var object_grabbed = null 4 | var mass_limit = 50 5 | var throw_force = 10 6 | 7 | var can_use = true 8 | 9 | # This entire script is dedicated to the ability_grab node and it's child node GradPosition3D. It's allows players to pick up and throw Rigid Bodies in a similar fashion to Source games. 10 | # This section asks the raycast to check for a Rigid Body, see if it qualifies to be carried, and grab it player isn't currently carrying a Rigid Body. 11 | func _process(delta): 12 | if Input.is_key_pressed(KEY_E): 13 | if can_use: 14 | can_use = false 15 | if not object_grabbed: 16 | if get_collider() is RigidBody3D and not get_collider() is VehicleBody3D and get_collider().mass <= mass_limit: 17 | object_grabbed = get_collider() 18 | else: 19 | release() 20 | else: 21 | can_use = true 22 | 23 | # This part throws whatever Rigid Body is held when Left-Click is pressed. 24 | if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): 25 | if object_grabbed: 26 | object_grabbed.linear_velocity = global_transform.basis.z * -throw_force 27 | release() 28 | 29 | # This stabilizes the Rigid Body when grabbed and releases if Rigid Body gets stuck on something. 30 | if object_grabbed: 31 | var vector = $GrabPosition3D.global_transform.origin - object_grabbed.global_transform.origin 32 | object_grabbed.linear_velocity = vector * 20 33 | object_grabbed.axis_lock_angular_x = true 34 | object_grabbed.axis_lock_angular_y = true 35 | object_grabbed.axis_lock_angular_z = true 36 | if vector.length() >= 3: 37 | release() 38 | 39 | # Releases Rigid Body, disables the axis locks, and let's the script know nothing is being grabbed. 40 | func release(): 41 | object_grabbed.axis_lock_angular_x = false 42 | object_grabbed.axis_lock_angular_y = false 43 | object_grabbed.axis_lock_angular_z = false 44 | object_grabbed = null 45 | -------------------------------------------------------------------------------- /assets/textures/dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyanideoneup/Godot-Hi-8-Demo/bf69fa61d049d9314ea77d409f7e8cada3626911/assets/textures/dark.png -------------------------------------------------------------------------------- /camcordericon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyanideoneup/Godot-Hi-8-Demo/bf69fa61d049d9314ea77d409f7e8cada3626911/camcordericon.png -------------------------------------------------------------------------------- /icon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=5 10 | 11 | [application] 12 | 13 | config/name="Hi8 Demo" 14 | run/main_scene="res://scenes/demo_scene.tscn" 15 | config/features=PackedStringArray("4.2", "Forward Plus") 16 | config/icon="res://camcordericon.png" 17 | 18 | [display] 19 | 20 | window/size/viewport_width=960 21 | window/size/viewport_height=720 22 | window/stretch/mode="viewport" 23 | window/stretch/scale_mode="integer" 24 | 25 | [dotnet] 26 | 27 | project/assembly_name="Hi8 Ddemo" 28 | 29 | [input] 30 | 31 | move_left={ 32 | "deadzone": 0.5, 33 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"echo":false,"script":null) 34 | ] 35 | } 36 | move_right={ 37 | "deadzone": 0.5, 38 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"echo":false,"script":null) 39 | ] 40 | } 41 | move_forward={ 42 | "deadzone": 0.5, 43 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"echo":false,"script":null) 44 | ] 45 | } 46 | move_backward={ 47 | "deadzone": 0.5, 48 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"echo":false,"script":null) 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /scenes/post_processing_stack.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=18 format=3 uid="uid://ctrqmsr0pyume"] 2 | 3 | [ext_resource type="Shader" path="res://assets/shaders/sharpen.gdshader" id="1_ybrub"] 4 | [ext_resource type="Shader" path="res://assets/shaders/fisheye.gdshader" id="2_yj28u"] 5 | [ext_resource type="Shader" path="res://assets/shaders/chromatic_aberration.gdshader" id="3_8pjt1"] 6 | [ext_resource type="Shader" path="res://assets/shaders/vhs_wiggle.gdshader" id="4_gl6sd"] 7 | [ext_resource type="Shader" path="res://assets/shaders/vhs_color_bleed.gdshader" id="5_38f3k"] 8 | [ext_resource type="Shader" path="res://assets/shaders/vignette.gdshader" id="6_xr7m8"] 9 | [ext_resource type="Shader" path="res://assets/shaders/grain.gdshader" id="7_so3lg"] 10 | 11 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_42vu3"] 12 | shader = ExtResource("1_ybrub") 13 | shader_parameter/strength = 2.0 14 | 15 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_xtt21"] 16 | shader = ExtResource("2_yj28u") 17 | shader_parameter/effect_amount = 1.5 18 | 19 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_m1m3a"] 20 | shader = ExtResource("3_8pjt1") 21 | shader_parameter/levels = 3 22 | shader_parameter/spread = 0.003 23 | 24 | [sub_resource type="FastNoiseLite" id="FastNoiseLite_7b6o2"] 25 | frequency = 0.4394 26 | 27 | [sub_resource type="NoiseTexture2D" id="NoiseTexture2D_445nm"] 28 | noise = SubResource("FastNoiseLite_7b6o2") 29 | 30 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_w2755"] 31 | shader = ExtResource("4_gl6sd") 32 | shader_parameter/strength = 5.0 33 | shader_parameter/uv_scaling = 1.0 34 | shader_parameter/movement_direction = Vector2(1, 1) 35 | shader_parameter/movement_speed = 0.5 36 | shader_parameter/NOISE_TEXTURE = SubResource("NoiseTexture2D_445nm") 37 | 38 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_sa2jk"] 39 | shader = ExtResource("5_38f3k") 40 | shader_parameter/wiggle = 0.22 41 | shader_parameter/wiggle_speed = 70.0 42 | shader_parameter/smear = 1.5 43 | shader_parameter/blur_samples = 15 44 | 45 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_3d14i"] 46 | shader = ExtResource("6_xr7m8") 47 | shader_parameter/alpha = 1.0 48 | shader_parameter/inner_radius = 0.405 49 | shader_parameter/outer_radius = 2.385 50 | 51 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_vw16o"] 52 | shader = ExtResource("1_ybrub") 53 | shader_parameter/strength = 0.6 54 | 55 | [sub_resource type="ShaderMaterial" id="ShaderMaterial_hyboy"] 56 | shader = ExtResource("7_so3lg") 57 | shader_parameter/strength = 20.0 58 | 59 | [node name="PostProcessingStack" type="CanvasLayer"] 60 | 61 | [node name="Sharpen1" type="CanvasLayer" parent="."] 62 | 63 | [node name="ColorRect" type="ColorRect" parent="Sharpen1"] 64 | material = SubResource("ShaderMaterial_42vu3") 65 | anchors_preset = 15 66 | anchor_right = 1.0 67 | anchor_bottom = 1.0 68 | grow_horizontal = 2 69 | grow_vertical = 2 70 | mouse_filter = 2 71 | 72 | [node name="Fisheye" type="CanvasLayer" parent="."] 73 | 74 | [node name="ColorRect" type="ColorRect" parent="Fisheye"] 75 | material = SubResource("ShaderMaterial_xtt21") 76 | anchors_preset = 15 77 | anchor_right = 1.0 78 | anchor_bottom = 1.0 79 | grow_horizontal = 2 80 | grow_vertical = 2 81 | mouse_filter = 2 82 | 83 | [node name="ChromaticAberration" type="CanvasLayer" parent="."] 84 | 85 | [node name="ColorRect" type="ColorRect" parent="ChromaticAberration"] 86 | material = SubResource("ShaderMaterial_m1m3a") 87 | anchors_preset = 15 88 | anchor_right = 1.0 89 | anchor_bottom = 1.0 90 | grow_horizontal = 2 91 | grow_vertical = 2 92 | mouse_filter = 2 93 | 94 | [node name="VHSWiggle" type="CanvasLayer" parent="."] 95 | 96 | [node name="ColorRect" type="ColorRect" parent="VHSWiggle"] 97 | material = SubResource("ShaderMaterial_w2755") 98 | anchors_preset = 15 99 | anchor_right = 1.0 100 | anchor_bottom = 1.0 101 | grow_horizontal = 2 102 | grow_vertical = 2 103 | mouse_filter = 2 104 | 105 | [node name="VHSColorBleed" type="CanvasLayer" parent="."] 106 | 107 | [node name="ColorRect" type="ColorRect" parent="VHSColorBleed"] 108 | material = SubResource("ShaderMaterial_sa2jk") 109 | anchors_preset = 15 110 | anchor_right = 1.0 111 | anchor_bottom = 1.0 112 | grow_horizontal = 2 113 | grow_vertical = 2 114 | mouse_filter = 2 115 | 116 | [node name="Vignette" type="CanvasLayer" parent="."] 117 | 118 | [node name="ColorRect" type="ColorRect" parent="Vignette"] 119 | material = SubResource("ShaderMaterial_3d14i") 120 | anchors_preset = 15 121 | anchor_right = 1.0 122 | anchor_bottom = 1.0 123 | grow_horizontal = 2 124 | grow_vertical = 2 125 | mouse_filter = 2 126 | 127 | [node name="Sharpen2" type="CanvasLayer" parent="."] 128 | 129 | [node name="ColorRect" type="ColorRect" parent="Sharpen2"] 130 | material = SubResource("ShaderMaterial_vw16o") 131 | anchors_preset = 15 132 | anchor_right = 1.0 133 | anchor_bottom = 1.0 134 | grow_horizontal = 2 135 | grow_vertical = 2 136 | mouse_filter = 2 137 | 138 | [node name="Grain" type="CanvasLayer" parent="."] 139 | 140 | [node name="ColorRect" type="ColorRect" parent="Grain"] 141 | material = SubResource("ShaderMaterial_hyboy") 142 | anchors_preset = 15 143 | anchor_right = 1.0 144 | anchor_bottom = 1.0 145 | grow_horizontal = 2 146 | grow_vertical = 2 147 | mouse_filter = 2 148 | -------------------------------------------------------------------------------- /screenshot.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyanideoneup/Godot-Hi-8-Demo/bf69fa61d049d9314ea77d409f7e8cada3626911/screenshot.PNG -------------------------------------------------------------------------------- /scripts/ui/date.gd: -------------------------------------------------------------------------------- 1 | extends Label 2 | 3 | func _process(_delta): 4 | var current_datetime_str = Time.get_datetime_string_from_system() 5 | var datetime_components = current_datetime_str.split("T") 6 | 7 | var date_components = datetime_components[0].split("-") 8 | var time_components = datetime_components[1].split(":") 9 | 10 | var year = int(date_components[0]) - 30 11 | var month = int(date_components[1]) 12 | var day = int(date_components[2]) 13 | var hour = int(time_components[0]) 14 | var minute = int(time_components[1]) 15 | 16 | var dst_info = Time.get_datetime_dict_from_system(true) 17 | var dst = dst_info.dst 18 | 19 | if dst: 20 | hour += 1 21 | if hour >= 24: 22 | hour -= 24 23 | day += 1 24 | 25 | var formatted_minute = "%02d" % minute 26 | 27 | var meridian = "AM" 28 | if hour >= 12: 29 | meridian = "PM" 30 | if hour > 12: 31 | hour -= 12 32 | 33 | var date_line1 = meridian + " " + str(hour) + ":" + formatted_minute 34 | var date_line2 = month_to_abbreviation(month) + "." + " " + str(day) + " " + str(year) 35 | text = date_line1 + "\n" + date_line2 36 | 37 | func month_to_abbreviation(month): 38 | match month: 39 | 1: return "Jan" 40 | 2: return "Feb" 41 | 3: return "Mar" 42 | 4: return "Apr" 43 | 5: return "May" 44 | 6: return "Jun" 45 | 7: return "Jul" 46 | 8: return "Aug" 47 | 9: return "Sep" 48 | 10: return "Oct" 49 | 11: return "Nov" 50 | 12: return "Dec" 51 | --------------------------------------------------------------------------------