Blender V5.0
math_matrix.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_math_matrix.hh"
10
11#include "BLI_math_rotation.hh"
12#include "BLI_simd.hh"
13#include "BLI_task.hh"
14
15#include <Eigen/Core>
16#include <Eigen/Dense>
17#include <Eigen/Eigenvalues>
18
19/* -------------------------------------------------------------------- */
22
23namespace blender {
24
25template<> float4x4 operator*(const float4x4 &a, const float4x4 &b)
26{
27 using namespace math;
29
30#if BLI_HAVE_SSE2
31 __m128 A0 = _mm_load_ps(a[0]);
32 __m128 A1 = _mm_load_ps(a[1]);
33 __m128 A2 = _mm_load_ps(a[2]);
34 __m128 A3 = _mm_load_ps(a[3]);
35
36 for (int i = 0; i < 4; i++) {
37 __m128 B0 = _mm_set1_ps(b[i][0]);
38 __m128 B1 = _mm_set1_ps(b[i][1]);
39 __m128 B2 = _mm_set1_ps(b[i][2]);
40 __m128 B3 = _mm_set1_ps(b[i][3]);
41
42 __m128 sum = _mm_add_ps(_mm_add_ps(_mm_mul_ps(B0, A0), _mm_mul_ps(B1, A1)),
43 _mm_add_ps(_mm_mul_ps(B2, A2), _mm_mul_ps(B3, A3)));
44
45 _mm_store_ps(result[i], sum);
46 }
47#else
48 result[0][0] = b[0][0] * a[0][0] + b[0][1] * a[1][0] + b[0][2] * a[2][0] + b[0][3] * a[3][0];
49 result[0][1] = b[0][0] * a[0][1] + b[0][1] * a[1][1] + b[0][2] * a[2][1] + b[0][3] * a[3][1];
50 result[0][2] = b[0][0] * a[0][2] + b[0][1] * a[1][2] + b[0][2] * a[2][2] + b[0][3] * a[3][2];
51 result[0][3] = b[0][0] * a[0][3] + b[0][1] * a[1][3] + b[0][2] * a[2][3] + b[0][3] * a[3][3];
52
53 result[1][0] = b[1][0] * a[0][0] + b[1][1] * a[1][0] + b[1][2] * a[2][0] + b[1][3] * a[3][0];
54 result[1][1] = b[1][0] * a[0][1] + b[1][1] * a[1][1] + b[1][2] * a[2][1] + b[1][3] * a[3][1];
55 result[1][2] = b[1][0] * a[0][2] + b[1][1] * a[1][2] + b[1][2] * a[2][2] + b[1][3] * a[3][2];
56 result[1][3] = b[1][0] * a[0][3] + b[1][1] * a[1][3] + b[1][2] * a[2][3] + b[1][3] * a[3][3];
57
58 result[2][0] = b[2][0] * a[0][0] + b[2][1] * a[1][0] + b[2][2] * a[2][0] + b[2][3] * a[3][0];
59 result[2][1] = b[2][0] * a[0][1] + b[2][1] * a[1][1] + b[2][2] * a[2][1] + b[2][3] * a[3][1];
60 result[2][2] = b[2][0] * a[0][2] + b[2][1] * a[1][2] + b[2][2] * a[2][2] + b[2][3] * a[3][2];
61 result[2][3] = b[2][0] * a[0][3] + b[2][1] * a[1][3] + b[2][2] * a[2][3] + b[2][3] * a[3][3];
62
63 result[3][0] = b[3][0] * a[0][0] + b[3][1] * a[1][0] + b[3][2] * a[2][0] + b[3][3] * a[3][0];
64 result[3][1] = b[3][0] * a[0][1] + b[3][1] * a[1][1] + b[3][2] * a[2][1] + b[3][3] * a[3][1];
65 result[3][2] = b[3][0] * a[0][2] + b[3][1] * a[1][2] + b[3][2] * a[2][2] + b[3][3] * a[3][2];
66 result[3][3] = b[3][0] * a[0][3] + b[3][1] * a[1][3] + b[3][2] * a[2][3] + b[3][3] * a[3][3];
67#endif
68
69 return result;
70}
71
72template<> float3x3 operator*(const float3x3 &a, const float3x3 &b)
73{
74 using namespace math;
76
77#if 0 /* 1.2 times slower. Could be used as reference for aligned version. */
78 __m128 A0 = _mm_set_ps(0, a[0][2], a[0][1], a[0][0]);
79 __m128 A1 = _mm_set_ps(0, a[1][2], a[1][1], a[1][0]);
80 __m128 A2 = _mm_set_ps(0, a[2][2], a[2][1], a[2][0]);
81
82 for (int i = 0; i < 2; i++) {
83 __m128 B0 = _mm_set1_ps(b[i][0]);
84 __m128 B1 = _mm_set1_ps(b[i][1]);
85 __m128 B2 = _mm_set1_ps(b[i][2]);
86 __m128 sum = _mm_add_ps(_mm_add_ps(_mm_mul_ps(B0, A0), _mm_mul_ps(B1, A1)),
87 _mm_mul_ps(B2, A2));
88 _mm_storeu_ps(result[i], sum);
89 }
90
91 _mm_storeu_ps(result[1], sum[1]);
92 /* Manual per component store to avoid segfault. */
93 _mm_store_ss(&result[2][0], sum[2]);
94 sum[2] = _mm_shuffle_ps(sum[2], sum[2], _MM_SHUFFLE(3, 2, 1, 1));
95 _mm_store_ss(&result[2][1], sum[2]);
96 sum[2] = _mm_shuffle_ps(sum[2], sum[2], _MM_SHUFFLE(3, 2, 1, 2));
97 _mm_store_ss(&result[2][2], sum[2]);
98
99#else
101 result[0][0] = b[0][0] * a[0][0] + b[0][1] * a[1][0] + b[0][2] * a[2][0];
102 result[0][1] = b[0][0] * a[0][1] + b[0][1] * a[1][1] + b[0][2] * a[2][1];
103 result[0][2] = b[0][0] * a[0][2] + b[0][1] * a[1][2] + b[0][2] * a[2][2];
104
105 result[1][0] = b[1][0] * a[0][0] + b[1][1] * a[1][0] + b[1][2] * a[2][0];
106 result[1][1] = b[1][0] * a[0][1] + b[1][1] * a[1][1] + b[1][2] * a[2][1];
107 result[1][2] = b[1][0] * a[0][2] + b[1][1] * a[1][2] + b[1][2] * a[2][2];
108
109 result[2][0] = b[2][0] * a[0][0] + b[2][1] * a[1][0] + b[2][2] * a[2][0];
110 result[2][1] = b[2][0] * a[0][1] + b[2][1] * a[1][1] + b[2][2] * a[2][1];
111 result[2][2] = b[2][0] * a[0][2] + b[2][1] * a[1][2] + b[2][2] * a[2][2];
112#endif
113 return result;
114}
115
116template float2x2 operator*(const float2x2 &a, const float2x2 &b);
117template double2x2 operator*(const double2x2 &a, const double2x2 &b);
118template double3x3 operator*(const double3x3 &a, const double3x3 &b);
119template double4x4 operator*(const double4x4 &a, const double4x4 &b);
120
121} // namespace blender
122
124
125namespace blender::math {
126
127/* -------------------------------------------------------------------- */
130
131template<typename T, int Size> T determinant(const MatBase<T, Size, Size> &mat)
132{
133 return Eigen::Map<const Eigen::Matrix<T, Size, Size>>(mat.base_ptr()).determinant();
134}
135
136template float determinant(const float2x2 &mat);
137template float determinant(const float3x3 &mat);
138template float determinant(const float4x4 &mat);
139template double determinant(const double2x2 &mat);
140template double determinant(const double3x3 &mat);
141template double determinant(const double4x4 &mat);
142
143template<typename T> bool is_negative(const MatBase<T, 3, 3> &mat)
144{
145 return determinant(mat) < T(0);
146}
147
148template<typename T> bool is_negative(const MatBase<T, 4, 4> &mat)
149{
150 return Eigen::Map<const Eigen::Matrix<T, 3, 3>, 0, Eigen::Stride<4, 1>>(mat.base_ptr())
151 .determinant() < T(0);
152}
153
154template bool is_negative(const float3x3 &mat);
155template bool is_negative(const float4x4 &mat);
156template bool is_negative(const double3x3 &mat);
157template bool is_negative(const double4x4 &mat);
158
160
161/* -------------------------------------------------------------------- */
164
165template<typename T, int Size> MatBase<T, Size, Size> adjoint(const MatBase<T, Size, Size> &mat)
166{
168 unroll<Size>([&](auto c) {
169 unroll<Size>([&](auto r) {
170 /* Copy other cells except the "cross" to compute the determinant. */
171 MatBase<T, Size - 1, Size - 1> tmp;
172 unroll<Size>([&](auto m_c) {
173 unroll<Size>([&](auto m_r) {
174 if (m_c != c && m_r != r) {
175 int d_c = (m_c < c) ? m_c : (m_c - 1);
176 int d_r = (m_r < r) ? m_r : (m_r - 1);
177 tmp[d_c][d_r] = mat[m_c][m_r];
178 }
179 });
180 });
181 T minor = determinant(tmp);
182 /* Transpose directly to get the adjugate. Swap destination row and col. */
183 adj[r][c] = ((c + r) & 1) ? -minor : minor;
184 });
185 });
186 return adj;
187}
188
189template float2x2 adjoint(const float2x2 &mat);
190template float3x3 adjoint(const float3x3 &mat);
191template float4x4 adjoint(const float4x4 &mat);
192template double2x2 adjoint(const double2x2 &mat);
193template double3x3 adjoint(const double3x3 &mat);
194template double4x4 adjoint(const double4x4 &mat);
195
197
198/* -------------------------------------------------------------------- */
201
202template<typename T, int Size>
204{
206 Eigen::Map<const Eigen::Matrix<T, Size, Size>> M(mat.base_ptr());
207 Eigen::Map<Eigen::Matrix<T, Size, Size>> R(result.base_ptr());
208 M.computeInverseWithCheck(R, r_success, 0.0f);
209 if (!r_success) {
210 R = R.Zero();
211 }
212 return result;
213}
214
215template float2x2 invert(const float2x2 &mat, bool &r_success);
216template float3x3 invert(const float3x3 &mat, bool &r_success);
217template float4x4 invert(const float4x4 &mat, bool &r_success);
218template double2x2 invert(const double2x2 &mat, bool &r_success);
219template double3x3 invert(const double3x3 &mat, bool &r_success);
220template double4x4 invert(const double4x4 &mat, bool &r_success);
221
222template<typename T, int Size>
224{
225 /* Start by trying normal inversion first. */
226 bool success;
227 MatBase<T, Size, Size> inv = invert<T, Size>(mat, success);
228 if (success) {
229 return inv;
230 }
231
240 VecBase<T, Size> S_val;
241
242 {
243 using namespace Eigen;
244 using MatrixT = Eigen::Matrix<T, Size, Size>;
245 using VectorT = Eigen::Matrix<T, Size, 1>;
246 /* Blender and Eigen matrices are both column-major by default.
247 * Since our matrix is squared, we can use thinU/V. */
253 using MatrixDynamicT = Eigen::Matrix<T, Dynamic, Dynamic>;
254 JacobiSVD<MatrixDynamicT, NoQRPreconditioner> svd(
255 Eigen::Map<const MatrixDynamicT>(mat.base_ptr(), Size, Size), ComputeThinU | ComputeThinV);
256
257 Eigen::Map<MatrixT>(U.base_ptr()) = svd.matrixU();
258 (Eigen::Map<VectorT>(S_val)) = svd.singularValues();
259 Eigen::Map<MatrixT>(V.base_ptr()) = svd.matrixV();
260 }
261
262 /* Invert or nullify component based on epsilon comparison. */
263 unroll<Size>([&](auto i) { S_val[i] = (S_val[i] < epsilon) ? T(0) : (T(1) / S_val[i]); });
264
266 return (V * W) * transpose(U);
267}
268
269template float2x2 pseudo_invert(const float2x2 &mat, float epsilon);
270template float3x3 pseudo_invert(const float3x3 &mat, float epsilon);
271template float4x4 pseudo_invert(const float4x4 &mat, float epsilon);
272template double2x2 pseudo_invert(const double2x2 &mat, double epsilon);
273template double3x3 pseudo_invert(const double3x3 &mat, double epsilon);
274template double4x4 pseudo_invert(const double4x4 &mat, double epsilon);
275
277
278/* -------------------------------------------------------------------- */
281
291template<typename T>
292static void polar_decompose(const MatBase<T, 3, 3> &mat3,
293 MatBase<T, 3, 3> &r_U,
294 MatBase<T, 3, 3> &r_P)
295{
296 /* From svd decomposition (M = WSV*), we have:
297 * U = WV*
298 * P = VSV*
299 */
301 VecBase<T, 3> S_val;
302
303 {
304 using namespace Eigen;
305 using MatrixT = Eigen::Matrix<T, 3, 3>;
306 using VectorT = Eigen::Matrix<T, 3, 1>;
307 /* Blender and Eigen matrices are both column-major by default.
308 * Since our matrix is squared, we can use thinU/V. */
313 using MatrixDynamicT = Eigen::Matrix<T, Dynamic, Dynamic>;
314 JacobiSVD<MatrixDynamicT, NoQRPreconditioner> svd(
315 Eigen::Map<const MatrixDynamicT>(mat3.base_ptr(), 3, 3), ComputeThinU | ComputeThinV);
316
317 Eigen::Map<MatrixT>(W.base_ptr()) = svd.matrixU();
318 (Eigen::Map<VectorT>(S_val)) = svd.singularValues();
319 Eigen::Map<MatrixT>(V.base_ptr()) = svd.matrixV();
320 }
321
324
325 r_U = W * Vt;
326 r_P = (V * S) * Vt;
327}
328
330
331/* -------------------------------------------------------------------- */
334
335template<typename T>
337{
338 using Mat3T = MatBase<T, 3, 3>;
339 /* 'Rotation' component ('U' part of polar decomposition,
340 * the closest orthogonal matrix to M3 rot/scale
341 * transformation matrix), spherically interpolated. */
342 Mat3T U_A, U_B;
343 /* 'Scaling' component ('P' part of polar decomposition, i.e. scaling in U-defined space),
344 * linearly interpolated. */
345 Mat3T P_A, P_B;
346
347 polar_decompose(A, U_A, P_A);
348 polar_decompose(B, U_B, P_B);
349
350 /* Quaternions cannot represent an axis flip. If such a singularity is detected, choose a
351 * different decomposition of the matrix that still satisfies A = U_A * P_A but which has a
352 * positive determinant and thus no axis flips. This resolves #77154.
353 *
354 * Note that a flip of two axes is just a rotation of 180 degrees around the third axis, and
355 * three flipped axes are just an 180 degree rotation + a single axis flip. It is thus sufficient
356 * to solve this problem for single axis flips. */
357 if (is_negative(U_A)) {
358 U_A = -U_A;
359 P_A = -P_A;
360 }
361 if (is_negative(U_B)) {
362 U_B = -U_B;
363 P_B = -P_B;
364 }
365
368 QuaternionBase<T> quat = math::interpolate(quat_A, quat_B, t);
369 Mat3T U = from_rotation<Mat3T>(quat);
370
371 Mat3T P = interpolate_linear(P_A, P_B, t);
372 /* And we reconstruct rot/scale matrix from interpolated polar components */
373 return U * P;
374}
375
376template float3x3 interpolate(const float3x3 &a, const float3x3 &b, float t);
377template double3x3 interpolate(const double3x3 &a, const double3x3 &b, double t);
378
379template<typename T>
381{
384
385 /* Location component, linearly interpolated. */
386 const auto &loc_a = static_cast<const MatBase<T, 4, 4> &>(A).location();
387 const auto &loc_b = static_cast<const MatBase<T, 4, 4> &>(B).location();
388 result.location() = interpolate(loc_a, loc_b, t);
389
390 return result;
391}
392
393template float4x4 interpolate(const float4x4 &a, const float4x4 &b, float t);
394template double4x4 interpolate(const double4x4 &a, const double4x4 &b, double t);
395
396template<typename T>
398{
399 using QuaternionT = QuaternionBase<T>;
400 using Vec3T = typename MatBase<T, 3, 3>::vec3_type;
401
402 Vec3T a_scale, b_scale;
403 QuaternionT a_quat, b_quat;
404 to_rot_scale<true>(a, a_quat, a_scale);
405 to_rot_scale<true>(b, b_quat, b_scale);
406
407 const Vec3T scale = interpolate(a_scale, b_scale, t);
408 const QuaternionT rotation = interpolate(a_quat, b_quat, t);
409 return from_rot_scale<MatBase<T, 3, 3>>(rotation, scale);
410}
411
412template float3x3 interpolate_fast(const float3x3 &a, const float3x3 &b, float t);
413template double3x3 interpolate_fast(const double3x3 &a, const double3x3 &b, double t);
414
415template<typename T>
417{
418 using QuaternionT = QuaternionBase<T>;
419 using Vec3T = typename MatBase<T, 3, 3>::vec3_type;
420
421 Vec3T a_loc, b_loc;
422 Vec3T a_scale, b_scale;
423 QuaternionT a_quat, b_quat;
424 to_loc_rot_scale<true>(a, a_loc, a_quat, a_scale);
425 to_loc_rot_scale<true>(b, b_loc, b_quat, b_scale);
426
427 const Vec3T location = interpolate(a_loc, b_loc, t);
428 const Vec3T scale = interpolate(a_scale, b_scale, t);
429 const QuaternionT rotation = interpolate(a_quat, b_quat, t);
430 return from_loc_rot_scale<MatBase<T, 4, 4>>(location, rotation, scale);
431}
432
433template float4x4 interpolate_fast(const float4x4 &a, const float4x4 &b, float t);
434template double4x4 interpolate_fast(const double4x4 &a, const double4x4 &b, double t);
435
437
438/* -------------------------------------------------------------------- */
441
443{
444 float3x3 n_mat = normalize(mat);
445 /* Rotate z-axis of matrix to z-axis. */
446 float3 z_axis = n_mat.z_axis();
447
448 /* Cross product with (0,0,1). */
449 float3 nor = normalize(float3(z_axis.y, -z_axis.x, 0.0f));
450
451 float ha = 0.5f * math::safe_acos(z_axis.z);
452 /* `nor` negative here, but why? */
453 Quaternion q1(math::cos(ha), -nor * math::sin(ha));
454
455 /* Rotate back x-axis from mat, using inverse q1. */
456 float3 x_axis = transform_point(conjugate(q1), n_mat.x_axis());
457
458 /* And align x-axes. */
459 float ha2 = 0.5f * math::atan2(x_axis.y, x_axis.x);
460 Quaternion q2(math::cos(ha2), 0.0f, 0.0f, math::sin(ha2));
461
462 return q1 * q2;
463}
464
466
467/* -------------------------------------------------------------------- */
470
471namespace detail {
472
473template void normalized_to_eul2(const float3x3 &mat,
474 Euler3Base<float> &eul1,
475 Euler3Base<float> &eul2);
476template void normalized_to_eul2(const float3x3 &mat,
477 EulerXYZBase<float> &eul1,
478 EulerXYZBase<float> &eul2);
479template void normalized_to_eul2(const double3x3 &mat,
480 EulerXYZBase<double> &eul1,
481 EulerXYZBase<double> &eul2);
482
483template QuaternionBase<float> normalized_to_quat_with_checks(const float3x3 &mat);
484template QuaternionBase<double> normalized_to_quat_with_checks(const double3x3 &mat);
485
486template MatBase<float, 2, 2> from_rotation(const AngleRadian &rotation);
487template MatBase<float, 3, 3> from_rotation(const AngleRadian &rotation);
488template MatBase<float, 3, 3> from_rotation(const EulerXYZ &rotation);
489template MatBase<float, 4, 4> from_rotation(const EulerXYZ &rotation);
490template MatBase<float, 3, 3> from_rotation(const Euler3 &rotation);
491template MatBase<float, 4, 4> from_rotation(const Euler3 &rotation);
492template MatBase<float, 3, 3> from_rotation(const Quaternion &rotation);
493template MatBase<float, 4, 4> from_rotation(const Quaternion &rotation);
494template MatBase<float, 3, 3> from_rotation(const AxisAngle &rotation);
495template MatBase<float, 4, 4> from_rotation(const AxisAngle &rotation);
496template MatBase<float, 3, 3> from_rotation(const AxisAngleCartesian &rotation);
497template MatBase<float, 4, 4> from_rotation(const AxisAngleCartesian &rotation);
498
499} // namespace detail
500
501template float3 transform_point(const float3x3 &mat, const float3 &point);
502template float3 transform_point(const float4x4 &mat, const float3 &point);
503template float3 transform_direction(const float3x3 &mat, const float3 &direction);
504template float3 transform_direction(const float4x4 &mat, const float3 &direction);
505template float3 project_point(const float4x4 &mat, const float3 &point);
506template float2 project_point(const float3x3 &mat, const float2 &point);
507
508namespace projection {
509
510template float4x4 orthographic(
511 float left, float right, float bottom, float top, float near_clip, float far_clip);
512template float4x4 perspective(
513 float left, float right, float bottom, float top, float near_clip, float far_clip);
515 float left, float right, float bottom, float top, float near_clip);
516
517} // namespace projection
518
520
525template<typename T>
526bool is_similarity_transform(const MatBase<T, 3, 3> &matrix, const T &epsilon = 1e-6)
527{
528 if (math::abs(math::dot(matrix[0], matrix[1])) > epsilon) {
529 return false;
530 }
531 if (math::abs(math::dot(matrix[0], matrix[2])) > epsilon) {
532 return false;
533 }
534 if (math::abs(math::dot(matrix[1], matrix[2])) > epsilon) {
535 return false;
536 }
537 const float length_0 = math::length_squared(matrix[0]);
538 const float length_1 = math::length_squared(matrix[1]);
539 const float length_2 = math::length_squared(matrix[2]);
540 if (math::abs(length_0 - length_1) > epsilon) {
541 return false;
542 }
543 if (math::abs(length_0 - length_2) > epsilon) {
544 return false;
545 }
546 if (math::abs(length_1 - length_2) > epsilon) {
547 return false;
548 }
549 return true;
550}
551
553{
555 return;
556 }
557 const float3x3 normal_transform = math::transpose(math::invert(transform));
558 if (is_similarity_transform(normal_transform)) {
559 const float3x3 normalized_transform = math::normalize(normal_transform);
560 threading::parallel_for(normals.index_range(), 1024, [&](const IndexRange range) {
561 for (float3 &normal : normals.slice(range)) {
562 normal = normalized_transform * normal;
563 }
564 });
565 }
566 else {
567 threading::parallel_for(normals.index_range(), 1024, [&](const IndexRange range) {
568 for (float3 &normal : normals.slice(range)) {
569 normal = math::normalize(normal_transform * normal);
570 }
571 });
572 }
573}
574
576{
578 dst.copy_from(src);
579 return;
580 }
581 const float3x3 normal_transform = math::transpose(math::invert(transform));
582 if (is_similarity_transform(normal_transform)) {
583 const float3x3 normalized_transform = math::normalize(normal_transform);
584 threading::parallel_for(src.index_range(), 1024, [&](const IndexRange range) {
585 for (const int i : range) {
586 dst[i] = normalized_transform * src[i];
587 }
588 });
589 }
590 else {
591 threading::parallel_for(src.index_range(), 1024, [&](const IndexRange range) {
592 for (const int i : range) {
593 dst[i] = math::normalize(normal_transform * src[i]);
594 }
595 });
596 }
597}
598
600{
602}
603
605 const float4x4 &transform,
607{
608 for (const int64_t i : src.index_range()) {
609 dst[i] = math::transform_point(transform, src[i]);
610 }
611}
612
614 const float4x4 &transform,
616 const bool use_threading)
617{
619 dst.copy_from(src);
620 }
621 else {
622 if (use_threading) {
623 threading::parallel_for(src.index_range(), 1024, [&](const IndexRange range) {
624 transform_points_no_threading(src.slice(range), transform, dst.slice(range));
625 });
626 }
627 else {
629 }
630 }
631}
632
634{
635 for (float3 &position : points) {
636 position = math::transform_point(transform, position);
637 }
638}
639
641 MutableSpan<float3> points,
642 const bool use_threading)
643{
645 return;
646 }
647 if (use_threading) {
648 threading::parallel_for(points.index_range(), 1024, [&](const IndexRange range) {
649 transform_points_no_threading(transform, points.slice(range));
650 });
651 }
652 else {
654 }
655}
656
657} // namespace blender::math
#define A0
Definition RandGen.cpp:26
#define A2
Definition RandGen.cpp:28
#define A1
Definition RandGen.cpp:27
#define U
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
#define A
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
long long int int64_t
btMatrix3x3 adjoint() const
Return the adjoint of the matrix.
btScalar determinant() const
Return the determinant of the matrix.
static T sum(const btAlignedObjectArray< T > &items)
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:739
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
static float normals[][3]
uint nor
uint top
VecBase< float, D > normalize(VecOp< float, D >) RET
MatBase< R, C > transpose(MatBase< C, R >) RET
MatBase< 2, 2 > float2x2
MatBase< 4, 4 > float4x4
MatBase< 3, 3 > float3x3
VecBase< float, 3 > float3
CCL_NAMESPACE_BEGIN ccl_device float invert(const float color, const float factor)
Definition invert.h:11
#define M
static int left
#define T
#define B
#define R
MatBase< T, 4, 4 > perspective_infinite(T left, T right, T bottom, T top, T near_clip)
Create a perspective projection matrix using OpenGL coordinate convention: Maps each axis range to [-...
QuaternionBase< T > conjugate(const QuaternionBase< T > &a)
QuaternionBase< float > Quaternion
T length_squared(const VecBase< T, Size > &a)
T cos(const AngleRadianBase< T > &a)
MatBase< T, NumCol, NumRow > transpose(const MatBase< T, NumRow, NumCol > &mat)
QuaternionBase< T > to_quaternion(const AxisAngleBase< T, AngleT > &axis_angle)
bool is_negative(const MatBase< T, 3, 3 > &mat)
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
static bool skip_transform(const float4x4 &transform)
Quaternion to_quaternion_legacy(const float3x3 &mat)
static void transform_points_no_threading(const Span< float3 > src, const float4x4 &transform, MutableSpan< float3 > dst)
MatBase< T, Size, Size > pseudo_invert(const MatBase< T, Size, Size > &mat, T epsilon=1e-8)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
CartesianBasis invert(const CartesianBasis &basis)
MatT from_scale(const VecBase< typename MatT::base_type, ScaleDim > &scale)
T interpolate(const T &a, const T &b, const FactorT &t)
void transform_normals(const float3x3 &transform, MutableSpan< float3 > normals)
bool is_similarity_transform(const MatBase< T, 3, 3 > &matrix, const T &epsilon=1e-6)
T atan2(const T &y, const T &x)
MatBase< T, 3, 3 > interpolate_fast(const MatBase< T, 3, 3 > &a, const MatBase< T, 3, 3 > &b, T t)
T safe_acos(const T &a)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
static void polar_decompose(const MatBase< T, 3, 3 > &mat3, MatBase< T, 3, 3 > &r_U, MatBase< T, 3, 3 > &r_P)
bool is_equal(const MatBase< T, NumCol, NumRow > &a, const MatBase< T, NumCol, NumRow > &b, const T epsilon=T(0))
T sin(const AngleRadianBase< T > &a)
void to_rot_scale(const MatBase< T, 2, 2 > &mat, AngleRadianBase< T > &r_rotation, VecBase< T, 2 > &r_scale)
T abs(const T &a)
MatBase< T, NumCol, NumRow > interpolate_linear(const MatBase< T, NumCol, NumRow > &a, const MatBase< T, NumCol, NumRow > &b, T t)
void to_loc_rot_scale(const MatBase< T, 3, 3 > &mat, VecBase< T, 2 > &r_location, AngleRadianBase< T > &r_rotation, VecBase< T, 2 > &r_scale)
MatT from_rot_scale(const RotationT &rotation, const VectorT &scale)
MatT from_rotation(const RotationT &rotation)
void transform_points(const float4x4 &transform, MutableSpan< float3 > points, bool use_threading=true)
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)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
MatBase< float, 2, 2 > float2x2
MatBase< float, 4, 4 > float4x4
MatBase< double, 3, 3 > double3x3
MatBase< double, 2, 2 > double2x2
MatBase< float, 3, 3 > float3x3
void unroll(Fn fn)
Definition BLI_unroll.hh:25
VecBase< float, 3 > float3
MatBase< T, B_NumCol, A_NumRow > operator*(const MatBase< T, A_NumCol, A_NumRow > &a, const MatBase< T, B_NumCol, B_NumRow > &b)
MatBase< double, 4, 4 > double4x4
VecBase< T, 3 > vec3_type
const T * base_ptr() const
i
Definition text_draw.cc:230
ccl_device_inline float3 transform_direction(const ccl_private Transform *t, const float3 a)
Definition transform.h:127
ccl_device_inline float3 transform_point(const ccl_private Transform *t, const float3 a)
Definition transform.h:56
CCL_NAMESPACE_BEGIN struct Window V