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
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.
Except for that, the particles and code in this repository are available under MIT license for free usage.

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://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")]

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

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/icon="res://icon.svg"
[display]
window/size/viewport_width=2304
window/size/viewport_height=1296
[dotnet]
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);
}