diff --git a/README.md b/README.md index e63df6f..0ba1b0d 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ ## Camera Effects -These effects are mostly to be placed as a child of Camera object +These effects should be place in a CanvasLayer object in any scene ### Pixelate @@ -40,9 +40,13 @@ These effects are mostly to be placed as a child of Camera object ![Vignette](./docs/images/camera-effects/vignette.png) +### Chromatic Aberration + +![Chromatic Aberration](./docs/images/camera-effects/chromatic-aberration.png) + ## License * Kenney Particle Pack is copyrighted by Kenney, and can be found at https://kenney.nl/assets/particle-pack * Kenney Prototype Tools is copyrighted by Kenney, and can be found at https://github.com/GeroVeni/kenney_prototype_tools -Except for that, the particles and code in this repository are available under MIT license for free usage. \ No newline at end of file +Except for that, the particles and code in this repository are available under MIT license for free usage. diff --git a/camera-effects.tscn b/camera-effects.tscn index 49f1182..743ca3f 100644 --- a/camera-effects.tscn +++ b/camera-effects.tscn @@ -1,13 +1,14 @@ -[gd_scene load_steps=12 format=3 uid="uid://c051w6upl0t16"] +[gd_scene load_steps=13 format=3 uid="uid://c051w6upl0t16"] -[ext_resource type="PackedScene" uid="uid://dgv546pcp176" path="res://camera-effects/camera-pixelate.tscn" id="1_1s7cw"] [ext_resource type="PackedScene" uid="uid://bydyult2k5rcb" path="res://addons/kenney_prototype_tools/scenes/green/green_01.tscn" id="1_61jfr"] -[ext_resource type="PackedScene" uid="uid://b3fmmgvf3owwy" path="res://camera-effects/camera-vignette.tscn" id="2_c86ci"] [ext_resource type="PackedScene" uid="uid://bjupt5nu14hth" path="res://addons/kenney_prototype_tools/scenes/dark/dark_05.tscn" id="2_xlmfj"] [ext_resource type="PackedScene" uid="uid://bhuxup1cbugbw" path="res://addons/kenney_prototype_tools/scenes/orange/orange_06.tscn" id="3_xj16f"] [ext_resource type="PackedScene" uid="uid://ct0k1os3fx251" path="res://addons/kenney_prototype_tools/scenes/purple/purple_03.tscn" id="4_paly4"] [ext_resource type="PackedScene" uid="uid://d23c4qtufdpk7" path="res://addons/kenney_prototype_tools/scenes/red/red_02.tscn" id="5_dra7r"] [ext_resource type="PackedScene" uid="uid://npssehgc2462" path="res://addons/kenney_prototype_tools/scenes/light/light_06.tscn" id="6_y7myb"] +[ext_resource type="PackedScene" uid="uid://sy04esp2kle1" path="res://camera-effects/chromatic_aberration.tscn" id="7_uoado"] +[ext_resource type="PackedScene" uid="uid://djsrvtsqjesw8" path="res://camera-effects/pixelate.tscn" id="8_fshcg"] +[ext_resource type="PackedScene" uid="uid://ds5xw2us1br3q" path="res://camera-effects/vignette.tscn" id="9_q1phu"] [sub_resource type="Environment" id="Environment_tln01"] glow_blend_mode = 4 @@ -29,10 +30,6 @@ current = true fov = 13.5 size = 13.34 -[node name="Pixelate" parent="Camera3D" instance=ExtResource("1_1s7cw")] - -[node name="Vignette" parent="Camera3D" instance=ExtResource("2_c86ci")] - [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] transform = Transform3D(1, 0, 0, 0, 0.5, 0.866025, 0, -0.866025, 0.5, 0, 2, 0) light_energy = 2.0 @@ -150,3 +147,13 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6, 0, -7) [node name="Cube36" parent="Scene" instance=ExtResource("6_y7myb")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5, 0, -8) + +[node name="CanvasLayer" type="CanvasLayer" parent="."] + +[node name="Chromatic Aberration" parent="CanvasLayer" instance=ExtResource("7_uoado")] +visible = false + +[node name="Pixelate" parent="CanvasLayer" instance=ExtResource("8_fshcg")] +visible = false + +[node name="Vignette" parent="CanvasLayer" instance=ExtResource("9_q1phu")] diff --git a/camera-effects/camera-pixelate.tscn b/camera-effects/camera-pixelate.tscn deleted file mode 100644 index f58e41d..0000000 --- a/camera-effects/camera-pixelate.tscn +++ /dev/null @@ -1,26 +0,0 @@ -[gd_scene load_steps=5 format=3 uid="uid://dgv546pcp176"] - -[sub_resource type="Gradient" id="Gradient_hmc0v"] -offsets = PackedFloat32Array(0.225256, 0.703072) -colors = PackedColorArray(0, 0, 0, 0, 0, 0, 0, 1) - -[sub_resource type="GradientTexture2D" id="GradientTexture2D_1cjfc"] -gradient = SubResource("Gradient_hmc0v") -width = 256 -height = 256 -fill = 1 -fill_from = Vector2(0.5, 0.5) - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_q043q"] -transparency = 1 -albedo_texture = SubResource("GradientTexture2D_1cjfc") -roughness = 0.0 - -[sub_resource type="QuadMesh" id="QuadMesh_002xp"] -material = SubResource("StandardMaterial3D_q043q") -size = Vector2(24, 14) - -[node name="Pixelate" type="MeshInstance3D"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.820396) -visible = false -mesh = SubResource("QuadMesh_002xp") diff --git a/camera-effects/camera-vignette.tscn b/camera-effects/camera-vignette.tscn deleted file mode 100644 index bcb628f..0000000 --- a/camera-effects/camera-vignette.tscn +++ /dev/null @@ -1,47 +0,0 @@ -[gd_scene load_steps=8 format=3 uid="uid://b3fmmgvf3owwy"] - -[sub_resource type="Curve" id="Curve_kdxx2"] -max_value = 1.5 -_data = [Vector2(0, 1.5), 0.0, 0.0, 0, 0, Vector2(0.498361, 1.28219), 0.0, 0.0, 0, 0, Vector2(1, 1.5), 0.0, 0.0, 0, 0] -point_count = 3 - -[sub_resource type="CurveTexture" id="CurveTexture_ts23d"] -curve = SubResource("Curve_kdxx2") - -[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_a08vp"] -gravity = Vector3(0, 0, 0) -scale_curve = SubResource("CurveTexture_ts23d") - -[sub_resource type="Gradient" id="Gradient_0ankm"] -offsets = PackedFloat32Array(0.430605, 0.733096) -colors = PackedColorArray(0, 0, 0, 0, 0.392157, 0, 0, 1) - -[sub_resource type="GradientTexture2D" id="GradientTexture2D_s3frb"] -gradient = SubResource("Gradient_0ankm") -width = 256 -height = 256 -fill = 1 -fill_from = Vector2(0.5, 0.5) - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_8laxd"] -transparency = 1 -vertex_color_use_as_albedo = true -albedo_texture = SubResource("GradientTexture2D_s3frb") -roughness = 0.0 -billboard_mode = 3 -billboard_keep_scale = true -particles_anim_h_frames = 1 -particles_anim_v_frames = 1 -particles_anim_loop = false - -[sub_resource type="QuadMesh" id="QuadMesh_hh0er"] -material = SubResource("StandardMaterial3D_8laxd") -size = Vector2(24, 14) - -[node name="Vignette" type="GPUParticles3D"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.5) -amount = 1 -lifetime = 3.0 -fixed_fps = 60 -process_material = SubResource("ParticleProcessMaterial_a08vp") -draw_pass_1 = SubResource("QuadMesh_hh0er") diff --git a/camera-effects/chromatic-aberration.gdshader b/camera-effects/chromatic-aberration.gdshader new file mode 100644 index 0000000..1778aa1 --- /dev/null +++ b/camera-effects/chromatic-aberration.gdshader @@ -0,0 +1,15 @@ +shader_type canvas_item; + +// inspired by: https://www.youtube.com/watch?v=aVzY6n3e19A + +uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear; +uniform float ca_strength = 20.0; + +void fragment() { + vec2 ca_offset = vec2(ca_strength, 0.0) * SCREEN_PIXEL_SIZE; + float red = texture(SCREEN_TEXTURE, SCREEN_UV - ca_offset).r; + float green = texture(SCREEN_TEXTURE, SCREEN_UV).g; + float blue = texture(SCREEN_TEXTURE, SCREEN_UV + ca_offset).b; + + COLOR = vec4(red, green, blue, 1.0); +} diff --git a/camera-effects/chromatic_aberration.tscn b/camera-effects/chromatic_aberration.tscn new file mode 100644 index 0000000..fe47c1b --- /dev/null +++ b/camera-effects/chromatic_aberration.tscn @@ -0,0 +1,15 @@ +[gd_scene load_steps=3 format=3 uid="uid://sy04esp2kle1"] + +[ext_resource type="Shader" path="res://camera-effects/chromatic-aberration.gdshader" id="1_qe316"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_bla75"] +shader = ExtResource("1_qe316") +shader_parameter/ca_strength = 20.0 + +[node name="Chromatic Aberration" type="ColorRect"] +material = SubResource("ShaderMaterial_bla75") +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 diff --git a/camera-effects/pixelate.gdshader b/camera-effects/pixelate.gdshader index 47a3fea..5101df5 100644 --- a/camera-effects/pixelate.gdshader +++ b/camera-effects/pixelate.gdshader @@ -1,9 +1,14 @@ -shader_type spatial; +shader_type canvas_item; + uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear; uniform int pixel_size = 1; uniform float alpha = 0.1; +// inspired by https://www.youtube.com/watch?v=77F4ZjmQ07U + void fragment() { + vec2 VIEWPORT_SIZE = 1.0 / SCREEN_PIXEL_SIZE; + // a variant of nearest neighbour fragment shader_type float x = float(int(FRAGCOORD.x) % pixel_size); float y = float(int(FRAGCOORD.y) % pixel_size); @@ -12,6 +17,5 @@ void fragment() { y = FRAGCOORD.y + floor(float(pixel_size) / 2.0) - y; // set albedo value on the current coordinate based on vec2(x,y) / viewport_size - ALBEDO = texture(SCREEN_TEXTURE, vec2(x, y) / VIEWPORT_SIZE).xyz; - ALPHA = alpha; + COLOR = vec4(texture(SCREEN_TEXTURE, vec2(x, y) / VIEWPORT_SIZE).xyz, alpha); } diff --git a/camera-effects/pixelate.tscn b/camera-effects/pixelate.tscn new file mode 100644 index 0000000..2f32afe --- /dev/null +++ b/camera-effects/pixelate.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=3 format=3 uid="uid://djsrvtsqjesw8"] + +[ext_resource type="Shader" path="res://camera-effects/pixelate.gdshader" id="1_boqib"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_1p2bf"] +shader = ExtResource("1_boqib") +shader_parameter/pixel_size = 4 +shader_parameter/alpha = 1.0 + +[node name="Pixelate" type="ColorRect"] +material = SubResource("ShaderMaterial_1p2bf") +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 diff --git a/camera-effects/vignette.gdshader b/camera-effects/vignette.gdshader new file mode 100644 index 0000000..02bf1d4 --- /dev/null +++ b/camera-effects/vignette.gdshader @@ -0,0 +1,20 @@ +shader_type canvas_item; + +uniform vec4 color : source_color; +uniform float speed = 3.0; +uniform float pulse_strength = 0.1; +uniform float internal_radius = 0.4; +uniform float external_radius = 0.7; + +float smoothCircle(vec2 center, float positioner, vec2 uv) +{ + float d = distance(center, uv); + return smoothstep(internal_radius + positioner, external_radius + positioner, d); +} + +void fragment() { + vec2 CENTER = vec2(0.5, 0.5); + float position = sin(TIME * speed) * pulse_strength; + float circle = smoothCircle(CENTER, position, UV); + COLOR = vec4(color.rgb, circle); +} diff --git a/camera-effects/vignette.tscn b/camera-effects/vignette.tscn new file mode 100644 index 0000000..6b131e8 --- /dev/null +++ b/camera-effects/vignette.tscn @@ -0,0 +1,19 @@ +[gd_scene load_steps=3 format=3 uid="uid://ds5xw2us1br3q"] + +[ext_resource type="Shader" path="res://camera-effects/vignette.gdshader" id="1_pj8nl"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_p1c5j"] +shader = ExtResource("1_pj8nl") +shader_parameter/color = Color(0.411765, 0, 0, 1) +shader_parameter/speed = 3.0 +shader_parameter/pulse_strength = 0.1 +shader_parameter/internal_radius = 0.4 +shader_parameter/external_radius = 0.7 + +[node name="Vignette" type="ColorRect"] +material = SubResource("ShaderMaterial_p1c5j") +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 diff --git a/docs/images/camera-effects/chromatic-aberration.png b/docs/images/camera-effects/chromatic-aberration.png new file mode 100644 index 0000000..5652fc7 Binary files /dev/null and b/docs/images/camera-effects/chromatic-aberration.png differ diff --git a/docs/images/camera-effects/pixelate.png b/docs/images/camera-effects/pixelate.png index 7bb0371..e184445 100644 Binary files a/docs/images/camera-effects/pixelate.png and b/docs/images/camera-effects/pixelate.png differ diff --git a/docs/images/camera-effects/vignette.png b/docs/images/camera-effects/vignette.png index 8ac58dc..667b1c1 100644 Binary files a/docs/images/camera-effects/vignette.png and b/docs/images/camera-effects/vignette.png differ diff --git a/project.godot b/project.godot index 04f7589..6741742 100644 --- a/project.godot +++ b/project.godot @@ -15,11 +15,6 @@ run/main_scene="res://particle-effects.tscn" config/features=PackedStringArray("4.2", "Forward Plus") config/icon="res://icon.svg" -[display] - -window/size/viewport_width=2304 -window/size/viewport_height=1296 - [dotnet] project/assembly_name="godot-visual-effects" diff --git a/shaders/shapes.gdshaderinc b/shaders/shapes.gdshaderinc new file mode 100644 index 0000000..b97fe02 --- /dev/null +++ b/shaders/shapes.gdshaderinc @@ -0,0 +1,59 @@ +/** + * Draws a filled circle + */ +float drawFullCircle(vec2 center, float radius, vec2 uv) +{ + return (distance(center, uv) <= radius) ? 1. : 0.; +} + +/** + * Draws a line circle + */ +float drawLineCircle(vec2 center, float radius, float stroke, vec2 uv) +{ + return drawFullCircle(center, radius, uv) + - drawFullCircle(center, radius - stroke, uv); +} + +/** + * Draws a line from p1 to p2 + * + * @param p1 vec2 + * @param p2 vec2 + * @param stroke float + * @param uv float to receive uv from fragment function + * @param one_px float This param should receive SCREEN_PIXEL_SIZE.x, as SCREEN_PIXEL_SIZE + * cannot be accessed from outside fragment() function + */ +float drawLine(vec2 p1, vec2 p2, float stroke, vec2 uv, float one_px) +{ + float r = 0.; + + // get dist between points + float d = distance(p1, p2); + + // get dist between current pixel and p1 + float duv = distance(p1, uv); + + //if point is on line, according to dist, it should match current uv + r = 1.-floor(1.-(stroke * one_px)+distance (mix(p1, p2, clamp(duv/d, 0., 1.)), uv)); + + return r; +} + +/** + * Draws a triangle + */ +float drawTriangle(vec2 p1, vec2 p2, vec2 p3, float stroke, vec2 uv, float one_px) { + return drawLine(p1, p2, stroke, uv, one_px) + + drawLine(p2, p3, stroke, uv, one_px) + + drawLine(p3, p1, stroke, uv, one_px); +} + +/** + * Draws a triangle with no baseline + */ +float drawArrowTriangle(vec2 p1, vec2 p2, vec2 p3, float stroke, vec2 uv, float one_px) { + return drawLine(p1, p2, stroke, uv, one_px) + + drawLine(p3, p1, stroke, uv, one_px); +} diff --git a/shaders/trigonometry.gdshaderinc b/shaders/trigonometry.gdshaderinc new file mode 100644 index 0000000..d239b88 --- /dev/null +++ b/shaders/trigonometry.gdshaderinc @@ -0,0 +1,53 @@ +const vec2 CENTER = vec2(.5, .5); + +/** + * Rotate a shape + */ +vec2 rotate(vec2 origin, vec2 destination, float angleInDegrees) { + float angle_radians = radians(angleInDegrees); + float cosTheta = cos(angle_radians); + float sinTheta = sin(angle_radians); + + // Translate the destination to be relative to the origin + vec2 translatedDestination = destination - origin; + + // Apply the rotation transformation + vec2 rotatedDestination; + rotatedDestination.x = cosTheta * translatedDestination.x - sinTheta * translatedDestination.y; + rotatedDestination.y = sinTheta * translatedDestination.x + cosTheta * translatedDestination.y; + + // Translate the rotated destination back to its original position + rotatedDestination += origin; + + return rotatedDestination; +} + +/** + * atan2 as defined in other languages + */ +float atan2(float y, float x) { + if (x > 0.0) { + return atan(y / x); + } else if (x < 0.0) { + if (y >= 0.0) { + return atan(y / x) + PI; + } else { + return atan(y / x) - PI; + } + } else { + if (y > 0.0) { + return PI / 2.; + } else if (y < 0.0) { + return -PI / 2.; + } else { + return 0.0; + } + } +} + +/** + * Angle in degrees between 2 coords + */ +float getAngleInDegrees(vec2 v1, vec2 v2) { + return atan2(v1.y - v2.y, v1.x - v2.x) * (180. / PI); +}