mirror of
https://github.com/marinho/godot-visual-effects.git
synced 2024-12-22 14:37:27 +08:00
Camera effects in CanvasLayer (+Cromatic Aberration)
This commit is contained in:
parent
0fc19ef815
commit
1668629916
@ -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,9 +40,13 @@ 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
|
||||||
* Kenney Prototype Tools is copyrighted by Kenney, and can be found at https://github.com/GeroVeni/kenney_prototype_tools
|
* 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.
|
||||||
|
@ -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")]
|
||||||
|
@ -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")
|
|
@ -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")
|
|
15
camera-effects/chromatic-aberration.gdshader
Normal file
15
camera-effects/chromatic-aberration.gdshader
Normal 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);
|
||||||
|
}
|
15
camera-effects/chromatic_aberration.tscn
Normal file
15
camera-effects/chromatic_aberration.tscn
Normal 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
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
16
camera-effects/pixelate.tscn
Normal file
16
camera-effects/pixelate.tscn
Normal 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
|
20
camera-effects/vignette.gdshader
Normal file
20
camera-effects/vignette.gdshader
Normal 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);
|
||||||
|
}
|
19
camera-effects/vignette.tscn
Normal file
19
camera-effects/vignette.tscn
Normal 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
|
BIN
docs/images/camera-effects/chromatic-aberration.png
Normal file
BIN
docs/images/camera-effects/chromatic-aberration.png
Normal file
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 |
@ -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"
|
||||||
|
59
shaders/shapes.gdshaderinc
Normal file
59
shaders/shapes.gdshaderinc
Normal 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);
|
||||||
|
}
|
53
shaders/trigonometry.gdshaderinc
Normal file
53
shaders/trigonometry.gdshaderinc
Normal 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);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user