5
5
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
6
*/
7
7
8
+ use core:: cmp:: Ordering ;
8
9
use godot_ffi as sys;
9
10
use sys:: { ffi_methods, GodotFfi } ;
10
11
11
12
use crate :: builtin:: math:: { FloatExt , GlamConv , GlamType } ;
12
13
use crate :: builtin:: vectors:: Vector3Axis ;
13
- use crate :: builtin:: { real, Basis , RVec3 , Vector3i } ;
14
+ use crate :: builtin:: { inner , real, Basis , RVec3 , Vector2 , Vector3i } ;
14
15
15
16
use std:: fmt;
16
17
@@ -38,42 +39,39 @@ pub struct Vector3 {
38
39
pub z : real ,
39
40
}
40
41
41
- impl Vector3 {
42
- /// Vector with all components set to `0.0`.
43
- pub const ZERO : Self = Self :: splat ( 0.0 ) ;
42
+ impl_vector_operators ! ( Vector3 , real, ( x, y, z) ) ;
44
43
45
- /// Vector with all components set to `1.0`.
46
- pub const ONE : Self = Self :: splat ( 1.0 ) ;
44
+ impl_vector_consts ! ( Vector3 , real) ;
45
+ impl_float_vector_consts ! ( Vector3 ) ;
46
+ impl_vector3x_consts ! ( Vector3 , real) ;
47
47
48
- /// Unit vector in -X direction. Can be interpreted as left in an untransformed 3D world.
49
- pub const LEFT : Self = Self :: new ( -1.0 , 0.0 , 0.0 ) ;
48
+ impl_vector_fns ! ( Vector3 , RVec3 , real, ( x, y, z) ) ;
49
+ impl_float_vector_fns ! ( Vector3 , ( x, y, z) ) ;
50
+ impl_vector3x_fns ! ( Vector3 , real) ;
51
+ impl_vector2_vector3_fns ! ( Vector3 , ( x, y, z) ) ;
52
+ impl_vector3_vector4_fns ! ( Vector3 , ( x, y, z) ) ;
50
53
51
- /// Unit vector in +X direction. Can be interpreted as right in an untransformed 3D world.
52
- pub const RIGHT : Self = Self :: new ( 1.0 , 0.0 , 0.0 ) ;
54
+ impl Vector3 {
55
+ /// Unit vector pointing towards the left side of imported 3D assets.
56
+ pub const MODEL_LEFT : Self = Self :: new ( 1.0 , 0.0 , 0.0 ) ;
53
57
54
- /// Unit vector in +Y direction. Typically interpreted as up in a 3D world .
55
- pub const UP : Self = Self :: new ( 0 .0, 1 .0, 0.0 ) ;
58
+ /// Unit vector pointing towards the right side of imported 3D assets .
59
+ pub const MODEL_RIGHT : Self = Self :: new ( - 1 .0, 0 .0, 0.0 ) ;
56
60
57
- /// Unit vector in -Y direction. Typically interpreted as down in a 3D world .
58
- pub const DOWN : Self = Self :: new ( 0.0 , - 1.0 , 0.0 ) ;
61
+ /// Unit vector pointing towards the top side (up) of imported 3D assets .
62
+ pub const MODEL_UP : Self = Self :: new ( 0.0 , 1.0 , 0.0 ) ;
59
63
60
- /// Unit vector in -Z direction. Can be interpreted as "into the screen" in an untransformed 3D world .
61
- pub const FORWARD : Self = Self :: new ( 0.0 , 0 .0, - 1 .0) ;
64
+ /// Unit vector pointing towards the bottom side (down) of imported 3D assets .
65
+ pub const MODEL_BOTTOM : Self = Self :: new ( 0.0 , - 1 .0, 0 .0) ;
62
66
63
- /// Unit vector in +Z direction. Can be interpreted as "out of the screen" in an untransformed 3D world .
64
- pub const BACK : Self = Self :: new ( 0.0 , 0.0 , 1.0 ) ;
67
+ /// Unit vector pointing towards the front side (facing forward) of imported 3D assets .
68
+ pub const MODEL_FRONT : Self = Self :: new ( 0.0 , 0.0 , 1.0 ) ;
65
69
66
- /// Returns a `Vector3` with the given components.
67
- pub const fn new ( x : real , y : real , z : real ) -> Self {
68
- Self { x, y, z }
69
- }
70
-
71
- /// Returns a new `Vector3` with all components set to `v`.
72
- pub const fn splat ( v : real ) -> Self {
73
- Self :: new ( v, v, v)
74
- }
70
+ /// Unit vector pointing towards the rear side (back) of imported 3D assets.
71
+ pub const MODEL_REAR : Self = Self :: new ( 0.0 , 0.0 , -1.0 ) ;
75
72
76
73
/// Constructs a new `Vector3` from a [`Vector3i`].
74
+ #[ inline]
77
75
pub const fn from_vector3i ( v : Vector3i ) -> Self {
78
76
Self {
79
77
x : v. x as real ,
@@ -82,126 +80,89 @@ impl Vector3 {
82
80
}
83
81
}
84
82
85
- /// Converts the corresponding `glam` type to `Self`.
86
- fn from_glam ( v : RVec3 ) -> Self {
87
- Self :: new ( v. x , v. y , v. z )
88
- }
89
-
90
- /// Converts `self` to the corresponding `glam` type.
91
- fn to_glam ( self ) -> RVec3 {
92
- RVec3 :: new ( self . x , self . y , self . z )
93
- }
94
-
95
- pub fn angle_to ( self , to : Self ) -> real {
96
- self . to_glam ( ) . angle_between ( to. to_glam ( ) )
97
- }
98
-
99
- pub fn bounce ( self , normal : Self ) -> Self {
100
- -self . reflect ( normal)
101
- }
102
-
103
- pub fn ceil ( self ) -> Self {
104
- Self :: from_glam ( self . to_glam ( ) . ceil ( ) )
105
- }
106
-
107
- pub fn clamp ( self , min : Self , max : Self ) -> Self {
108
- Self :: from_glam ( self . to_glam ( ) . clamp ( min. to_glam ( ) , max. to_glam ( ) ) )
83
+ #[ doc( hidden) ]
84
+ #[ inline]
85
+ pub fn as_inner ( & self ) -> inner:: InnerVector3 {
86
+ inner:: InnerVector3 :: from_outer ( self )
109
87
}
110
88
89
+ /// Returns the cross product of this vector and `with`.
90
+ ///
91
+ /// This returns a vector perpendicular to both this and `with`, which would be the normal vector of the plane
92
+ /// defined by the two vectors. As there are two such vectors, in opposite directions,
93
+ /// this method returns the vector defined by a right-handed coordinate system.
94
+ /// If the two vectors are parallel this returns an empty vector, making it useful for testing if two vectors are parallel.
95
+ #[ inline]
111
96
pub fn cross ( self , with : Self ) -> Self {
112
97
Self :: from_glam ( self . to_glam ( ) . cross ( with. to_glam ( ) ) )
113
98
}
114
99
115
- pub fn direction_to ( self , to : Self ) -> Self {
116
- ( to - self ) . normalized ( )
117
- }
118
-
119
- pub fn distance_squared_to ( self , to : Self ) -> real {
120
- ( to - self ) . length_squared ( )
121
- }
122
-
123
- pub fn distance_to ( self , to : Self ) -> real {
124
- ( to - self ) . length ( )
125
- }
126
-
127
- pub fn dot ( self , with : Self ) -> real {
128
- self . to_glam ( ) . dot ( with. to_glam ( ) )
129
- }
130
-
131
- pub fn floor ( self ) -> Self {
132
- Self :: from_glam ( self . to_glam ( ) . floor ( ) )
133
- }
100
+ /// Returns the Vector3 from an octahedral-compressed form created using [`Vector3::octahedron_encode`] (stored as a [`Vector2`]).
101
+ #[ inline]
102
+ pub fn octahedron_decode ( uv : Vector2 ) -> Self {
103
+ let f = Vector2 :: new ( uv. x * 2.0 - 1.0 , uv. y * 2.0 - 1.0 ) ;
104
+ let mut n = Vector3 :: new ( f. x , f. y , 1.0 - f. x . abs ( ) - f. y . abs ( ) ) ;
134
105
135
- pub fn inverse ( self ) -> Self {
136
- Self :: new ( 1.0 / self . x , 1 .0 / self . y , 1.0 / self . z )
137
- }
106
+ let t = ( -n . z ) . clamp ( 0.0 , 1.0 ) ;
107
+ n . x += if n . x >= 0 .0 { -t } else { t } ;
108
+ n . y += if n . y >= 0.0 { -t } else { t } ;
138
109
139
- pub fn is_finite ( self ) -> bool {
140
- self . to_glam ( ) . is_finite ( )
110
+ n. normalized ( )
141
111
}
142
112
143
- pub fn is_normalized ( self ) -> bool {
144
- self . to_glam ( ) . is_normalized ( )
145
- }
113
+ /// Returns the octahedral-encoded (oct32) form of this Vector3 as a [`Vector2`]. Since a [`Vector2`] occupies 1/3 less memory compared to Vector3,
114
+ /// this form of compression can be used to pass greater amounts of [`Vector3::normalized`] Vector3s without increasing storage or memory requirements.
115
+ /// See also [`Vector3::octahedron_decode`].
116
+ ///
117
+ /// Note: Octahedral compression is lossy, although visual differences are rarely perceptible in real world scenarios.
118
+ ///
119
+ /// # Panics
120
+ /// If vector is not normalized.
121
+ #[ inline]
122
+ pub fn octahedron_encode ( self ) -> Vector2 {
123
+ assert ! ( self . is_normalized( ) ) ;
146
124
147
- pub fn length_squared ( self ) -> real {
148
- self . to_glam ( ) . length_squared ( )
149
- }
125
+ let mut n = self ;
126
+ n /= n. x . abs ( ) + n. y . abs ( ) + n. z . abs ( ) ;
150
127
151
- pub fn limit_length ( self , length : Option < real > ) -> Self {
152
- Self :: from_glam ( self . to_glam ( ) . clamp_length_max ( length. unwrap_or ( 1.0 ) ) )
153
- }
154
-
155
- pub fn max_axis_index ( self ) -> Vector3Axis {
156
- if self . x < self . y {
157
- if self . y < self . z {
158
- Vector3Axis :: Z
159
- } else {
160
- Vector3Axis :: Y
161
- }
162
- } else if self . x < self . z {
163
- Vector3Axis :: Z
128
+ let mut o = if n. z >= 0.0 {
129
+ Vector2 :: new ( n. x , n. y )
164
130
} else {
165
- Vector3Axis :: X
166
- }
167
- }
131
+ let x = ( 1.0 - n. y . abs ( ) ) * ( if n. x >= 0.0 { 1.0 } else { -1.0 } ) ;
132
+ let y = ( 1.0 - n. x . abs ( ) ) * ( if n. y >= 0.0 { 1.0 } else { -1.0 } ) ;
168
133
169
- pub fn min_axis_index ( self ) -> Vector3Axis {
170
- if self . x < self . y {
171
- if self . x < self . z {
172
- Vector3Axis :: X
173
- } else {
174
- Vector3Axis :: Z
175
- }
176
- } else if self . y < self . z {
177
- Vector3Axis :: Y
178
- } else {
179
- Vector3Axis :: Z
180
- }
181
- }
134
+ Vector2 :: new ( x, y)
135
+ } ;
182
136
183
- pub fn move_toward ( self , to : Self , delta : real ) -> Self {
184
- let vd = to - self ;
185
- let len = vd. length ( ) ;
186
- if len <= delta || len < real:: CMP_EPSILON {
187
- to
188
- } else {
189
- self + vd / len * delta
190
- }
191
- }
137
+ o. x = o. x * 0.5 + 0.5 ;
138
+ o. y = o. y * 0.5 + 0.5 ;
192
139
193
- pub fn project ( self , b : Self ) -> Self {
194
- Self :: from_glam ( self . to_glam ( ) . project_onto ( b. to_glam ( ) ) )
140
+ o
195
141
}
196
142
197
- pub fn reflect ( self , normal : Self ) -> Self {
198
- 2.0 * normal * self . dot ( normal) - self
143
+ /// Returns the outer product with `with`.
144
+ #[ inline]
145
+ pub fn outer ( self , with : Self ) -> Basis {
146
+ let x = Vector3 :: new ( self . x * with. x , self . x * with. y , self . x * with. z ) ;
147
+ let y = Vector3 :: new ( self . y * with. x , self . y * with. y , self . y * with. z ) ;
148
+ let z = Vector3 :: new ( self . z * with. x , self . z * with. y , self . z * with. z ) ;
149
+
150
+ Basis :: from_rows ( x, y, z)
199
151
}
200
152
201
- pub fn round ( self ) -> Self {
202
- Self :: from_glam ( self . to_glam ( ) . round ( ) )
153
+ /// Returns this vector rotated around `axis` by `angle` radians. `axis` must be normalized.
154
+ ///
155
+ /// # Panics
156
+ /// If `axis` is not normalized.
157
+ #[ inline]
158
+ pub fn rotated ( self , axis : Self , angle : real ) -> Self {
159
+ assert ! ( axis. is_normalized( ) ) ;
160
+ Basis :: from_axis_angle ( axis, angle) * self
203
161
}
204
162
163
+ /// Returns the signed angle to the given vector, in radians. The sign of the angle is positive in a counter-clockwise direction and
164
+ /// negative in a clockwise direction when viewed from the side specified by the `axis`.
165
+ #[ inline]
205
166
pub fn signed_angle_to ( self , to : Self , axis : Self ) -> real {
206
167
let cross_to = self . cross ( to) ;
207
168
let unsigned_angle = cross_to. length ( ) . atan2 ( self . dot ( to) ) ;
@@ -221,6 +182,7 @@ impl Vector3 {
221
182
/// Length is also interpolated in the case that the input vectors have different lengths. If both
222
183
/// input vectors have zero length or are collinear to each other, the method instead behaves like
223
184
/// [`Vector3::lerp`].
185
+ #[ inline]
224
186
pub fn slerp ( self , to : Self , weight : real ) -> Self {
225
187
let start_length_sq: real = self . length_squared ( ) ;
226
188
let end_length_sq = to. length_squared ( ) ;
@@ -245,23 +207,6 @@ impl Vector3 {
245
207
let angle = self . angle_to ( to) ;
246
208
self . rotated ( unit_axis, angle * weight) * ( result_length / start_length)
247
209
}
248
-
249
- pub fn slide ( self , normal : Self ) -> Self {
250
- self - normal * self . dot ( normal)
251
- }
252
-
253
- /// Returns this vector rotated around `axis` by `angle` radians. `axis` must be normalized.
254
- ///
255
- /// # Panics
256
- /// If `axis` is not normalized.
257
- pub fn rotated ( self , axis : Self , angle : real ) -> Self {
258
- assert ! ( axis. is_normalized( ) ) ;
259
- Basis :: from_axis_angle ( axis, angle) * self
260
- }
261
-
262
- pub fn coords ( & self ) -> ( real , real , real ) {
263
- ( self . x , self . y , self . z )
264
- }
265
210
}
266
211
267
212
/// Formats the vector like Godot: `(x, y, z)`.
@@ -271,12 +216,6 @@ impl fmt::Display for Vector3 {
271
216
}
272
217
}
273
218
274
- impl_common_vector_fns ! ( Vector3 , real) ;
275
- impl_float_vector_glam_fns ! ( Vector3 , real) ;
276
- impl_float_vector_component_fns ! ( Vector3 , real, ( x, y, z) ) ;
277
- impl_vector_operators ! ( Vector3 , real, ( x, y, z) ) ;
278
- impl_swizzle_trait_for_vector3x ! ( Vector3 , real) ;
279
-
280
219
// SAFETY:
281
220
// This type is represented as `Self` in Godot, so `*mut Self` is sound.
282
221
unsafe impl GodotFfi for Vector3 {
0 commit comments