55 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
66 */
77
8+ use core:: cmp:: Ordering ;
89use godot_ffi as sys;
910use sys:: { ffi_methods, GodotFfi } ;
1011
1112use crate :: builtin:: math:: { FloatExt , GlamConv , GlamType } ;
1213use crate :: builtin:: vectors:: Vector3Axis ;
13- use crate :: builtin:: { real, Basis , RVec3 , Vector3i } ;
14+ use crate :: builtin:: { inner , real, Basis , RVec3 , Vector2 , Vector3i } ;
1415
1516use std:: fmt;
1617
@@ -38,42 +39,39 @@ pub struct Vector3 {
3839 pub z : real ,
3940}
4041
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) ) ;
4443
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) ;
4747
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) ) ;
5053
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 ) ;
5357
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 ) ;
5660
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 ) ;
5963
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) ;
6266
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 ) ;
6569
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 ) ;
7572
7673 /// Constructs a new `Vector3` from a [`Vector3i`].
74+ #[ inline]
7775 pub const fn from_vector3i ( v : Vector3i ) -> Self {
7876 Self {
7977 x : v. x as real ,
@@ -82,126 +80,89 @@ impl Vector3 {
8280 }
8381 }
8482
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 )
10987 }
11088
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]
11196 pub fn cross ( self , with : Self ) -> Self {
11297 Self :: from_glam ( self . to_glam ( ) . cross ( with. to_glam ( ) ) )
11398 }
11499
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 ( ) ) ;
134105
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 } ;
138109
139- pub fn is_finite ( self ) -> bool {
140- self . to_glam ( ) . is_finite ( )
110+ n. normalized ( )
141111 }
142112
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( ) ) ;
146124
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 ( ) ;
150127
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 )
164130 } 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 } ) ;
168133
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+ } ;
182136
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 ;
192139
193- pub fn project ( self , b : Self ) -> Self {
194- Self :: from_glam ( self . to_glam ( ) . project_onto ( b. to_glam ( ) ) )
140+ o
195141 }
196142
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)
199151 }
200152
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
203161 }
204162
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]
205166 pub fn signed_angle_to ( self , to : Self , axis : Self ) -> real {
206167 let cross_to = self . cross ( to) ;
207168 let unsigned_angle = cross_to. length ( ) . atan2 ( self . dot ( to) ) ;
@@ -221,6 +182,7 @@ impl Vector3 {
221182 /// Length is also interpolated in the case that the input vectors have different lengths. If both
222183 /// input vectors have zero length or are collinear to each other, the method instead behaves like
223184 /// [`Vector3::lerp`].
185+ #[ inline]
224186 pub fn slerp ( self , to : Self , weight : real ) -> Self {
225187 let start_length_sq: real = self . length_squared ( ) ;
226188 let end_length_sq = to. length_squared ( ) ;
@@ -245,23 +207,6 @@ impl Vector3 {
245207 let angle = self . angle_to ( to) ;
246208 self . rotated ( unit_axis, angle * weight) * ( result_length / start_length)
247209 }
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- }
265210}
266211
267212/// Formats the vector like Godot: `(x, y, z)`.
@@ -271,12 +216,6 @@ impl fmt::Display for Vector3 {
271216 }
272217}
273218
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-
280219// SAFETY:
281220// This type is represented as `Self` in Godot, so `*mut Self` is sound.
282221unsafe impl GodotFfi for Vector3 {
0 commit comments