1
- use super :: { Basis , IsEqualApprox , Vector3 } ;
1
+ use super :: { Basis , IsEqualApprox , Vector3 , CMP_EPSILON } ;
2
2
use glam:: EulerRot ;
3
- use std:: ops:: Mul ;
3
+ use std:: ops:: { Mul , Neg } ;
4
4
5
5
#[ derive( Copy , Clone , Debug , PartialEq ) ]
6
6
#[ repr( C ) ]
@@ -119,7 +119,38 @@ impl Quat {
119
119
pub fn slerp ( self , b : Self , t : f32 ) -> Self {
120
120
debug_assert ! ( self . is_normalized( ) , "Quaternion `self` is not normalized" ) ;
121
121
debug_assert ! ( b. is_normalized( ) , "Quaternion `b` is not normalized" ) ;
122
- Self :: gd ( self . glam ( ) . lerp ( b. glam ( ) , t) )
122
+
123
+ // Copied from Godot's Quat::slerp as glam::lerp version diverges too much
124
+
125
+ // calc cosine
126
+ let cosom = self . dot ( b) ;
127
+
128
+ // adjust signs (if necessary)
129
+ let ( cosom, b) = if cosom < 0.0 {
130
+ ( -cosom, -b)
131
+ } else {
132
+ ( cosom, b)
133
+ } ;
134
+
135
+ // calculate coefficients
136
+ let scale = if ( 1.0 - cosom) > CMP_EPSILON as f32 {
137
+ // standard case (slerp)
138
+ let omega = cosom. acos ( ) ;
139
+ let sinom = omega. sin ( ) ;
140
+ ( ( ( 1.0 - t) * omega) . sin ( ) / sinom, ( t * omega) . sin ( ) / sinom)
141
+ } else {
142
+ // "from" and "to" quaternions are very close
143
+ // ... so we can do a linear interpolation
144
+ ( 1.0 - t, t)
145
+ } ;
146
+
147
+ // calculate final values
148
+ Self :: new (
149
+ scale. 0 * self . x + scale. 1 * b. x ,
150
+ scale. 0 * self . y + scale. 1 * b. y ,
151
+ scale. 0 * self . z + scale. 1 * b. z ,
152
+ scale. 0 * self . w + scale. 1 * b. w ,
153
+ )
123
154
}
124
155
125
156
/// Returns the result of the spherical linear interpolation between this quaternion and `t` by
@@ -128,6 +159,9 @@ impl Quat {
128
159
pub fn slerpni ( self , b : Self , t : f32 ) -> Self {
129
160
debug_assert ! ( self . is_normalized( ) , "Quaternion `self` is not normalized" ) ;
130
161
debug_assert ! ( b. is_normalized( ) , "Quaternion `b` is not normalized" ) ;
162
+
163
+ // Copied from Godot's Quat::slerpni as glam::slerp version diverges too much
164
+
131
165
let dot = self . dot ( b) ;
132
166
if dot. abs ( ) > 0.9999 {
133
167
self
@@ -172,6 +206,15 @@ impl Mul<Vector3> for Quat {
172
206
}
173
207
}
174
208
209
+ impl Neg for Quat {
210
+ type Output = Quat ;
211
+
212
+ #[ inline]
213
+ fn neg ( self ) -> Self {
214
+ Self :: gd ( -self . glam ( ) )
215
+ }
216
+ }
217
+
175
218
#[ cfg( test) ]
176
219
mod test {
177
220
use super :: * ;
0 commit comments