Ark Server API (ASE) - Wiki
Loading...
Searching...
No Matches
Quat.h
Go to the documentation of this file.
1// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "../BasicTypes.h"
7#include "Vector.h"
8#include "Rotator.h"
9
10/**
11 * Floating point quaternion that can represent a rotation about an axis in 3-D space.
12 * The X, Y, Z, W components also double as the Axis/Angle format.
13 *
14 * Order matters when composing quaternions: C = A * B will yield a quaternion C that logically
15 * first applies B then A to any subsequent transformation (right first, then left).
16 * Note that this is the opposite order of FTransform multiplication.
17 *
18 * Example: LocalToWorld = (LocalToWorld * DeltaRotation) will change rotation in local space by DeltaRotation.
19 * Example: LocalToWorld = (DeltaRotation * LocalToWorld) will change rotation in world space by DeltaRotation.
20 */
21MS_ALIGN(16) struct FQuat
22{
23public:
24
25 /** The quaternion's X-component. */
26 float X;
27
28 /** The quaternion's Y-component. */
29 float Y;
30
31 /** The quaternion's Z-component. */
32 float Z;
33
34 /** The quaternion's W-component. */
35 float W;
36
37public:
38
39 /** Identity quaternion. */
40 static const FQuat Identity;
41
42public:
43
44 /** Default constructor (no initialization). */
45 FORCEINLINE FQuat() { }
46
47 /**
48 * Creates and initializes a new quaternion, with the W component either 0 or 1.
49 *
50 * @param EForceInit Force init enum: if equal to ForceInitToZero then W is 0, otherwise W = 1 (creating an identity transform)
51 */
52 explicit FORCEINLINE FQuat(EForceInit);
53
54 /**
55 * Constructor.
56 *
57 * @param InX X component of the quaternion
58 * @param InY Y component of the quaternion
59 * @param InZ Z component of the quaternion
60 * @param InW W component of the quaternion
61 */
62 FORCEINLINE FQuat(float InX, float InY, float InZ, float InW);
63
64 /**
65 * Copy constructor.
66 *
67 * @param Q A FQuat object to use to create new quaternion from.
68 */
69 FORCEINLINE FQuat(const FQuat& Q);
70
71 /**
72 * Creates and initializes a new quaternion from the given rotator.
73 *
74 * @param R The rotator to initialize from.
75 */
76 explicit FQuat(const FRotator& R);
77
78 /**
79 * Creates and initializes a new quaternion from the a rotation around the given axis.
80 *
81 * @param Axis assumed to be a normalized vector
82 * @param Angle angle to rotate above the given axis (in radians)
83 */
84 FQuat(FVector Axis, float AngleRad);
85
86public:
87
88#ifdef IMPLEMENT_ASSIGNMENT_OPERATOR_MANUALLY
89 /**
90 * Copy another FQuat into this one
91 *
92 * @return reference to this FQuat
93 */
94 FORCEINLINE FQuat& operator=(const FQuat& Other);
95#endif
96
97 /**
98 * Gets the result of adding a Quaternion to this.
99 * This is a component-wise addition; composing quaternions should be done via multiplication.
100 *
101 * @param Q The Quaternion to add.
102 * @return The result of addition.
103 */
104 FORCEINLINE FQuat operator+(const FQuat& Q) const;
105
106 /**
107 * Adds to this quaternion.
108 * This is a component-wise addition; composing quaternions should be done via multiplication.
109 *
110 * @param Other The quaternion to add to this.
111 * @return Result after addition.
112 */
113 FORCEINLINE FQuat operator+=(const FQuat& Q);
114
115 /**
116 * Gets the result of subtracting a Quaternion to this.
117 * This is a component-wise subtraction; composing quaternions should be done via multiplication.
118 *
119 * @param Q The Quaternion to subtract.
120 * @return The result of subtraction.
121 */
122 FORCEINLINE FQuat operator-(const FQuat& Q) const;
123
124 /**
125 * Checks whether another Quaternion is equal to this, within specified tolerance.
126 *
127 * @param Q The other Quaternion.
128 * @param Tolerance Error tolerance for comparison with other Quaternion.
129 * @return true if two Quaternions are equal, within specified tolerance, otherwise false.
130 */
131 FORCEINLINE bool Equals(const FQuat& Q, float Tolerance=KINDA_SMALL_NUMBER) const;
132
133 /**
134 * Checks whether this Quaternion is an Identity Quaternion.
135 * Assumes Quaternion tested is normalized.
136 *
137 * @param Tolerance Error tolerance for comparison with Identity Quaternion.
138 * @return true if Quaternion is a normalized Identity Quaternion.
139 */
140 FORCEINLINE bool IsIdentity(float Tolerance=SMALL_NUMBER) const;
141
142 /**
143 * Subtracts another quaternion from this.
144 * This is a component-wise subtraction; composing quaternions should be done via multiplication.
145 *
146 * @param Q The other quaternion.
147 * @return reference to this after subtraction.
148 */
149 FORCEINLINE FQuat operator-=(const FQuat& Q);
150
151 /**
152 * Rotate a vector by this quaternion.
153 *
154 * @param V the vector to be rotated
155 * @return vector after rotation
156 * @see RotateVector
157 */
158 FVector operator*(const FVector& V) const;
159
160 /**
161 * Multiply this quaternion by a scaling factor.
162 *
163 * @param Scale The scaling factor.
164 * @return a reference to this after scaling.
165 */
166 FORCEINLINE FQuat operator*=(const float Scale);
167
168 /**
169 * Get the result of scaling this quaternion.
170 *
171 * @param Scale The scaling factor.
172 * @return The result of scaling.
173 */
174 FORCEINLINE FQuat operator*(const float Scale) const;
175
176 /**
177 * Divide this quaternion by scale.
178 *
179 * @param Scale What to divide by.
180 * @return a reference to this after scaling.
181 */
182 FORCEINLINE FQuat operator/=(const float Scale);
183
184 /**
185 * Divide this quaternion by scale.
186 *
187 * @param Scale What to divide by.
188 * @return new Quaternion of this after division by scale.
189 */
190 FORCEINLINE FQuat operator/(const float Scale) const;
191
192 /**
193 * Checks whether two quaternions are identical.
194 * This is an exact comparison per-component;see Equals() for a comparison
195 * that allows for a small error tolerance and flipped axes of rotation.
196 *
197 * @param Q The other quaternion.
198 * @return true if two quaternion are identical, otherwise false.
199 * @see Equals
200 */
201 bool operator==(const FQuat& Q) const;
202
203 /**
204 * Checks whether two quaternions are not identical.
205 *
206 * @param Q The other quaternion.
207 * @return true if two quaternion are not identical, otherwise false.
208 */
209 bool operator!=(const FQuat& Q) const;
210
211 /**
212 * Calculates dot product of two quaternions.
213 *
214 * @param Q The other quaternions.
215 * @return The dot product.
216 */
217 float operator|(const FQuat& Q) const;
218
219public:
220
221 /**
222 * Convert a vector of floating-point Euler angles (in degrees) into a Quaternion.
223 *
224 * @param Euler the Euler angles
225 * @return constructed FQuat
226 */
227 static FQuat MakeFromEuler(const FVector& Euler);
228
229 /** Convert a Quaternion into floating-point Euler angles (in degrees). */
230 FVector Euler() const;
231
232 /**
233 * Normalize this quaternion if it is large enough.
234 * If it is too small, returns an identity quaternion.
235 *
236 * @param Tolerance Minimum squared length of quaternion for normalization.
237 */
238 FORCEINLINE void Normalize(float Tolerance = SMALL_NUMBER);
239
240 /**
241 * Get a normalized copy of this quaternion.
242 * If it is too small, returns an identity quaternion.
243 *
244 * @param Tolerance Minimum squared length of quaternion for normalization.
245 */
246 FORCEINLINE FQuat GetNormalized(float Tolerance = SMALL_NUMBER) const;
247
248 // Return true if this quaternion is normalized
249 bool IsNormalized() const;
250
251 /**
252 * Get the length of this quaternion.
253 *
254 * @return The length of this quaternion.
255 */
256 FORCEINLINE float Size() const;
257
258 /**
259 * Get the length squared of this quaternion.
260 *
261 * @return The length of this quaternion.
262 */
263 FORCEINLINE float SizeSquared() const;
264
265
266 /** Get the angle of this quaternion */
267 FORCEINLINE float GetAngle() const;
268
269 /**
270 * get the axis and angle of rotation of this quaternion
271 *
272 * @param Axis{out] vector of axis of the quaternion
273 * @param Angle{out] angle of the quaternion
274 * @warning : assumes normalized quaternions.
275 */
276 void ToAxisAndAngle(FVector& Axis, float& Angle) const;
277
278 /**
279 * Get the swing and twist decomposition for a specified axis
280 *
281 * @param InTwistAxis Axis to use for decomposition
282 * @param OutSwing swing component quaternion
283 * @param OutTwist Twist component quaternion
284 * @warning assumes normalised quaternion and twist axis
285 */
286 void ToSwingTwist(const FVector& InTwistAxis, FQuat& OutSwing, FQuat& OutTwist) const;
287
288 /**
289 * Rotate a vector by this quaternion.
290 *
291 * @param V the vector to be rotated
292 * @return vector after rotation
293 */
294 FVector RotateVector(FVector V) const;
295
296 /**
297 * Rotate a vector by the inverse of this quaternion.
298 *
299 * @param V the vector to be rotated
300 * @return vector after rotation by the inverse of this quaternion.
301 */
302 FVector UnrotateVector(FVector V) const;
303
304 /**
305 * @return quaternion with W=0 and V=theta*v.
306 */
307 FQuat Log() const;
308
309 /**
310 * @note Exp should really only be used after Log.
311 * Assumes a quaternion with W=0 and V=theta*v (where |v| = 1).
312 * Exp(q) = (sin(theta)*v, cos(theta))
313 */
314 FQuat Exp() const;
315
316 /**
317 * @return inverse of this quaternion
318 */
319 FORCEINLINE FQuat Inverse() const;
320
321 /**
322 * Enforce that the delta between this Quaternion and another one represents
323 * the shortest possible rotation angle
324 */
325 void EnforceShortestArcWith(const FQuat& OtherQuat);
326
327 /** Get the forward direction (X axis) after it has been rotated by this Quaternion. */
328 FORCEINLINE FVector GetAxisX() const;
329
330 /** Get the right direction (Y axis) after it has been rotated by this Quaternion. */
331 FORCEINLINE FVector GetAxisY() const;
332
333 /** Get the up direction (Z axis) after it has been rotated by this Quaternion. */
334 FORCEINLINE FVector GetAxisZ() const;
335
336 /** Get the forward direction (X axis) after it has been rotated by this Quaternion. */
337 FORCEINLINE FVector GetForwardVector() const;
338
339 /** Get the right direction (Y axis) after it has been rotated by this Quaternion. */
340 FORCEINLINE FVector GetRightVector() const;
341
342 /** Get the up direction (Z axis) after it has been rotated by this Quaternion. */
343 FORCEINLINE FVector GetUpVector() const;
344
345 /** Convert a rotation into a unit vector facing in its direction. Equivalent to GetForwardVector(). */
346 FORCEINLINE FVector Vector() const;
347
348 /** Get the FRotator representation of this Quaternion. */
349 FRotator Rotator() const;
350
351 /**
352 * Get the axis of rotation of the Quaternion.
353 * This is the axis around which rotation occurs to transform the canonical coordinate system to the target orientation.
354 * For the identity Quaternion which has no such rotation, FVector(1,0,0) is returned.
355 */
356 FORCEINLINE FVector GetRotationAxis() const;
357
358 /** Find the angular distance between two rotation quaternions (in radians) */
359 FORCEINLINE float AngularDistance(const FQuat& Q) const;
360
361 /**
362 * Utility to check if there are any non-finite values (NaN or Inf) in this Quat.
363 *
364 * @return true if there are any non-finite values in this Quaternion, otherwise false.
365 */
366 bool ContainsNaN() const;
367
368 /**
369 * Get a textual representation of the vector.
370 *
371 * @return Text describing the vector.
372 */
373 FString ToString() const;
374
375 /**
376 * Initialize this FQuat from a FString.
377 * The string is expected to contain X=, Y=, Z=, W=, otherwise
378 * this FQuat will have indeterminate (invalid) values.
379 *
380 * @param InSourceString FString containing the quaternion values.
381 * @return true if the FQuat was initialized; false otherwise.
382 */
383 bool InitFromString(const FString& InSourceString);
384
385public:
386
388 FORCEINLINE void DiagnosticCheckNaN() const
389 {
390 if (ContainsNaN())
391 {
392 logOrEnsureNanError(TEXT("FQuat contains NaN: %s"), *ToString());
393 *const_cast<FQuat*>(this) = FQuat::Identity;
394 }
395 }
396
397 FORCEINLINE void DiagnosticCheckNaN(const TCHAR* Message) const
398 {
399 if (ContainsNaN())
400 {
401 logOrEnsureNanError(TEXT("%s: FQuat contains NaN: %s"), Message, *ToString());
402 *const_cast<FQuat*>(this) = FQuat::Identity;
403 }
404 }
405#else
406 FORCEINLINE void DiagnosticCheckNaN() const {}
407 FORCEINLINE void DiagnosticCheckNaN(const TCHAR* Message) const {}
408#endif
409
410public:
411
412 /**
413 * Generates the 'smallest' (geodesic) rotation between two vectors of arbitrary length.
414 */
415 static FORCEINLINE FQuat FindBetween(const FVector& Vector1, const FVector& Vector2)
416 {
417 return FindBetweenVectors(Vector1, Vector2);
418 }
419
420 /**
421 * Generates the 'smallest' (geodesic) rotation between two normals (assumed to be unit length).
422 */
423 static FQuat FindBetweenNormals(const FVector& Normal1, const FVector& Normal2);
424
425 /**
426 * Generates the 'smallest' (geodesic) rotation between two vectors of arbitrary length.
427 */
428 static FQuat FindBetweenVectors(const FVector& Vector1, const FVector& Vector2);
429
430 /**
431 * Error measure (angle) between two quaternions, ranged [0..1].
432 * Returns the hypersphere-angle between two quaternions; alignment shouldn't matter, though
433 * @note normalized input is expected.
434 */
435 static FORCEINLINE float Error(const FQuat& Q1, const FQuat& Q2);
436
437 /**
438 * FQuat::Error with auto-normalization.
439 */
440 static FORCEINLINE float ErrorAutoNormalize(const FQuat& A, const FQuat& B);
441
442 /**
443 * Fast Linear Quaternion Interpolation.
444 * Result is NOT normalized.
445 */
446 static FORCEINLINE FQuat FastLerp(const FQuat& A, const FQuat& B, const float Alpha);
447
448 /**
449 * Bi-Linear Quaternion interpolation.
450 * Result is NOT normalized.
451 */
452 static FORCEINLINE FQuat FastBilerp(const FQuat& P00, const FQuat& P10, const FQuat& P01, const FQuat& P11, float FracX, float FracY);
453
454
455 /** Spherical interpolation. Will correct alignment. Result is NOT normalized. */
456 static FQuat Slerp_NotNormalized(const FQuat &Quat1, const FQuat &Quat2, float Slerp);
457
458 /** Spherical interpolation. Will correct alignment. Result is normalized. */
459 static FORCEINLINE FQuat Slerp(const FQuat &Quat1, const FQuat &Quat2, float Slerp)
460 {
461 return Slerp_NotNormalized(Quat1, Quat2, Slerp).GetNormalized();
462 }
463
464 /**
465 * Simpler Slerp that doesn't do any checks for 'shortest distance' etc.
466 * We need this for the cubic interpolation stuff so that the multiple Slerps dont go in different directions.
467 * Result is NOT normalized.
468 */
469 static FQuat SlerpFullPath_NotNormalized(const FQuat &quat1, const FQuat &quat2, float Alpha);
470
471 /**
472 * Simpler Slerp that doesn't do any checks for 'shortest distance' etc.
473 * We need this for the cubic interpolation stuff so that the multiple Slerps dont go in different directions.
474 * Result is normalized.
475 */
476 static FORCEINLINE FQuat SlerpFullPath(const FQuat &quat1, const FQuat &quat2, float Alpha)
477 {
478 return SlerpFullPath_NotNormalized(quat1, quat2, Alpha).GetNormalized();
479 }
480
481 /**
482 * Given start and end quaternions of quat1 and quat2, and tangents at those points tang1 and tang2, calculate the point at Alpha (between 0 and 1) between them. Result is normalized.
483 * This will correct alignment by ensuring that the shortest path is taken.
484 */
485 static FQuat Squad(const FQuat& quat1, const FQuat& tang1, const FQuat& quat2, const FQuat& tang2, float Alpha);
486
487 /**
488 * Simpler Squad that doesn't do any checks for 'shortest distance' etc.
489 * Given start and end quaternions of quat1 and quat2, and tangents at those points tang1 and tang2, calculate the point at Alpha (between 0 and 1) between them. Result is normalized.
490 */
491 static FQuat SquadFullPath(const FQuat& quat1, const FQuat& tang1, const FQuat& quat2, const FQuat& tang2, float Alpha);
492
493 /**
494 * Calculate tangents between given points
495 *
496 * @param PrevP quaternion at P-1
497 * @param P quaternion to return the tangent
498 * @param NextP quaternion P+1
499 * @param Tension @todo document
500 * @param OutTan Out control point
501 */
502 static void CalcTangents(const FQuat& PrevP, const FQuat& P, const FQuat& NextP, float Tension, FQuat& OutTan);
503
505
506
507/* FQuat inline functions
508 *****************************************************************************/
509
510FORCEINLINE FQuat::FQuat(const FRotator& R)
511{
512 *this = R.Quaternion();
513 DiagnosticCheckNaN();
514}
515
516
517FORCEINLINE FVector FQuat::operator*(const FVector& V) const
518{
519 return RotateVector(V);
520}
521
522/* FQuat inline functions
523 *****************************************************************************/
524
525FORCEINLINE FQuat::FQuat(EForceInit ZeroOrNot)
526 : X(0), Y(0), Z(0), W(ZeroOrNot == ForceInitToZero ? 0.0f : 1.0f)
527{ }
528
529
530FORCEINLINE FQuat::FQuat(float InX, float InY, float InZ, float InW)
531 : X(InX)
532 , Y(InY)
533 , Z(InZ)
534 , W(InW)
535{
536 DiagnosticCheckNaN();
537}
538
539
540FORCEINLINE FQuat::FQuat(const FQuat& Q)
541 : X(Q.X)
542 , Y(Q.Y)
543 , Z(Q.Z)
544 , W(Q.W)
545{ }
546
547#ifdef IMPLEMENT_ASSIGNMENT_OPERATOR_MANUALLY
548FORCEINLINE FQuat& FQuat::operator=(const FQuat& Other)
549{
550 this->X = Other.X;
551 this->Y = Other.Y;
552 this->Z = Other.Z;
553 this->W = Other.W;
554
555 return *this;
556}
557#endif
558
559
560FORCEINLINE FQuat::FQuat(FVector Axis, float AngleRad)
561{
562 const float half_a = 0.5f * AngleRad;
563 float s, c;
564 FMath::SinCos(&s, &c, half_a);
565
566 X = s * Axis.X;
567 Y = s * Axis.Y;
568 Z = s * Axis.Z;
569 W = c;
570
571 DiagnosticCheckNaN();
572}
573
574
575FORCEINLINE FQuat FQuat::operator+(const FQuat& Q) const
576{
577 return FQuat(X + Q.X, Y + Q.Y, Z + Q.Z, W + Q.W);
578}
579
580
581FORCEINLINE FQuat FQuat::operator+=(const FQuat& Q)
582{
583 this->X += Q.X;
584 this->Y += Q.Y;
585 this->Z += Q.Z;
586 this->W += Q.W;
587
588 DiagnosticCheckNaN();
589
590 return *this;
591}
592
593
594FORCEINLINE FQuat FQuat::operator-(const FQuat& Q) const
595{
596 return FQuat(X - Q.X, Y - Q.Y, Z - Q.Z, W - Q.W);
597}
598
599
600FORCEINLINE bool FQuat::Equals(const FQuat& Q, float Tolerance) const
601{
602#if PLATFORM_ENABLE_VECTORINTRINSICS
603 const VectorRegister ToleranceV = VectorLoadFloat1(&Tolerance);
604 const VectorRegister A = VectorLoadAligned(this);
605 const VectorRegister B = VectorLoadAligned(&Q);
606
607 const VectorRegister RotationSub = VectorAbs(VectorSubtract(A, B));
608 const VectorRegister RotationAdd = VectorAbs(VectorAdd(A, B));
609 return !VectorAnyGreaterThan(RotationSub, ToleranceV) || !VectorAnyGreaterThan(RotationAdd, ToleranceV);
610#else
611 return (FMath::Abs(X - Q.X) <= Tolerance && FMath::Abs(Y - Q.Y) <= Tolerance && FMath::Abs(Z - Q.Z) <= Tolerance && FMath::Abs(W - Q.W) <= Tolerance)
612 || (FMath::Abs(X + Q.X) <= Tolerance && FMath::Abs(Y + Q.Y) <= Tolerance && FMath::Abs(Z + Q.Z) <= Tolerance && FMath::Abs(W + Q.W) <= Tolerance);
613#endif // PLATFORM_ENABLE_VECTORINTRINSICS
614}
615
616FORCEINLINE bool FQuat::IsIdentity(float Tolerance) const
617{
618 return Equals(FQuat::Identity, Tolerance);
619}
620
621FORCEINLINE FQuat FQuat::operator-=(const FQuat& Q)
622{
623 this->X -= Q.X;
624 this->Y -= Q.Y;
625 this->Z -= Q.Z;
626 this->W -= Q.W;
627
628 DiagnosticCheckNaN();
629
630 return *this;
631}
632
633
634FORCEINLINE FQuat FQuat::operator*=(const float Scale)
635{
636 X *= Scale;
637 Y *= Scale;
638 Z *= Scale;
639 W *= Scale;
640
641 DiagnosticCheckNaN();
642
643 return *this;
644}
645
646
647FORCEINLINE FQuat FQuat::operator*(const float Scale) const
648{
649 return FQuat(Scale * X, Scale * Y, Scale * Z, Scale * W);
650}
651
652
653FORCEINLINE FQuat FQuat::operator/=(const float Scale)
654{
655 const float Recip = 1.0f / Scale;
656 X *= Recip;
657 Y *= Recip;
658 Z *= Recip;
659 W *= Recip;
660
661 DiagnosticCheckNaN();
662
663 return *this;
664}
665
666
667FORCEINLINE FQuat FQuat::operator/(const float Scale) const
668{
669 const float Recip = 1.0f / Scale;
670 return FQuat(X * Recip, Y * Recip, Z * Recip, W * Recip);
671}
672
673
674FORCEINLINE bool FQuat::operator==(const FQuat& Q) const
675{
676#if PLATFORM_ENABLE_VECTORINTRINSICS
677 const VectorRegister A = VectorLoadAligned(this);
678 const VectorRegister B = VectorLoadAligned(&Q);
679 return VectorMaskBits(VectorCompareEQ(A, B)) == 0x0F;
680#else
681 return X == Q.X && Y == Q.Y && Z == Q.Z && W == Q.W;
682#endif // PLATFORM_ENABLE_VECTORINTRINSICS
683}
684
685
686FORCEINLINE bool FQuat::operator!=(const FQuat& Q) const
687{
688#if PLATFORM_ENABLE_VECTORINTRINSICS
689 const VectorRegister A = VectorLoadAligned(this);
690 const VectorRegister B = VectorLoadAligned(&Q);
691 return VectorMaskBits(VectorCompareNE(A, B)) != 0x00;
692#else
693 return X != Q.X || Y != Q.Y || Z != Q.Z || W != Q.W;
694#endif // PLATFORM_ENABLE_VECTORINTRINSICS
695}
696
697
698FORCEINLINE float FQuat::operator|(const FQuat& Q) const
699{
700 return X * Q.X + Y * Q.Y + Z * Q.Z + W * Q.W;
701}
702
703
704FORCEINLINE void FQuat::Normalize(float Tolerance)
705{
706#if PLATFORM_ENABLE_VECTORINTRINSICS
707 const VectorRegister Vector = VectorLoadAligned(this);
708
709 const VectorRegister SquareSum = VectorDot4(Vector, Vector);
710 const VectorRegister NonZeroMask = VectorCompareGE(SquareSum, VectorLoadFloat1(&Tolerance));
711 const VectorRegister InvLength = VectorReciprocalSqrtAccurate(SquareSum);
712 const VectorRegister NormalizedVector = VectorMultiply(InvLength, Vector);
713 VectorRegister Result = VectorSelect(NonZeroMask, NormalizedVector, GlobalVectorConstants::Float0001);
714
715 VectorStoreAligned(Result, this);
716#else
717 const float SquareSum = X * X + Y * Y + Z * Z + W * W;
718
719 if (SquareSum >= Tolerance)
720 {
721 const float Scale = FMath::InvSqrt(SquareSum);
722
723 X *= Scale;
724 Y *= Scale;
725 Z *= Scale;
726 W *= Scale;
727 }
728 else
729 {
730 *this = FQuat::Identity;
731 }
732#endif // PLATFORM_ENABLE_VECTORINTRINSICS
733}
734
735
736FORCEINLINE FQuat FQuat::GetNormalized(float Tolerance) const
737{
738 FQuat Result(*this);
739 Result.Normalize(Tolerance);
740 return Result;
741}
742
743FORCEINLINE bool FQuat::IsNormalized() const
744{
745 return (FMath::Abs(1.f - SizeSquared()) < THRESH_QUAT_NORMALIZED);
746}
747
748
749FORCEINLINE float FQuat::Size() const
750{
751 return FMath::Sqrt(X * X + Y * Y + Z * Z + W * W);
752}
753
754
755FORCEINLINE float FQuat::SizeSquared() const
756{
757 return (X * X + Y * Y + Z * Z + W * W);
758}
759
760FORCEINLINE float FQuat::GetAngle() const
761{
762 return 2.f * FMath::Acos(W);
763}
764
765
766FORCEINLINE void FQuat::ToAxisAndAngle(FVector& Axis, float& Angle) const
767{
768 Angle = GetAngle();
769 Axis = GetRotationAxis();
770}
771
772FORCEINLINE FVector FQuat::GetRotationAxis() const
773{
774 // Ensure we never try to sqrt a neg number
775 const float S = FMath::Sqrt(FMath::Max(1.f - (W * W), 0.f));
776
777 if (S >= 0.0001f)
778 {
779 return FVector(X / S, Y / S, Z / S);
780 }
781
782 return FVector(1.f, 0.f, 0.f);
783}
784
785float FQuat::AngularDistance(const FQuat& Q) const
786{
787 float InnerProd = X*Q.X + Y*Q.Y + Z*Q.Z + W*Q.W;
788 return FMath::Acos((2 * InnerProd * InnerProd) - 1.f);
789}
790
791
792FORCEINLINE FVector FQuat::RotateVector(FVector V) const
793{
794#if WITH_DIRECTXMATH
795 FVector Result;
796 VectorQuaternionVector3Rotate(&Result, &V, this);
797 return Result;
798
799#else
800
801 // http://people.csail.mit.edu/bkph/articles/Quaternions.pdf
802 // V' = V + 2w(Q x V) + (2Q x (Q x V))
803 // refactor:
804 // V' = V + w(2(Q x V)) + (Q x (2(Q x V)))
805 // T = 2(Q x V);
806 // V' = V + w*(T) + (Q x T)
807
808 const FVector Q(X, Y, Z);
809 const FVector T = 2.f * FVector::CrossProduct(Q, V);
810 const FVector Result = V + (W * T) + FVector::CrossProduct(Q, T);
811 return Result;
812#endif
813}
814
815FORCEINLINE FVector FQuat::UnrotateVector(FVector V) const
816{
817#if WITH_DIRECTXMATH
818 FVector Result;
819 VectorQuaternionVector3InverseRotate(&Result, &V, this);
820 return Result;
821#else
822 //return Inverse().RotateVector(V);
823
824 const FVector Q(-X, -Y, -Z); // Inverse
825 const FVector T = 2.f * FVector::CrossProduct(Q, V);
826 const FVector Result = V + (W * T) + FVector::CrossProduct(Q, T);
827 return Result;
828#endif
829}
830
831
832FORCEINLINE FQuat FQuat::Inverse() const
833{
834 checkSlow(IsNormalized());
835
836 return FQuat(-X, -Y, -Z, W);
837}
838
839
840FORCEINLINE void FQuat::EnforceShortestArcWith(const FQuat& OtherQuat)
841{
842 const float DotResult = (OtherQuat | *this);
843 const float Bias = FMath::FloatSelect(DotResult, 1.0f, -1.0f);
844
845 X *= Bias;
846 Y *= Bias;
847 Z *= Bias;
848 W *= Bias;
849}
850
851
852FORCEINLINE FVector FQuat::GetAxisX() const
853{
854 return RotateVector(FVector(1.f, 0.f, 0.f));
855}
856
857
858FORCEINLINE FVector FQuat::GetAxisY() const
859{
860 return RotateVector(FVector(0.f, 1.f, 0.f));
861}
862
863
864FORCEINLINE FVector FQuat::GetAxisZ() const
865{
866 return RotateVector(FVector(0.f, 0.f, 1.f));
867}
868
869
870FORCEINLINE FVector FQuat::GetForwardVector() const
871{
872 return GetAxisX();
873}
874
875FORCEINLINE FVector FQuat::GetRightVector() const
876{
877 return GetAxisY();
878}
879
880FORCEINLINE FVector FQuat::GetUpVector() const
881{
882 return GetAxisZ();
883}
884
885FORCEINLINE FVector FQuat::Vector() const
886{
887 return GetAxisX();
888}
889
890
891FORCEINLINE float FQuat::Error(const FQuat& Q1, const FQuat& Q2)
892{
893 const float cosom = FMath::Abs(Q1.X * Q2.X + Q1.Y * Q2.Y + Q1.Z * Q2.Z + Q1.W * Q2.W);
894 return (FMath::Abs(cosom) < 0.9999999f) ? FMath::Acos(cosom)*(1.f / PI) : 0.0f;
895}
896
897
898FORCEINLINE float FQuat::ErrorAutoNormalize(const FQuat& A, const FQuat& B)
899{
900 FQuat Q1 = A;
901 Q1.Normalize();
902
903 FQuat Q2 = B;
904 Q2.Normalize();
905
906 return FQuat::Error(Q1, Q2);
907}
908
909/**
910 * Fast Linear Quaternion Interpolation.
911 * Result is NOT normalized.
912 */
913FORCEINLINE FQuat FQuat::FastLerp(const FQuat& A, const FQuat& B, const float Alpha)
914{
915 // To ensure the 'shortest route', we make sure the dot product between the both rotations is positive.
916 const float DotResult = (A | B);
917 const float Bias = FMath::FloatSelect(DotResult, 1.0f, -1.0f);
918 return (B * Alpha) + (A * (Bias * (1.f - Alpha)));
919}
920
921
922FORCEINLINE FQuat FQuat::FastBilerp(const FQuat& P00, const FQuat& P10, const FQuat& P01, const FQuat& P11, float FracX, float FracY)
923{
924 return FQuat::FastLerp(
925 FQuat::FastLerp(P00,P10,FracX),
926 FQuat::FastLerp(P01,P11,FracX),
927 FracY
928 );
929}
930
931
932FORCEINLINE bool FQuat::ContainsNaN() const
933{
934 return (!FMath::IsFinite(X) ||
938 );
939}
940
941template<> struct TIsPODType<FQuat> { enum { Value = true }; };
#define checkSlow(expr)
Definition BasicTypes.h:15
#define MS_ALIGN(n)
Definition BasicTypes.h:21
#define GCC_ALIGN(n)
Definition BasicTypes.h:22
EForceInit
Definition BasicTypes.h:147
@ ForceInitToZero
Definition BasicTypes.h:149
#define ENABLE_NAN_DIAGNOSTIC
#define SMALL_NUMBER
#define PI
#define THRESH_QUAT_NORMALIZED
#define KINDA_SMALL_NUMBER
FORCEINLINE FVector operator*(float Scale, const FVector &V)
Definition Vector.h:870
static FORCEINLINE float Acos(float Value)
static FORCEINLINE float InvSqrt(float F)
static CONSTEXPR FORCEINLINE float FloatSelect(float Comparand, float ValueGEZero, float ValueLTZero)
static FORCEINLINE float Sqrt(float Value)
static CONSTEXPR FORCEINLINE T Max(const T A, const T B)
static FORCEINLINE bool IsFinite(float A)
static CONSTEXPR FORCEINLINE T Abs(const T A)
static FORCEINLINE void SinCos(float *ScalarSin, float *ScalarCos, float Value)
FQuat Quaternion() const
float X
Definition Vector.h:27
float Y
Definition Vector.h:30
float Z
Definition Vector.h:33
static FORCEINLINE FVector CrossProduct(const FVector &A, const FVector &B)
Definition Vector.h:1115
FORCEINLINE FVector operator+(const FVector &V) const
Definition Vector.h:1130
FORCEINLINE CONSTEXPR FVector(float InX, float InY, float InZ)
Definition Vector.h:1067