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:: meta:: impl_godot_as_self;
1314use crate :: builtin:: vectors:: Vector3Axis ;
14- use crate :: builtin:: { real, Basis , RVec3 , Vector3i } ;
15+ use crate :: builtin:: { inner , real, Basis , RVec3 , Vector2 , Vector3i } ;
1516
1617use std:: fmt;
1718
@@ -39,42 +40,39 @@ pub struct Vector3 {
3940 pub z : real ,
4041}
4142
42- impl Vector3 {
43- /// Vector with all components set to `0.0`.
44- pub const ZERO : Self = Self :: splat ( 0.0 ) ;
43+ impl_vector_operators ! ( Vector3 , real, ( x, y, z) ) ;
4544
46- /// Vector with all components set to `1.0`.
47- pub const ONE : Self = Self :: splat ( 1.0 ) ;
45+ impl_vector_consts ! ( Vector3 , real) ;
46+ impl_float_vector_consts ! ( Vector3 ) ;
47+ impl_vector3x_consts ! ( Vector3 , real) ;
4848
49- /// Unit vector in -X direction. Can be interpreted as left in an untransformed 3D world.
50- pub const LEFT : Self = Self :: new ( -1.0 , 0.0 , 0.0 ) ;
49+ impl_vector_fns ! ( Vector3 , RVec3 , real, ( x, y, z) ) ;
50+ impl_float_vector_fns ! ( Vector3 , ( x, y, z) ) ;
51+ impl_vector3x_fns ! ( Vector3 , real) ;
52+ impl_vector2_vector3_fns ! ( Vector3 , ( x, y, z) ) ;
53+ impl_vector3_vector4_fns ! ( Vector3 , ( x, y, z) ) ;
5154
52- /// Unit vector in +X direction. Can be interpreted as right in an untransformed 3D world.
53- pub const RIGHT : Self = Self :: new ( 1.0 , 0.0 , 0.0 ) ;
55+ impl Vector3 {
56+ /// Unit vector pointing towards the left side of imported 3D assets.
57+ pub const MODEL_LEFT : Self = Self :: new ( 1.0 , 0.0 , 0.0 ) ;
5458
55- /// Unit vector in +Y direction. Typically interpreted as up in a 3D world .
56- pub const UP : Self = Self :: new ( 0 .0, 1 .0, 0.0 ) ;
59+ /// Unit vector pointing towards the right side of imported 3D assets .
60+ pub const MODEL_RIGHT : Self = Self :: new ( - 1 .0, 0 .0, 0.0 ) ;
5761
58- /// Unit vector in -Y direction. Typically interpreted as down in a 3D world .
59- pub const DOWN : Self = Self :: new ( 0.0 , - 1.0 , 0.0 ) ;
62+ /// Unit vector pointing towards the top side (up) of imported 3D assets .
63+ pub const MODEL_UP : Self = Self :: new ( 0.0 , 1.0 , 0.0 ) ;
6064
61- /// Unit vector in -Z direction. Can be interpreted as "into the screen" in an untransformed 3D world .
62- pub const FORWARD : Self = Self :: new ( 0.0 , 0 .0, - 1 .0) ;
65+ /// Unit vector pointing towards the bottom side (down) of imported 3D assets .
66+ pub const MODEL_BOTTOM : Self = Self :: new ( 0.0 , - 1 .0, 0 .0) ;
6367
64- /// Unit vector in +Z direction. Can be interpreted as "out of the screen" in an untransformed 3D world .
65- pub const BACK : Self = Self :: new ( 0.0 , 0.0 , 1.0 ) ;
68+ /// Unit vector pointing towards the front side (facing forward) of imported 3D assets .
69+ pub const MODEL_FRONT : Self = Self :: new ( 0.0 , 0.0 , 1.0 ) ;
6670
67- /// Returns a `Vector3` with the given components.
68- pub const fn new ( x : real , y : real , z : real ) -> Self {
69- Self { x, y, z }
70- }
71-
72- /// Returns a new `Vector3` with all components set to `v`.
73- pub const fn splat ( v : real ) -> Self {
74- Self :: new ( v, v, v)
75- }
71+ /// Unit vector pointing towards the rear side (back) of imported 3D assets.
72+ pub const MODEL_REAR : Self = Self :: new ( 0.0 , 0.0 , -1.0 ) ;
7673
7774 /// Constructs a new `Vector3` from a [`Vector3i`].
75+ #[ inline]
7876 pub const fn from_vector3i ( v : Vector3i ) -> Self {
7977 Self {
8078 x : v. x as real ,
@@ -83,126 +81,89 @@ impl Vector3 {
8381 }
8482 }
8583
86- /// Converts the corresponding `glam` type to `Self`.
87- fn from_glam ( v : RVec3 ) -> Self {
88- Self :: new ( v. x , v. y , v. z )
89- }
90-
91- /// Converts `self` to the corresponding `glam` type.
92- fn to_glam ( self ) -> RVec3 {
93- RVec3 :: new ( self . x , self . y , self . z )
94- }
95-
96- pub fn angle_to ( self , to : Self ) -> real {
97- self . to_glam ( ) . angle_between ( to. to_glam ( ) )
98- }
99-
100- pub fn bounce ( self , normal : Self ) -> Self {
101- -self . reflect ( normal)
102- }
103-
104- pub fn ceil ( self ) -> Self {
105- Self :: from_glam ( self . to_glam ( ) . ceil ( ) )
106- }
107-
108- pub fn clamp ( self , min : Self , max : Self ) -> Self {
109- Self :: from_glam ( self . to_glam ( ) . clamp ( min. to_glam ( ) , max. to_glam ( ) ) )
84+ #[ doc( hidden) ]
85+ #[ inline]
86+ pub fn as_inner ( & self ) -> inner:: InnerVector3 {
87+ inner:: InnerVector3 :: from_outer ( self )
11088 }
11189
90+ /// Returns the cross product of this vector and `with`.
91+ ///
92+ /// This returns a vector perpendicular to both this and `with`, which would be the normal vector of the plane
93+ /// defined by the two vectors. As there are two such vectors, in opposite directions,
94+ /// this method returns the vector defined by a right-handed coordinate system.
95+ /// If the two vectors are parallel this returns an empty vector, making it useful for testing if two vectors are parallel.
96+ #[ inline]
11297 pub fn cross ( self , with : Self ) -> Self {
11398 Self :: from_glam ( self . to_glam ( ) . cross ( with. to_glam ( ) ) )
11499 }
115100
116- pub fn direction_to ( self , to : Self ) -> Self {
117- ( to - self ) . normalized ( )
118- }
119-
120- pub fn distance_squared_to ( self , to : Self ) -> real {
121- ( to - self ) . length_squared ( )
122- }
123-
124- pub fn distance_to ( self , to : Self ) -> real {
125- ( to - self ) . length ( )
126- }
127-
128- pub fn dot ( self , with : Self ) -> real {
129- self . to_glam ( ) . dot ( with. to_glam ( ) )
130- }
131-
132- pub fn floor ( self ) -> Self {
133- Self :: from_glam ( self . to_glam ( ) . floor ( ) )
134- }
101+ /// Returns the Vector3 from an octahedral-compressed form created using [`Vector3::octahedron_encode`] (stored as a [`Vector2`]).
102+ #[ inline]
103+ pub fn octahedron_decode ( uv : Vector2 ) -> Self {
104+ let f = Vector2 :: new ( uv. x * 2.0 - 1.0 , uv. y * 2.0 - 1.0 ) ;
105+ let mut n = Vector3 :: new ( f. x , f. y , 1.0 - f. x . abs ( ) - f. y . abs ( ) ) ;
135106
136- pub fn inverse ( self ) -> Self {
137- Self :: new ( 1.0 / self . x , 1 .0 / self . y , 1.0 / self . z )
138- }
107+ let t = ( -n . z ) . clamp ( 0.0 , 1.0 ) ;
108+ n . x += if n . x >= 0 .0 { -t } else { t } ;
109+ n . y += if n . y >= 0.0 { -t } else { t } ;
139110
140- pub fn is_finite ( self ) -> bool {
141- self . to_glam ( ) . is_finite ( )
111+ n. normalized ( )
142112 }
143113
144- pub fn is_normalized ( self ) -> bool {
145- self . to_glam ( ) . is_normalized ( )
146- }
114+ /// Returns the octahedral-encoded (oct32) form of this Vector3 as a [`Vector2`]. Since a [`Vector2`] occupies 1/3 less memory compared to Vector3,
115+ /// this form of compression can be used to pass greater amounts of [`Vector3::normalized`] Vector3s without increasing storage or memory requirements.
116+ /// See also [`Vector3::octahedron_decode`].
117+ ///
118+ /// Note: Octahedral compression is lossy, although visual differences are rarely perceptible in real world scenarios.
119+ ///
120+ /// # Panics
121+ /// If vector is not normalized.
122+ #[ inline]
123+ pub fn octahedron_encode ( self ) -> Vector2 {
124+ assert ! ( self . is_normalized( ) ) ;
147125
148- pub fn length_squared ( self ) -> real {
149- self . to_glam ( ) . length_squared ( )
150- }
126+ let mut n = self ;
127+ n /= n. x . abs ( ) + n. y . abs ( ) + n. z . abs ( ) ;
151128
152- pub fn limit_length ( self , length : Option < real > ) -> Self {
153- Self :: from_glam ( self . to_glam ( ) . clamp_length_max ( length. unwrap_or ( 1.0 ) ) )
154- }
155-
156- pub fn max_axis_index ( self ) -> Vector3Axis {
157- if self . x < self . y {
158- if self . y < self . z {
159- Vector3Axis :: Z
160- } else {
161- Vector3Axis :: Y
162- }
163- } else if self . x < self . z {
164- Vector3Axis :: Z
129+ let mut o = if n. z >= 0.0 {
130+ Vector2 :: new ( n. x , n. y )
165131 } else {
166- Vector3Axis :: X
167- }
168- }
132+ let x = ( 1.0 - n. y . abs ( ) ) * ( if n. x >= 0.0 { 1.0 } else { -1.0 } ) ;
133+ let y = ( 1.0 - n. x . abs ( ) ) * ( if n. y >= 0.0 { 1.0 } else { -1.0 } ) ;
169134
170- pub fn min_axis_index ( self ) -> Vector3Axis {
171- if self . x < self . y {
172- if self . x < self . z {
173- Vector3Axis :: X
174- } else {
175- Vector3Axis :: Z
176- }
177- } else if self . y < self . z {
178- Vector3Axis :: Y
179- } else {
180- Vector3Axis :: Z
181- }
182- }
135+ Vector2 :: new ( x, y)
136+ } ;
183137
184- pub fn move_toward ( self , to : Self , delta : real ) -> Self {
185- let vd = to - self ;
186- let len = vd. length ( ) ;
187- if len <= delta || len < real:: CMP_EPSILON {
188- to
189- } else {
190- self + vd / len * delta
191- }
192- }
138+ o. x = o. x * 0.5 + 0.5 ;
139+ o. y = o. y * 0.5 + 0.5 ;
193140
194- pub fn project ( self , b : Self ) -> Self {
195- Self :: from_glam ( self . to_glam ( ) . project_onto ( b. to_glam ( ) ) )
141+ o
196142 }
197143
198- pub fn reflect ( self , normal : Self ) -> Self {
199- 2.0 * normal * self . dot ( normal) - self
144+ /// Returns the outer product with `with`.
145+ #[ inline]
146+ pub fn outer ( self , with : Self ) -> Basis {
147+ let x = Vector3 :: new ( self . x * with. x , self . x * with. y , self . x * with. z ) ;
148+ let y = Vector3 :: new ( self . y * with. x , self . y * with. y , self . y * with. z ) ;
149+ let z = Vector3 :: new ( self . z * with. x , self . z * with. y , self . z * with. z ) ;
150+
151+ Basis :: from_rows ( x, y, z)
200152 }
201153
202- pub fn round ( self ) -> Self {
203- Self :: from_glam ( self . to_glam ( ) . round ( ) )
154+ /// Returns this vector rotated around `axis` by `angle` radians. `axis` must be normalized.
155+ ///
156+ /// # Panics
157+ /// If `axis` is not normalized.
158+ #[ inline]
159+ pub fn rotated ( self , axis : Self , angle : real ) -> Self {
160+ assert ! ( axis. is_normalized( ) ) ;
161+ Basis :: from_axis_angle ( axis, angle) * self
204162 }
205163
164+ /// Returns the signed angle to the given vector, in radians. The sign of the angle is positive in a counter-clockwise direction and
165+ /// negative in a clockwise direction when viewed from the side specified by the `axis`.
166+ #[ inline]
206167 pub fn signed_angle_to ( self , to : Self , axis : Self ) -> real {
207168 let cross_to = self . cross ( to) ;
208169 let unsigned_angle = cross_to. length ( ) . atan2 ( self . dot ( to) ) ;
@@ -222,6 +183,7 @@ impl Vector3 {
222183 /// Length is also interpolated in the case that the input vectors have different lengths. If both
223184 /// input vectors have zero length or are collinear to each other, the method instead behaves like
224185 /// [`Vector3::lerp`].
186+ #[ inline]
225187 pub fn slerp ( self , to : Self , weight : real ) -> Self {
226188 let start_length_sq: real = self . length_squared ( ) ;
227189 let end_length_sq = to. length_squared ( ) ;
@@ -246,23 +208,6 @@ impl Vector3 {
246208 let angle = self . angle_to ( to) ;
247209 self . rotated ( unit_axis, angle * weight) * ( result_length / start_length)
248210 }
249-
250- pub fn slide ( self , normal : Self ) -> Self {
251- self - normal * self . dot ( normal)
252- }
253-
254- /// Returns this vector rotated around `axis` by `angle` radians. `axis` must be normalized.
255- ///
256- /// # Panics
257- /// If `axis` is not normalized.
258- pub fn rotated ( self , axis : Self , angle : real ) -> Self {
259- assert ! ( axis. is_normalized( ) ) ;
260- Basis :: from_axis_angle ( axis, angle) * self
261- }
262-
263- pub fn coords ( & self ) -> ( real , real , real ) {
264- ( self . x , self . y , self . z )
265- }
266211}
267212
268213/// Formats the vector like Godot: `(x, y, z)`.
@@ -272,12 +217,6 @@ impl fmt::Display for Vector3 {
272217 }
273218}
274219
275- impl_common_vector_fns ! ( Vector3 , real) ;
276- impl_float_vector_glam_fns ! ( Vector3 , real) ;
277- impl_float_vector_component_fns ! ( Vector3 , real, ( x, y, z) ) ;
278- impl_vector_operators ! ( Vector3 , real, ( x, y, z) ) ;
279- impl_swizzle_trait_for_vector3x ! ( Vector3 , real) ;
280-
281220// SAFETY:
282221// This type is represented as `Self` in Godot, so `*mut Self` is sound.
283222unsafe impl GodotFfi for Vector3 {
0 commit comments