Camera effects in CanvasLayer (+Cromatic Aberration)

This commit is contained in:
Mario Brandao 2023-12-13 22:48:27 +01:00
parent 0fc19ef815
commit 1668629916
16 changed files with 224 additions and 90 deletions

View File

@ -30,7 +30,7 @@
## Camera Effects ## 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 ### Pixelate
@ -40,6 +40,10 @@ These effects are mostly to be placed as a child of Camera object
![Vignette](./docs/images/camera-effects/vignette.png) ![Vignette](./docs/images/camera-effects/vignette.png)
### Chromatic Aberration
![Chromatic Aberration](./docs/images/camera-effects/chromatic-aberration.png)
## License ## License
* Kenney Particle Pack is copyrighted by Kenney, and can be found at https://kenney.nl/assets/particle-pack * Kenney Particle Pack is copyrighted by Kenney, and can be found at https://kenney.nl/assets/particle-pack

View File

@ -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://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://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://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://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://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://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"] [sub_resource type="Environment" id="Environment_tln01"]
glow_blend_mode = 4 glow_blend_mode = 4
@ -29,10 +30,6 @@ current = true
fov = 13.5 fov = 13.5
size = 13.34 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="."] [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 0.5, 0.866025, 0, -0.866025, 0.5, 0, 2, 0) transform = Transform3D(1, 0, 0, 0, 0.5, 0.866025, 0, -0.866025, 0.5, 0, 2, 0)
light_energy = 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")] [node name="Cube36" parent="Scene" instance=ExtResource("6_y7myb")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5, 0, -8) 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")]

View File

@ -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")

View File

@ -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")

View File

@ -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);
}

View File

@ -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

View File

@ -1,9 +1,14 @@
shader_type spatial; shader_type canvas_item;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear; uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear;
uniform int pixel_size = 1; uniform int pixel_size = 1;
uniform float alpha = 0.1; uniform float alpha = 0.1;
// inspired by https://www.youtube.com/watch?v=77F4ZjmQ07U
void fragment() { void fragment() {
vec2 VIEWPORT_SIZE = 1.0 / SCREEN_PIXEL_SIZE;
// a variant of nearest neighbour fragment shader_type // a variant of nearest neighbour fragment shader_type
float x = float(int(FRAGCOORD.x) % pixel_size); float x = float(int(FRAGCOORD.x) % pixel_size);
float y = float(int(FRAGCOORD.y) % 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; y = FRAGCOORD.y + floor(float(pixel_size) / 2.0) - y;
// set albedo value on the current coordinate based on vec2(x,y) / viewport_size // set albedo value on the current coordinate based on vec2(x,y) / viewport_size
ALBEDO = texture(SCREEN_TEXTURE, vec2(x, y) / VIEWPORT_SIZE).xyz; COLOR = vec4(texture(SCREEN_TEXTURE, vec2(x, y) / VIEWPORT_SIZE).xyz, alpha);
ALPHA = alpha;
} }

View File

@ -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

View File

@ -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);
}

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 252 KiB

After

Width:  |  Height:  |  Size: 182 KiB

View File

@ -15,11 +15,6 @@ run/main_scene="res://particle-effects.tscn"
config/features=PackedStringArray("4.2", "Forward Plus") config/features=PackedStringArray("4.2", "Forward Plus")
config/icon="res://icon.svg" config/icon="res://icon.svg"
[display]
window/size/viewport_width=2304
window/size/viewport_height=1296
[dotnet] [dotnet]
project/assembly_name="godot-visual-effects" project/assembly_name="godot-visual-effects"

View File

@ -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);
}

View File

@ -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);
}