5#include "testing/testing.h"
21 float in_quat[4] = {
w,
x,
y,
z};
22 float norm_quat[4], matrix[3][3], out_quat[4];
33 EXPECT_V4_NEAR(norm_quat, out_quat, FLT_EPSILON);
36TEST(math_rotation, quat_to_mat_to_quat_rot180)
44TEST(math_rotation, quat_to_mat_to_quat_rot180n)
52TEST(math_rotation, quat_to_mat_to_quat_rot90)
54 const float s2 = 1 /
sqrtf(2);
63TEST(math_rotation, quat_to_mat_to_quat_rot90n)
65 const float s2 = 1 /
sqrtf(2);
74TEST(math_rotation, quat_to_mat_to_quat_bad_T83196)
83TEST(math_rotation, quat_to_mat_to_quat_bad_negative)
89TEST(math_rotation, quat_to_mat_to_quat_near_1000)
103TEST(math_rotation, quat_to_mat_to_quat_near_0100)
117TEST(math_rotation, quat_to_mat_to_quat_near_0010)
131TEST(math_rotation, quat_to_mat_to_quat_near_0001)
146TEST(math_rotation, quat_to_mat_to_quat_zeroed_matrix)
148 float matrix_zeroed[3][3] = {{0.0f}};
149 float matrix_result[3][3];
150 float matrix_unit[3][3];
157 EXPECT_M3_NEAR(matrix_unit, matrix_result, FLT_EPSILON);
160TEST(math_rotation, quat_split_swing_and_twist_negative)
162 const float input[4] = {-0.5f, 0,
sqrtf(3) / 2, 0};
163 const float expected_swing[4] = {1.0f, 0, 0, 0};
164 const float expected_twist[4] = {0.5f, 0, -
sqrtf(3) / 2, 0};
165 float swing[4], twist[4];
169 EXPECT_NEAR(twist_angle, -
M_PI * 2 / 3, FLT_EPSILON);
170 EXPECT_V4_NEAR(swing, expected_swing, FLT_EPSILON);
171 EXPECT_V4_NEAR(twist, expected_twist, FLT_EPSILON);
174TEST(math_rotation, mat3_normalized_to_quat_fast_degenerate)
180 const float input[3][3] = {
181 {1.0000000000, -0.0000006315, -0.0000000027},
182 {0.0000009365, 1.0000000000, -0.0000000307},
183 {0.0000001964, 0.2103530765, 0.9776254892},
185 const float expect_quat[4] = {
187 -0.052810292690992355,
188 4.9985139582986449e-08,
189 -3.93654971730939e-07,
191 ASSERT_FLOAT_EQ(1.0f,
dot_qtqt(expect_quat, expect_quat))
192 <<
"expected quaternion should be normal";
194 float actual_quat[4];
196 EXPECT_FLOAT_EQ(1.0f,
dot_qtqt(actual_quat, actual_quat));
197 EXPECT_V4_NEAR(expect_quat, actual_quat, FLT_EPSILON);
206 for (
int i = 0; i <
range; i++) {
210 const float sin_cos_test_fl[2] = {
sinf(phi),
cosf(phi)};
211 EXPECT_V2_NEAR(sin_cos_fl, sin_cos_test_fl, expected_eps);
216TEST(math_rotation, sin_cos_from_fraction_accuracy)
218 for (
int range = 1; range <= 64; range++) {
231 } multiple_of = (range & 1) ? MULTIPLE_OF_1 : ((range & 3) ? MULTIPLE_OF_2 : MULTIPLE_OF_4);
235 for (
int i = 0; i <
range; i++) {
238 switch (multiple_of) {
239 case MULTIPLE_OF_1: {
240 sin_cos_fl[0] =
fabsf(sin_cos_fl[0]);
243 case MULTIPLE_OF_2: {
244 sin_cos_fl[0] =
fabsf(sin_cos_fl[0]);
245 sin_cos_fl[1] =
fabsf(sin_cos_fl[1]);
248 case MULTIPLE_OF_4: {
249 sin_cos_fl[0] =
fabsf(sin_cos_fl[0]);
250 sin_cos_fl[1] =
fabsf(sin_cos_fl[1]);
251 if (sin_cos_fl[0] > sin_cos_fl[1]) {
252 std::swap(sin_cos_fl[0], sin_cos_fl[1]);
261 float delta = b[0] - a[0];
267 int unique_coords_count = 1;
270 for (
int i = 1; i <
range; i_prev = i++) {
271 if (coords[i_prev] != coords[i]) {
272 unique_coords_count += 1;
276 switch (multiple_of) {
277 case MULTIPLE_OF_1: {
278 EXPECT_EQ(unique_coords_count, (range / 2) + 1);
281 case MULTIPLE_OF_2: {
282 EXPECT_EQ(unique_coords_count, (range / 4) + 1);
285 case MULTIPLE_OF_4: {
286 EXPECT_EQ(unique_coords_count, (range / 8) + 1);
292TEST(math_rotation, sin_cos_from_fraction_symmetry)
294 for (
int range = 1; range <= 64; range++) {
303TEST(math_rotation, DefaultConstructor)
317TEST(math_rotation, RotateDirectionAroundAxis)
320 EXPECT_NEAR(a.x, 0.0f, FLT_EPSILON);
321 EXPECT_NEAR(a.y, 1.0f, FLT_EPSILON);
322 EXPECT_NEAR(a.z, 0.0f, FLT_EPSILON);
324 EXPECT_NEAR(
b.x, -1.0f, FLT_EPSILON);
325 EXPECT_NEAR(
b.y, 0.0f, FLT_EPSILON);
326 EXPECT_NEAR(
b.z, 0.0f, FLT_EPSILON);
328 EXPECT_NEAR(c.x, 0.0f, FLT_EPSILON);
329 EXPECT_NEAR(c.y, 0.0f, FLT_EPSILON);
330 EXPECT_NEAR(c.z, 1.0f, FLT_EPSILON);
333TEST(math_rotation, AxisAngleConstructors)
336 EXPECT_V3_NEAR(a.axis(),
float3(0, 0, 1), 1
e-4);
337 EXPECT_NEAR(
float(a.angle()),
M_PI_2, 1
e-4);
338 EXPECT_NEAR(
sin(a.angle()), 1.0f, 1
e-4);
339 EXPECT_NEAR(
cos(a.angle()), 0.0f, 1
e-4);
342 EXPECT_V3_NEAR(
b.axis(),
float3(0, 0, 1), 1
e-4);
343 EXPECT_NEAR(
float(
b.angle()),
M_PI_2, 1
e-4);
344 EXPECT_NEAR(
b.angle().sin(), 1.0f, 1
e-4);
345 EXPECT_NEAR(
b.angle().cos(), 0.0f, 1
e-4);
351 AxisAngle c({1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f});
352 EXPECT_V3_NEAR(c.axis(),
float3(0, 0, 1), 1
e-4);
353 EXPECT_NEAR(
float(c.angle()),
M_PI_2, 1
e-4);
355 AxisAngle d({1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f});
356 EXPECT_V3_NEAR(d.axis(),
float3(0, 0, -1), 1
e-4);
357 EXPECT_NEAR(
float(d.angle()),
M_PI_2, 1
e-4);
360TEST(math_rotation, QuaternionDot)
367TEST(math_rotation, QuaternionConjugate)
373TEST(math_rotation, QuaternionNormalize)
377 float4(0.1825741827, 0.3651483654, 0.5477225780, 0.7302967309),
381TEST(math_rotation, QuaternionInvert)
386 Quaternion q2(0.927091f, 0.211322f, -0.124857f, 0.283295f);
388 EXPECT_V4_NEAR(
float4(result),
float4(0.927091f, -0.211322f, 0.124857f, -0.283295f), 1e-4f);
391TEST(math_rotation, QuaternionCanonicalize)
394 float4(0.5f, 2.0f, 3.0f, 4.0f),
397 float4(0.5f, -2.0f, -3.0f, -4.0f),
401TEST(math_rotation, QuaternionAngleBetween)
406 EXPECT_V4_NEAR(
float4(q3),
float4(-0.394478f, 0.00330195f, 0.284119f, -0.873872f), 1e-4f);
407 EXPECT_NEAR(
float(
angle_of(
q1)), 0.76844f, 1e-4f);
408 EXPECT_NEAR(
float(
angle_of(q2)), 3.30854f, 1e-4f);
409 EXPECT_NEAR(
float(
angle_of(q3)), 3.95259f, 1e-4f);
417TEST(math_rotation, QuaternionPower)
440TEST(math_rotation, QuaternionFromTriangle)
442 float3 v1(0.927091f, 0.211322f, -0.124857f);
443 float3 v2(-0.051681f, 0.498261f, -0.86146f);
444 float3 v3(0.211322f, -0.124857f, 0.283295f);
446 float4(0.255566f, -0.213799f, 0.454253f, 0.826214f),
449 float4(0.103802f, 0.295067f, -0.812945f, 0.491204f),
453TEST(math_rotation, QuaternionFromVector)
455 float3 v1(0.927091f, 0.211322f, -0.124857f);
456 float3 v2(-0.051681f, 0.498261f, -0.86146f);
458 float4(0.129047, 0, -0.50443, -0.853755),
461 float4(0.12474, 0.0330631, -0.706333, -0.696017),
464 float4(0.111583, -0.0648251, -0.00729451, -0.991612),
467 float4(0.476074, 0.580363, -0.403954, 0.522832),
470 float4(0.62436, 0.104259, 0, 0.774148),
473 float4(0.622274, 0.0406802, 0.0509963, 0.780077),
476 float4(0.747014, 0.0737433, -0.655337, 0.0840594),
479 float4(0.751728, 0.146562, -0.642981, 0),
482 float4(0.751728, 0.146562, -0.642981, 0),
485 float4(0.991638, 0, 0.0656442, 0.111104),
488 float4(0.706333, 0.696017, 0.12474, 0.0330631),
491 float4(0.991612, -0.0072946, 0.0648251, 0.111583),
494 float4(0.580363, -0.476074, -0.522832, -0.403954),
497 float4(0.781137, -0.083334, 0, -0.618774),
500 float4(0.780077, -0.0509963, 0.0406802, -0.622274),
503 float4(0.0737433, -0.747014, -0.0840594, -0.655337),
506 float4(0.659473, -0.167065, 0.732929, 0),
509 float4(0.659473, -0.167065, 0.732929, 0),
513 float4(0.725211, 0, -0.596013, -0.344729),
516 float4(0.691325, 0.219092, -0.672309, -0.148561),
519 float4(0.643761, -0.333919, -0.370346, -0.580442),
522 float4(0.320473, 0.593889, 0.383792, 0.630315),
525 float4(0.499999, 0.864472, 0, -0.0518617),
528 float4(0.0447733, 0.0257574, -0.49799, -0.865643),
531 float4(0.646551, 0.193334, -0.174318, 0.717082),
534 float4(0.965523, 0.258928, 0.0268567, 0),
537 float4(0.965523, 0.258928, 0.0268567, 0),
540 float4(0.688527, 0, 0.627768, 0.363095),
543 float4(0.672309, 0.148561, 0.691325, 0.219092),
546 float4(0.580442, -0.370345, 0.333919, 0.643761),
549 float4(0.593889, -0.320473, -0.630315, 0.383792),
552 float4(0.866026, -0.499102, 0, 0.0299423),
555 float4(0.865643, -0.49799, -0.0257574, 0.0447733),
558 float4(0.193334, -0.646551, -0.717082, -0.174318),
561 float4(0.260317, -0.960371, -0.0996123, 0),
564 float4(0.260317, -0.960371, -0.0996123, 0),
568TEST(math_rotation, QuaternionWrappedAround)
578TEST(math_rotation, QuaternionFromTracking)
585 if (forward_axis.
axis() == up_axis) {
603TEST(math_rotation, EulerWrappedAround)
611TEST(math_rotation, Euler3ToGimbal)
614 float3 ijk{0.350041, -0.358896, 0.528994};
623 float3x3({0.808309, -0.504665, 0}, {0.47251, 0.863315, 0}, {0.351241, 0, 1}));
625 float3x3({0.808309, 0, -0.351241}, {0.504665, 1, -0}, {0.303232, 0, 0.936285}));
627 float3x3({0.863315, -0.474062, 0}, {0.504665, 0.810963, 0}, {-0, 0.342936, 1}));
629 float3x3({1, -0.504665, 0}, {0, 0.810963, -0.342936}, {0, 0.296062, 0.939359}));
631 float3x3({0.936285, 0, -0.329941}, {0, 1, -0.342936}, {0.351241, 0, 0.879508}));
633 float3x3({1, -0, -0.351241}, {0, 0.939359, -0.321086}, {0, 0.342936, 0.879508}));
654 if ((
abs(src_forward) ==
abs(src_up)) || (
abs(dst_forward) ==
abs(dst_up))) {
660 if (src_forward == dst_forward && src_up == dst_up) {
676 if (src_forward == dst_forward) {
699 Quaternion q(0.927091f, 0.211322f, -0.124857f, 0.283295f);
701 float3 p(0.576f, -0.6546f, 46.354f);
703 EXPECT_V3_NEAR(result,
float3(-4.33722f, -21.661f, 40.7608f), 1e-4f);
706 float3 p2(1.0f, 2.0f, 3.0f);
721TEST(math_rotation, DualQuaternionNormalize)
735 EXPECT_V4_NEAR(
float4(
sum.trans), (
float4(0.777778, 0.666667, 0.444444, 0.666667) /
len), 1e-4f);
741TEST(math_rotation, DualQuaternionFromMatrix)
745 {-1.28264, 2.87361, 0.0230992, 12.8871},
746 {3.27343, 0.812993, -0.895575, -13.5216},
749 {0.16104, -0.406549, 0.899324, 22.8871},
750 {0.981987, -0.0252451, -0.187255, -3.52155},
753 {-0.445021, 2.97151, -0.250095, -42.5586},
754 {0.146173, 0.473002, 1.62645, -9.75092},
758 EXPECT_V4_NEAR(
float4(dq.
quat),
float4(0.502368, 0.0543716, -0.854483, -0.120535), 1e-4f);
759 EXPECT_V4_NEAR(
float4(dq.
trans),
float4(22.674, -0.878616, 11.2762, 14.167), 1e-4f);
760 EXPECT_M4_NEAR(dq.
scale, expected_scale_mat, 1e-4f);
766 {-1.04583, -0.150756, -0.385074, -22.2225},
767 {-0.123402, 2.32698, 1.66357, 5.397},
770 {-0.271734, 0.421514, -0.865151, -12.2225},
771 {-0.960477, -0.0623834, 0.27128, 15.397},
774 {0.971507, -0.382422, 1.09917, -69.5943},
775 {-0.331274, 0.8794, 2.67787, -2.88715},
779 EXPECT_V4_NEAR(
float4(dq.
quat),
float4(0.149898, -0.319339, -0.0441496, -0.934668), 1e-4f);
780 EXPECT_V4_NEAR(
float4(dq.
trans),
float4(-2.20019, 39.6236, 49.052, -16.2077), 1e-4f);
781 EXPECT_M4_NEAR(dq.
scale, expected_scale_mat, 1e-4f);
787 for (
int i = 0; i < 1000; i++) {
788 auto frand = []() {
return (std::rand() - RAND_MAX / 2) /
float(RAND_MAX); };
794 mat.
location() + 10,
EulerXYZ{frand() * 10.0f, frand() * 10.0f, frand() * 10.0f});
802 EXPECT_M4_NEAR(dq.
scale, expect.
scale, 2e-4f);
808TEST(math_rotation, DualQuaternionTransform)
812 {-0.445021, 2.97151, -0.250095, -42.5586},
813 {0.146173, 0.473002, 1.62645, -9.75092},
817 {22.674, -0.878616, 11.2762, 14.167},
820 float3 p0{51.0f, 1647.0f, 12.0f};
821 float3 p1{58.0f, 0.0054f, 10.0f};
822 float3 p2{0.0f, 7854.0f, 111.0f};
837 {-1.28264, 2.87361, 0.0230978},
838 {3.27343, 0.812991, -0.895574}))};
840 EXPECT_V3_NEAR(p0_result, p0_expect, 1e-2f);
841 EXPECT_V3_NEAR(p1_result, p1_expect, 1e-2f);
842 EXPECT_V3_NEAR(p2_result, p2_expect, 1e-2f);
843 EXPECT_M3_NEAR(crazy_space_mat, expected_crazy_space_mat, 1e-4f);
847 {0.971507, -0.382422, 1.09917, -69.5943},
848 {-0.331274, 0.8794, 2.67787, -2.88715},
852 {-2.20019, 39.6236, 49.052, -16.207},
855 float3 p0{51.0f, 1647.0f, 12.0f};
856 float3 p1{58.0f, 0.0054f, 10.0f};
857 float3 p2{0.0f, 7854.0f, 111.0f};
872 {-1.04583, -0.150754, -0.385079},
873 {-0.123401, 2.32698, 1.66357}))};
875 EXPECT_V3_NEAR(p0_result,
float3(-2591.83, -328.472, 3851.6), 1e-2f);
876 EXPECT_V3_NEAR(p1_result,
float3(46.6121, -86.7318, 14.8882), 1e-2f);
877 EXPECT_V3_NEAR(p2_result,
float3(-12309.5, -1248.99, 18466.1), 6e-2f);
878 EXPECT_M3_NEAR(crazy_space_mat, expected_crazy_space_mat, 1e-4f);
882TEST(math_axis_angle, AxisAngleFromQuaternion)
888 EXPECT_V3_NEAR(axis_angle.axis(), from_quaternion.axis(), 1
e-6);
889 EXPECT_NEAR(axis_angle.angle().radian(), from_quaternion.angle().radian(), 1
e-6);
895 EXPECT_V3_NEAR(axis_angle.axis(), from_quaternion.axis(), 1
e-6);
896 EXPECT_NEAR(axis_angle.angle().radian(), from_quaternion.angle().radian(), 1
e-6);
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
void unit_m3(float m[3][3])
void quat_to_mat3(float m[3][3], const float q[4])
void sin_cos_from_fraction(int numerator, int denominator, float *r_sin, float *r_cos)
void mul_qt_fl(float q[4], float f)
float normalize_qt_qt(float r[4], const float q[4])
float dot_qtqt(const float a[4], const float b[4])
float quat_split_swing_and_twist(const float q_in[4], int axis, float r_swing[4], float r_twist[4])
void mat4_to_dquat(DualQuat *dq, const float basemat[4][4], const float mat[4][4])
bool mat3_from_axis_conversion(int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3])
void mul_v3m3_dq(float r[3], float R[3][3], DualQuat *dq)
void quat_apply_track(float quat[4], short axis, short upflag)
void mat3_normalized_to_quat_fast(float q[4], const float mat[3][3])
void mat3_normalized_to_quat(float q[4], const float mat[3][3])
bool mat3_from_axis_conversion_single(int src_axis, int dst_axis, float r_mat[3][3])
TEST(math_rotation, quat_to_mat_to_quat_rot180)
static void test_sin_cos_from_fraction_accuracy(const int range, const float expected_eps)
static void test_quat_to_mat_to_quat(float w, float x, float y, float z)
static void test_sin_cos_from_fraction_symmetry(const int range)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
btMatrix3x3 transpose() const
Return the transpose of the matrix.
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
static T sum(const btAlignedObjectArray< T > &items)
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
void append_unchecked(const T &value)
void reserve(const int64_t min_capacity)
constexpr int as_int() const
static constexpr Value Z_POS
static constexpr Value Y_NEG
static constexpr Value Z_NEG
static constexpr AxisSigned from_int(int axis_int)
static constexpr Value X_NEG
static constexpr Value Y_POS
static constexpr Value X_POS
constexpr Axis axis() const
constexpr int as_int() const
static constexpr Axis from_int(const int axis_int)
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
TEST(math_rotation, DefaultConstructor)
AngleCartesianBase< float > AngleCartesian
QuaternionBase< T > from_triangle(const VecBase< T, 3 > &v1, const VecBase< T, 3 > &v2, const VecBase< T, 3 > &v3, const VecBase< T, 3 > &normal)
AngleRadianBase< float > AngleRadian
QuaternionBase< T > conjugate(const QuaternionBase< T > &a)
QuaternionBase< float > Quaternion
T cos(const AngleRadianBase< T > &a)
T pow(const T &x, const T &power)
QuaternionBase< T > from_vector(const VecBase< T, 3 > &vector, const AxisSigned track_flag, const Axis up_flag)
QuaternionBase< T > to_quaternion(const AxisAngleBase< T, AngleT > &axis_angle)
CartesianBasis rotation_between(const CartesianBasis &a, const CartesianBasis &b)
AngleRadianBase< T > angle_between(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
MatT from_loc_rot(const typename MatT::loc_type &location, const RotationT &rotation)
AxisAngleBase< float, AngleRadianBase< float > > AxisAngle
AngleRadianBase< T > angle_between_signed(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
EulerXYZBase< float > EulerXYZ
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
MatBase< T, 3, 3 > to_gimbal_axis(const Euler3Base< T > &rotation)
CartesianBasis invert(const CartesianBasis &basis)
float3 rotate_direction_around_axis(const float3 &direction, const float3 &axis, float angle)
AngleRadianBase< T > angle_of(const QuaternionBase< T > &q)
DualQuaternionBase< float > DualQuaternion
QuaternionBase< T > invert_normalized(const QuaternionBase< T > &q)
AxisAngleBase< T, AngleT > to_axis_angle(const EulerXYZBase< T > &euler)
QuaternionBase< T > canonicalize(const QuaternionBase< T > &q)
T sin(const AngleRadianBase< T > &a)
AngleRadianBase< T > angle_of_signed(const QuaternionBase< T > &q)
CartesianBasis from_orthonormal_axes(const AxisSigned forward, const AxisSigned up)
MatT from_rotation(const RotationT &rotation)
DualQuaternionBase< T > to_dual_quaternion(const MatBase< T, 4, 4 > &mat, const MatBase< T, 4, 4 > &basemat)
MatT from_loc_rot_scale(const typename MatT::loc_type &location, const RotationT &rotation, const VecBase< typename MatT::base_type, ScaleDim > &scale)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
const c_style_mat & ptr() const
static MatBase identity()
const AngleT & angle() const
const vec3_type & axis() const
QuaternionBase< T > trans
EulerXYZBase wrapped_around(const EulerXYZBase &reference) const
static QuaternionBase identity()