2022-02-11 09:07:11 +11:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
* \ingroup bli
|
2011-02-27 20:37:56 +00:00
|
|
|
*/
|
|
|
|
|
2009-11-09 22:42:41 +00:00
|
|
|
#include "BLI_math.h"
|
|
|
|
|
2013-12-06 03:46:27 +11:00
|
|
|
#include "BLI_strict_flags.h"
|
|
|
|
|
2019-10-22 15:21:59 +11:00
|
|
|
#ifndef MATH_STANDALONE
|
|
|
|
# include "eigen_capi.h"
|
|
|
|
#endif
|
2018-05-31 16:36:20 +02:00
|
|
|
|
2009-11-09 22:42:41 +00:00
|
|
|
/********************************* Init **************************************/
|
|
|
|
|
2014-09-06 11:19:34 +10:00
|
|
|
void zero_m2(float m[2][2])
|
|
|
|
{
|
|
|
|
memset(m, 0, sizeof(float[2][2]));
|
|
|
|
}
|
|
|
|
|
2009-11-10 19:13:05 +00:00
|
|
|
void zero_m3(float m[3][3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2014-09-06 11:19:34 +10:00
|
|
|
memset(m, 0, sizeof(float[3][3]));
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2009-11-10 19:13:05 +00:00
|
|
|
void zero_m4(float m[4][4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2014-09-06 11:19:34 +10:00
|
|
|
memset(m, 0, sizeof(float[4][4]));
|
|
|
|
}
|
|
|
|
|
|
|
|
void unit_m2(float m[2][2])
|
|
|
|
{
|
|
|
|
m[0][0] = m[1][1] = 1.0f;
|
|
|
|
m[0][1] = 0.0f;
|
|
|
|
m[1][0] = 0.0f;
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2012-12-11 14:29:01 +00:00
|
|
|
void unit_m3(float m[3][3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2014-07-30 11:00:59 +02:00
|
|
|
m[0][0] = m[1][1] = m[2][2] = 1.0f;
|
|
|
|
m[0][1] = m[0][2] = 0.0f;
|
|
|
|
m[1][0] = m[1][2] = 0.0f;
|
|
|
|
m[2][0] = m[2][1] = 0.0f;
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2012-12-11 14:29:01 +00:00
|
|
|
void unit_m4(float m[4][4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2014-07-30 11:00:59 +02:00
|
|
|
m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f;
|
|
|
|
m[0][1] = m[0][2] = m[0][3] = 0.0f;
|
|
|
|
m[1][0] = m[1][2] = m[1][3] = 0.0f;
|
|
|
|
m[2][0] = m[2][1] = m[2][3] = 0.0f;
|
|
|
|
m[3][0] = m[3][1] = m[3][2] = 0.0f;
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2019-08-20 21:09:55 +08:00
|
|
|
void unit_m4_db(double m[4][4])
|
|
|
|
{
|
|
|
|
m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f;
|
|
|
|
m[0][1] = m[0][2] = m[0][3] = 0.0f;
|
|
|
|
m[1][0] = m[1][2] = m[1][3] = 0.0f;
|
|
|
|
m[2][0] = m[2][1] = m[2][3] = 0.0f;
|
|
|
|
m[3][0] = m[3][1] = m[3][2] = 0.0f;
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void copy_m2_m2(float m1[2][2], const float m2[2][2])
|
2014-09-06 11:19:34 +10:00
|
|
|
{
|
|
|
|
memcpy(m1, m2, sizeof(float[2][2]));
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void copy_m3_m3(float m1[3][3], const float m2[3][3])
|
2012-03-25 12:41:58 +00:00
|
|
|
{
|
2009-11-09 22:42:41 +00:00
|
|
|
/* destination comes first: */
|
2014-09-06 11:19:34 +10:00
|
|
|
memcpy(m1, m2, sizeof(float[3][3]));
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void copy_m4_m4(float m1[4][4], const float m2[4][4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2014-09-06 11:19:34 +10:00
|
|
|
memcpy(m1, m2, sizeof(float[4][4]));
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2019-08-20 21:09:55 +08:00
|
|
|
void copy_m4_m4_db(double m1[4][4], const double m2[4][4])
|
|
|
|
{
|
|
|
|
memcpy(m1, m2, sizeof(double[4][4]));
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void copy_m3_m4(float m1[3][3], const float m2[4][4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2012-03-25 12:41:58 +00:00
|
|
|
m1[0][0] = m2[0][0];
|
|
|
|
m1[0][1] = m2[0][1];
|
|
|
|
m1[0][2] = m2[0][2];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
m1[1][0] = m2[1][0];
|
|
|
|
m1[1][1] = m2[1][1];
|
|
|
|
m1[1][2] = m2[1][2];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
m1[2][0] = m2[2][0];
|
|
|
|
m1[2][1] = m2[2][1];
|
|
|
|
m1[2][2] = m2[2][2];
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void copy_m4_m3(float m1[4][4], const float m2[3][3]) /* no clear */
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2012-03-25 12:41:58 +00:00
|
|
|
m1[0][0] = m2[0][0];
|
|
|
|
m1[0][1] = m2[0][1];
|
|
|
|
m1[0][2] = m2[0][2];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
m1[1][0] = m2[1][0];
|
|
|
|
m1[1][1] = m2[1][1];
|
|
|
|
m1[1][2] = m2[1][2];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2014-07-30 11:00:59 +02:00
|
|
|
m1[2][0] = m2[2][0];
|
|
|
|
m1[2][1] = m2[2][1];
|
|
|
|
m1[2][2] = m2[2][2];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
|
|
|
/* Reevan's Bugfix */
|
2014-07-30 11:00:59 +02:00
|
|
|
m1[0][3] = 0.0f;
|
|
|
|
m1[1][3] = 0.0f;
|
|
|
|
m1[2][3] = 0.0f;
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2014-02-02 01:27:06 +11:00
|
|
|
m1[3][0] = 0.0f;
|
|
|
|
m1[3][1] = 0.0f;
|
|
|
|
m1[3][2] = 0.0f;
|
2014-07-30 11:00:59 +02:00
|
|
|
m1[3][3] = 1.0f;
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-02-20 12:48:42 +11:00
|
|
|
void copy_m3_m2(float m1[3][3], const float m2[2][2])
|
|
|
|
{
|
|
|
|
m1[0][0] = m2[0][0];
|
|
|
|
m1[0][1] = m2[0][1];
|
|
|
|
m1[0][2] = 0.0f;
|
|
|
|
|
|
|
|
m1[1][0] = m2[1][0];
|
|
|
|
m1[1][1] = m2[1][1];
|
|
|
|
m1[1][2] = 0.0f;
|
|
|
|
|
|
|
|
m1[2][0] = 0.0f;
|
|
|
|
m1[2][1] = 0.0f;
|
|
|
|
m1[2][2] = 1.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void copy_m4_m2(float m1[4][4], const float m2[2][2])
|
|
|
|
{
|
|
|
|
m1[0][0] = m2[0][0];
|
|
|
|
m1[0][1] = m2[0][1];
|
|
|
|
m1[0][2] = 0.0f;
|
|
|
|
m1[0][3] = 0.0f;
|
|
|
|
|
|
|
|
m1[1][0] = m2[1][0];
|
|
|
|
m1[1][1] = m2[1][1];
|
|
|
|
m1[1][2] = 0.0f;
|
|
|
|
m1[1][3] = 0.0f;
|
|
|
|
|
|
|
|
m1[2][0] = 0.0f;
|
|
|
|
m1[2][1] = 0.0f;
|
|
|
|
m1[2][2] = 1.0f;
|
|
|
|
m1[2][3] = 0.0f;
|
|
|
|
|
|
|
|
m1[3][0] = 0.0f;
|
|
|
|
m1[3][1] = 0.0f;
|
|
|
|
m1[3][2] = 0.0f;
|
|
|
|
m1[3][3] = 1.0f;
|
|
|
|
}
|
|
|
|
|
2020-11-21 16:06:02 +03:00
|
|
|
void copy_m3d_m3(double m1[3][3], const float m2[3][3])
|
|
|
|
{
|
|
|
|
m1[0][0] = m2[0][0];
|
|
|
|
m1[0][1] = m2[0][1];
|
|
|
|
m1[0][2] = m2[0][2];
|
|
|
|
|
|
|
|
m1[1][0] = m2[1][0];
|
|
|
|
m1[1][1] = m2[1][1];
|
|
|
|
m1[1][2] = m2[1][2];
|
|
|
|
|
|
|
|
m1[2][0] = m2[2][0];
|
|
|
|
m1[2][1] = m2[2][1];
|
|
|
|
m1[2][2] = m2[2][2];
|
|
|
|
}
|
|
|
|
|
2019-08-20 21:09:55 +08:00
|
|
|
void copy_m4d_m4(double m1[4][4], const float m2[4][4])
|
|
|
|
{
|
|
|
|
m1[0][0] = m2[0][0];
|
|
|
|
m1[0][1] = m2[0][1];
|
|
|
|
m1[0][2] = m2[0][2];
|
|
|
|
m1[0][3] = m2[0][3];
|
|
|
|
|
|
|
|
m1[1][0] = m2[1][0];
|
|
|
|
m1[1][1] = m2[1][1];
|
|
|
|
m1[1][2] = m2[1][2];
|
|
|
|
m1[1][3] = m2[1][3];
|
|
|
|
|
|
|
|
m1[2][0] = m2[2][0];
|
|
|
|
m1[2][1] = m2[2][1];
|
|
|
|
m1[2][2] = m2[2][2];
|
|
|
|
m1[2][3] = m2[2][3];
|
|
|
|
|
|
|
|
m1[3][0] = m2[3][0];
|
|
|
|
m1[3][1] = m2[3][1];
|
|
|
|
m1[3][2] = m2[3][2];
|
|
|
|
m1[3][3] = m2[3][3];
|
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void copy_m3_m3d(float m1[3][3], const double m2[3][3])
|
2013-10-20 12:08:51 +00:00
|
|
|
{
|
|
|
|
/* Keep it stupid simple for better data flow in CPU. */
|
2020-09-04 20:59:13 +02:00
|
|
|
m1[0][0] = (float)m2[0][0];
|
|
|
|
m1[0][1] = (float)m2[0][1];
|
|
|
|
m1[0][2] = (float)m2[0][2];
|
2013-10-20 12:08:51 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
m1[1][0] = (float)m2[1][0];
|
|
|
|
m1[1][1] = (float)m2[1][1];
|
|
|
|
m1[1][2] = (float)m2[1][2];
|
2013-10-20 12:08:51 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
m1[2][0] = (float)m2[2][0];
|
|
|
|
m1[2][1] = (float)m2[2][1];
|
|
|
|
m1[2][2] = (float)m2[2][2];
|
2013-10-20 12:08:51 +00:00
|
|
|
}
|
|
|
|
|
2012-12-11 14:29:01 +00:00
|
|
|
void swap_m3m3(float m1[3][3], float m2[3][3])
|
2011-01-31 20:02:51 +00:00
|
|
|
{
|
|
|
|
float t;
|
|
|
|
int i, j;
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
for (i = 0; i < 3; i++) {
|
2011-01-31 20:02:51 +00:00
|
|
|
for (j = 0; j < 3; j++) {
|
2012-03-25 12:41:58 +00:00
|
|
|
t = m1[i][j];
|
2011-01-31 20:02:51 +00:00
|
|
|
m1[i][j] = m2[i][j];
|
|
|
|
m2[i][j] = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-11 14:29:01 +00:00
|
|
|
void swap_m4m4(float m1[4][4], float m2[4][4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
float t;
|
|
|
|
int i, j;
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
for (i = 0; i < 4; i++) {
|
2009-11-09 22:42:41 +00:00
|
|
|
for (j = 0; j < 4; j++) {
|
2012-03-25 12:41:58 +00:00
|
|
|
t = m1[i][j];
|
2009-11-09 22:42:41 +00:00
|
|
|
m1[i][j] = m2[i][j];
|
|
|
|
m2[i][j] = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-13 11:27:09 +02:00
|
|
|
void shuffle_m4(float R[4][4], const int index[4])
|
2020-02-15 01:49:50 +01:00
|
|
|
{
|
|
|
|
zero_m4(R);
|
|
|
|
for (int k = 0; k < 4; k++) {
|
|
|
|
if (index[k] >= 0) {
|
|
|
|
R[index[k]][k] = 1.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-09 22:42:41 +00:00
|
|
|
/******************************** Arithmetic *********************************/
|
|
|
|
|
2016-09-25 14:27:48 +02:00
|
|
|
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
|
|
|
|
{
|
2019-03-27 13:16:10 +11:00
|
|
|
if (A == R) {
|
2016-09-25 14:27:48 +02:00
|
|
|
mul_m4_m4_post(R, B);
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
|
|
|
else if (B == R) {
|
2016-09-25 14:27:48 +02:00
|
|
|
mul_m4_m4_pre(R, A);
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
|
|
|
else {
|
2016-09-25 14:27:48 +02:00
|
|
|
mul_m4_m4m4_uniq(R, A, B);
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
2016-09-25 14:27:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void mul_m4_m4m4_uniq(float R[4][4], const float A[4][4], const float B[4][4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2020-11-06 12:30:59 +11:00
|
|
|
BLI_assert(!ELEM(R, A, B));
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2021-07-23 16:56:00 +10:00
|
|
|
/* Matrix product: `R[j][k] = A[j][i] . B[i][k]`. */
|
2021-02-14 14:20:51 +01:00
|
|
|
#ifdef BLI_HAVE_SSE2
|
2018-06-01 18:10:43 +02:00
|
|
|
__m128 A0 = _mm_loadu_ps(A[0]);
|
|
|
|
__m128 A1 = _mm_loadu_ps(A[1]);
|
|
|
|
__m128 A2 = _mm_loadu_ps(A[2]);
|
|
|
|
__m128 A3 = _mm_loadu_ps(A[3]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-01 18:10:43 +02:00
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
__m128 B0 = _mm_set1_ps(B[i][0]);
|
|
|
|
__m128 B1 = _mm_set1_ps(B[i][1]);
|
|
|
|
__m128 B2 = _mm_set1_ps(B[i][2]);
|
|
|
|
__m128 B3 = _mm_set1_ps(B[i][3]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-01 18:10:43 +02:00
|
|
|
__m128 sum = _mm_add_ps(_mm_add_ps(_mm_mul_ps(B0, A0), _mm_mul_ps(B1, A1)),
|
|
|
|
_mm_add_ps(_mm_mul_ps(B2, A2), _mm_mul_ps(B3, A3)));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-01 18:10:43 +02:00
|
|
|
_mm_storeu_ps(R[i], sum);
|
|
|
|
}
|
2018-05-31 16:36:20 +02:00
|
|
|
#else
|
2016-09-25 14:27:48 +02:00
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-09-25 14:27:48 +02:00
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-09-25 14:27:48 +02:00
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-09-25 14:27:48 +02:00
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
2018-05-31 16:36:20 +02:00
|
|
|
#endif
|
2016-09-25 14:27:48 +02:00
|
|
|
}
|
|
|
|
|
2019-08-20 21:09:55 +08:00
|
|
|
void mul_m4_m4m4_db_uniq(double R[4][4], const double A[4][4], const double B[4][4])
|
|
|
|
{
|
2020-11-06 12:30:59 +11:00
|
|
|
BLI_assert(!ELEM(R, A, B));
|
2019-08-20 21:09:55 +08:00
|
|
|
|
2021-07-23 16:56:00 +10:00
|
|
|
/* Matrix product: `R[j][k] = A[j][i] . B[i][k]`. */
|
2019-08-20 21:09:55 +08:00
|
|
|
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
}
|
|
|
|
|
|
|
|
void mul_m4db_m4db_m4fl_uniq(double R[4][4], const double A[4][4], const float B[4][4])
|
|
|
|
{
|
2019-08-20 23:41:41 +10:00
|
|
|
/* Remove second check since types don't match. */
|
2020-11-06 12:30:59 +11:00
|
|
|
BLI_assert(!ELEM(R, A /*, B */));
|
2019-08-20 21:09:55 +08:00
|
|
|
|
2021-07-23 16:56:00 +10:00
|
|
|
/* Matrix product: `R[j][k] = A[j][i] . B[i][k]`. */
|
2019-08-20 21:09:55 +08:00
|
|
|
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
R[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];
|
|
|
|
}
|
|
|
|
|
2016-09-25 14:27:48 +02:00
|
|
|
void mul_m4_m4_pre(float R[4][4], const float A[4][4])
|
|
|
|
{
|
|
|
|
BLI_assert(A != R);
|
|
|
|
float B[4][4];
|
|
|
|
copy_m4_m4(B, R);
|
|
|
|
mul_m4_m4m4_uniq(R, A, B);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mul_m4_m4_post(float R[4][4], const float B[4][4])
|
|
|
|
{
|
|
|
|
BLI_assert(B != R);
|
|
|
|
float A[4][4];
|
|
|
|
copy_m4_m4(A, R);
|
|
|
|
mul_m4_m4m4_uniq(R, A, B);
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2016-09-25 18:48:11 +02:00
|
|
|
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2019-03-27 13:16:10 +11:00
|
|
|
if (A == R) {
|
2016-09-25 18:48:11 +02:00
|
|
|
mul_m3_m3_post(R, B);
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
|
|
|
else if (B == R) {
|
2016-09-25 18:48:11 +02:00
|
|
|
mul_m3_m3_pre(R, A);
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
|
|
|
else {
|
2016-09-25 18:48:11 +02:00
|
|
|
mul_m3_m3m3_uniq(R, A, B);
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
2016-09-25 18:48:11 +02:00
|
|
|
}
|
2010-04-15 10:28:32 +00:00
|
|
|
|
2016-09-25 18:48:11 +02:00
|
|
|
void mul_m3_m3_pre(float R[3][3], const float A[3][3])
|
|
|
|
{
|
|
|
|
BLI_assert(A != R);
|
|
|
|
float B[3][3];
|
|
|
|
copy_m3_m3(B, R);
|
|
|
|
mul_m3_m3m3_uniq(R, A, B);
|
|
|
|
}
|
2010-04-15 10:28:32 +00:00
|
|
|
|
2016-09-25 18:48:11 +02:00
|
|
|
void mul_m3_m3_post(float R[3][3], const float B[3][3])
|
|
|
|
{
|
|
|
|
BLI_assert(B != R);
|
|
|
|
float A[3][3];
|
|
|
|
copy_m3_m3(A, R);
|
|
|
|
mul_m3_m3m3_uniq(R, A, B);
|
|
|
|
}
|
2010-04-15 10:28:32 +00:00
|
|
|
|
2016-09-25 18:48:11 +02:00
|
|
|
void mul_m3_m3m3_uniq(float R[3][3], const float A[3][3], const float B[3][3])
|
|
|
|
{
|
2020-11-06 12:30:59 +11:00
|
|
|
BLI_assert(!ELEM(R, A, B));
|
2010-04-15 10:28:32 +00:00
|
|
|
|
2016-09-25 18:48:11 +02:00
|
|
|
R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0];
|
|
|
|
R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1];
|
|
|
|
R[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + B[0][2] * A[2][2];
|
|
|
|
|
|
|
|
R[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + B[1][2] * A[2][0];
|
|
|
|
R[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + B[1][2] * A[2][1];
|
|
|
|
R[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + B[1][2] * A[2][2];
|
|
|
|
|
|
|
|
R[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + B[2][2] * A[2][0];
|
|
|
|
R[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + B[2][2] * A[2][1];
|
|
|
|
R[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + B[2][2] * A[2][2];
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void mul_m4_m4m3(float R[4][4], const float A[4][4], const float B[3][3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
float B_[3][3], A_[4][4];
|
2011-12-15 16:09:57 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
/* copy so it works when R is the same pointer as A or B */
|
2016-09-24 16:21:38 +02:00
|
|
|
/* TODO: avoid copying when matrices are different */
|
2020-09-04 20:59:13 +02:00
|
|
|
copy_m4_m4(A_, A);
|
|
|
|
copy_m3_m3(B_, B);
|
2011-12-15 16:09:57 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
R[0][0] = B_[0][0] * A_[0][0] + B_[0][1] * A_[1][0] + B_[0][2] * A_[2][0];
|
|
|
|
R[0][1] = B_[0][0] * A_[0][1] + B_[0][1] * A_[1][1] + B_[0][2] * A_[2][1];
|
|
|
|
R[0][2] = B_[0][0] * A_[0][2] + B_[0][1] * A_[1][2] + B_[0][2] * A_[2][2];
|
|
|
|
R[1][0] = B_[1][0] * A_[0][0] + B_[1][1] * A_[1][0] + B_[1][2] * A_[2][0];
|
|
|
|
R[1][1] = B_[1][0] * A_[0][1] + B_[1][1] * A_[1][1] + B_[1][2] * A_[2][1];
|
|
|
|
R[1][2] = B_[1][0] * A_[0][2] + B_[1][1] * A_[1][2] + B_[1][2] * A_[2][2];
|
|
|
|
R[2][0] = B_[2][0] * A_[0][0] + B_[2][1] * A_[1][0] + B_[2][2] * A_[2][0];
|
|
|
|
R[2][1] = B_[2][0] * A_[0][1] + B_[2][1] * A_[1][1] + B_[2][2] * A_[2][1];
|
|
|
|
R[2][2] = B_[2][0] * A_[0][2] + B_[2][1] * A_[1][2] + B_[2][2] * A_[2][2];
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
2009-11-10 19:13:05 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void mul_m3_m3m4(float R[3][3], const float A[3][3], const float B[4][4])
|
2019-04-14 18:13:39 +03:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
float B_[4][4], A_[3][3];
|
2019-04-14 18:13:39 +03:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
/* copy so it works when R is the same pointer as A or B */
|
2019-04-14 18:13:39 +03:00
|
|
|
/* TODO: avoid copying when matrices are different */
|
2020-09-04 20:59:13 +02:00
|
|
|
copy_m3_m3(A_, A);
|
|
|
|
copy_m4_m4(B_, B);
|
2019-04-14 18:13:39 +03:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
/* R[i][j] = B_[i][k] * A_[k][j] */
|
|
|
|
R[0][0] = B_[0][0] * A_[0][0] + B_[0][1] * A_[1][0] + B_[0][2] * A_[2][0];
|
|
|
|
R[0][1] = B_[0][0] * A_[0][1] + B_[0][1] * A_[1][1] + B_[0][2] * A_[2][1];
|
|
|
|
R[0][2] = B_[0][0] * A_[0][2] + B_[0][1] * A_[1][2] + B_[0][2] * A_[2][2];
|
2019-04-14 18:13:39 +03:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
R[1][0] = B_[1][0] * A_[0][0] + B_[1][1] * A_[1][0] + B_[1][2] * A_[2][0];
|
|
|
|
R[1][1] = B_[1][0] * A_[0][1] + B_[1][1] * A_[1][1] + B_[1][2] * A_[2][1];
|
|
|
|
R[1][2] = B_[1][0] * A_[0][2] + B_[1][1] * A_[1][2] + B_[1][2] * A_[2][2];
|
2019-04-14 18:13:39 +03:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
R[2][0] = B_[2][0] * A_[0][0] + B_[2][1] * A_[1][0] + B_[2][2] * A_[2][0];
|
|
|
|
R[2][1] = B_[2][0] * A_[0][1] + B_[2][1] * A_[1][1] + B_[2][2] * A_[2][1];
|
|
|
|
R[2][2] = B_[2][0] * A_[0][2] + B_[2][1] * A_[1][2] + B_[2][2] * A_[2][2];
|
2019-04-14 18:13:39 +03:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void mul_m3_m4m3(float R[3][3], const float A[4][4], const float B[3][3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
float B_[3][3], A_[4][4];
|
2012-09-16 15:25:28 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
/* copy so it works when R is the same pointer as A or B */
|
2016-09-24 16:21:38 +02:00
|
|
|
/* TODO: avoid copying when matrices are different */
|
2020-09-04 20:59:13 +02:00
|
|
|
copy_m4_m4(A_, A);
|
|
|
|
copy_m3_m3(B_, B);
|
2012-09-16 15:25:28 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
/* R[i][j] = B[i][k] * A[k][j] */
|
|
|
|
R[0][0] = B_[0][0] * A_[0][0] + B_[0][1] * A_[1][0] + B_[0][2] * A_[2][0];
|
|
|
|
R[0][1] = B_[0][0] * A_[0][1] + B_[0][1] * A_[1][1] + B_[0][2] * A_[2][1];
|
|
|
|
R[0][2] = B_[0][0] * A_[0][2] + B_[0][1] * A_[1][2] + B_[0][2] * A_[2][2];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
R[1][0] = B_[1][0] * A_[0][0] + B_[1][1] * A_[1][0] + B_[1][2] * A_[2][0];
|
|
|
|
R[1][1] = B_[1][0] * A_[0][1] + B_[1][1] * A_[1][1] + B_[1][2] * A_[2][1];
|
|
|
|
R[1][2] = B_[1][0] * A_[0][2] + B_[1][1] * A_[1][2] + B_[1][2] * A_[2][2];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
R[2][0] = B_[2][0] * A_[0][0] + B_[2][1] * A_[1][0] + B_[2][2] * A_[2][0];
|
|
|
|
R[2][1] = B_[2][0] * A_[0][1] + B_[2][1] * A_[1][1] + B_[2][2] * A_[2][1];
|
|
|
|
R[2][2] = B_[2][0] * A_[0][2] + B_[2][1] * A_[1][2] + B_[2][2] * A_[2][2];
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void mul_m4_m3m4(float R[4][4], const float A[3][3], const float B[4][4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
float B_[4][4], A_[3][3];
|
2012-09-16 15:25:28 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
/* copy so it works when R is the same pointer as A or B */
|
2016-09-24 16:21:38 +02:00
|
|
|
/* TODO: avoid copying when matrices are different */
|
2020-09-04 20:59:13 +02:00
|
|
|
copy_m3_m3(A_, A);
|
|
|
|
copy_m4_m4(B_, B);
|
2012-09-16 15:25:28 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
R[0][0] = B_[0][0] * A_[0][0] + B_[0][1] * A_[1][0] + B_[0][2] * A_[2][0];
|
|
|
|
R[0][1] = B_[0][0] * A_[0][1] + B_[0][1] * A_[1][1] + B_[0][2] * A_[2][1];
|
|
|
|
R[0][2] = B_[0][0] * A_[0][2] + B_[0][1] * A_[1][2] + B_[0][2] * A_[2][2];
|
|
|
|
R[1][0] = B_[1][0] * A_[0][0] + B_[1][1] * A_[1][0] + B_[1][2] * A_[2][0];
|
|
|
|
R[1][1] = B_[1][0] * A_[0][1] + B_[1][1] * A_[1][1] + B_[1][2] * A_[2][1];
|
|
|
|
R[1][2] = B_[1][0] * A_[0][2] + B_[1][1] * A_[1][2] + B_[1][2] * A_[2][2];
|
|
|
|
R[2][0] = B_[2][0] * A_[0][0] + B_[2][1] * A_[1][0] + B_[2][2] * A_[2][0];
|
|
|
|
R[2][1] = B_[2][0] * A_[0][1] + B_[2][1] * A_[1][1] + B_[2][2] * A_[2][1];
|
|
|
|
R[2][2] = B_[2][0] * A_[0][2] + B_[2][1] * A_[1][2] + B_[2][2] * A_[2][2];
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void mul_m3_m4m4(float R[3][3], const float A[4][4], const float B[4][4])
|
2019-04-14 18:13:39 +03:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
R[0][0] = B[0][0] * A[0][0] + B[0][1] * A[1][0] + B[0][2] * A[2][0];
|
|
|
|
R[0][1] = B[0][0] * A[0][1] + B[0][1] * A[1][1] + B[0][2] * A[2][1];
|
|
|
|
R[0][2] = B[0][0] * A[0][2] + B[0][1] * A[1][2] + B[0][2] * A[2][2];
|
|
|
|
R[1][0] = B[1][0] * A[0][0] + B[1][1] * A[1][0] + B[1][2] * A[2][0];
|
|
|
|
R[1][1] = B[1][0] * A[0][1] + B[1][1] * A[1][1] + B[1][2] * A[2][1];
|
|
|
|
R[1][2] = B[1][0] * A[0][2] + B[1][1] * A[1][2] + B[1][2] * A[2][2];
|
|
|
|
R[2][0] = B[2][0] * A[0][0] + B[2][1] * A[1][0] + B[2][2] * A[2][0];
|
|
|
|
R[2][1] = B[2][0] * A[0][1] + B[2][1] * A[1][1] + B[2][2] * A[2][1];
|
|
|
|
R[2][2] = B[2][0] * A[0][2] + B[2][1] * A[1][2] + B[2][2] * A[2][2];
|
2019-04-14 18:13:39 +03:00
|
|
|
}
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2020-08-25 12:35:44 +10:00
|
|
|
/* -------------------------------------------------------------------- */
|
2014-07-21 18:55:12 +10:00
|
|
|
/** \name Macro helpers for: mul_m3_series
|
2014-07-20 14:01:42 +10:00
|
|
|
* \{ */
|
2020-10-27 21:32:09 +11:00
|
|
|
|
2017-08-04 15:05:02 +10:00
|
|
|
void _va_mul_m3_series_3(float r[3][3], const float m1[3][3], const float m2[3][3])
|
2014-07-20 14:01:42 +10:00
|
|
|
{
|
2014-07-21 18:55:12 +10:00
|
|
|
mul_m3_m3m3(r, m1, m2);
|
2014-07-20 14:01:42 +10:00
|
|
|
}
|
2014-07-21 18:55:12 +10:00
|
|
|
void _va_mul_m3_series_4(float r[3][3],
|
2014-07-20 14:01:42 +10:00
|
|
|
const float m1[3][3],
|
2017-08-04 15:05:02 +10:00
|
|
|
const float m2[3][3],
|
|
|
|
const float m3[3][3])
|
2014-07-20 14:01:42 +10:00
|
|
|
{
|
2014-07-21 18:55:12 +10:00
|
|
|
mul_m3_m3m3(r, m1, m2);
|
|
|
|
mul_m3_m3m3(r, r, m3);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2016-09-25 18:48:11 +02:00
|
|
|
void _va_mul_m3_series_5(float r[3][3],
|
2017-08-04 15:05:02 +10:00
|
|
|
const float m1[3][3],
|
|
|
|
const float m2[3][3],
|
2019-04-14 18:13:39 +03:00
|
|
|
const float m3[3][3],
|
|
|
|
const float m4[3][3])
|
2019-04-17 06:17:24 +02:00
|
|
|
{
|
2014-07-21 18:55:12 +10:00
|
|
|
mul_m3_m3m3(r, m1, m2);
|
|
|
|
mul_m3_m3m3(r, r, m3);
|
|
|
|
mul_m3_m3m3(r, r, m4);
|
2014-07-20 14:01:42 +10:00
|
|
|
}
|
2014-07-21 18:55:12 +10:00
|
|
|
void _va_mul_m3_series_6(float r[3][3],
|
2017-08-04 15:05:02 +10:00
|
|
|
const float m1[3][3],
|
|
|
|
const float m2[3][3],
|
|
|
|
const float m3[3][3],
|
|
|
|
const float m4[3][3],
|
|
|
|
const float m5[3][3])
|
2014-07-20 14:01:42 +10:00
|
|
|
{
|
2014-07-21 18:55:12 +10:00
|
|
|
mul_m3_m3m3(r, m1, m2);
|
|
|
|
mul_m3_m3m3(r, r, m3);
|
|
|
|
mul_m3_m3m3(r, r, m4);
|
|
|
|
mul_m3_m3m3(r, r, m5);
|
2014-07-20 14:01:42 +10:00
|
|
|
}
|
2014-07-21 18:55:12 +10:00
|
|
|
void _va_mul_m3_series_7(float r[3][3],
|
2017-08-04 15:05:02 +10:00
|
|
|
const float m1[3][3],
|
|
|
|
const float m2[3][3],
|
|
|
|
const float m3[3][3],
|
|
|
|
const float m4[3][3],
|
|
|
|
const float m5[3][3],
|
|
|
|
const float m6[3][3])
|
2014-07-20 14:01:42 +10:00
|
|
|
{
|
2014-07-21 18:55:12 +10:00
|
|
|
mul_m3_m3m3(r, m1, m2);
|
|
|
|
mul_m3_m3m3(r, r, m3);
|
|
|
|
mul_m3_m3m3(r, r, m4);
|
|
|
|
mul_m3_m3m3(r, r, m5);
|
|
|
|
mul_m3_m3m3(r, r, m6);
|
2014-07-20 14:01:42 +10:00
|
|
|
}
|
2014-07-21 18:55:12 +10:00
|
|
|
void _va_mul_m3_series_8(float r[3][3],
|
2017-08-04 15:05:02 +10:00
|
|
|
const float m1[3][3],
|
|
|
|
const float m2[3][3],
|
|
|
|
const float m3[3][3],
|
|
|
|
const float m4[3][3],
|
|
|
|
const float m5[3][3],
|
|
|
|
const float m6[3][3],
|
|
|
|
const float m7[3][3])
|
2014-07-20 14:01:42 +10:00
|
|
|
{
|
2014-07-21 18:55:12 +10:00
|
|
|
mul_m3_m3m3(r, m1, m2);
|
|
|
|
mul_m3_m3m3(r, r, m3);
|
|
|
|
mul_m3_m3m3(r, r, m4);
|
|
|
|
mul_m3_m3m3(r, r, m5);
|
|
|
|
mul_m3_m3m3(r, r, m6);
|
|
|
|
mul_m3_m3m3(r, r, m7);
|
2014-07-20 14:01:42 +10:00
|
|
|
}
|
2014-07-21 18:55:12 +10:00
|
|
|
void _va_mul_m3_series_9(float r[3][3],
|
2017-08-04 15:05:02 +10:00
|
|
|
const float m1[3][3],
|
|
|
|
const float m2[3][3],
|
|
|
|
const float m3[3][3],
|
|
|
|
const float m4[3][3],
|
|
|
|
const float m5[3][3],
|
|
|
|
const float m6[3][3],
|
|
|
|
const float m7[3][3],
|
|
|
|
const float m8[3][3])
|
2014-07-20 14:01:42 +10:00
|
|
|
{
|
2014-07-21 18:55:12 +10:00
|
|
|
mul_m3_m3m3(r, m1, m2);
|
|
|
|
mul_m3_m3m3(r, r, m3);
|
|
|
|
mul_m3_m3m3(r, r, m4);
|
|
|
|
mul_m3_m3m3(r, r, m5);
|
|
|
|
mul_m3_m3m3(r, r, m6);
|
|
|
|
mul_m3_m3m3(r, r, m7);
|
|
|
|
mul_m3_m3m3(r, r, m8);
|
2014-07-20 14:01:42 +10:00
|
|
|
}
|
2021-12-14 15:49:31 +11:00
|
|
|
|
2014-07-20 14:01:42 +10:00
|
|
|
/** \} */
|
|
|
|
|
2020-08-25 12:35:44 +10:00
|
|
|
/* -------------------------------------------------------------------- */
|
2014-07-21 18:55:12 +10:00
|
|
|
/** \name Macro helpers for: mul_m4_series
|
2014-07-20 14:01:42 +10:00
|
|
|
* \{ */
|
2020-10-27 21:32:09 +11:00
|
|
|
|
2017-08-04 15:05:02 +10:00
|
|
|
void _va_mul_m4_series_3(float r[4][4], const float m1[4][4], const float m2[4][4])
|
2019-04-17 06:17:24 +02:00
|
|
|
{
|
2014-07-20 20:44:42 +06:00
|
|
|
mul_m4_m4m4(r, m1, m2);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2016-09-24 16:21:38 +02:00
|
|
|
void _va_mul_m4_series_4(float r[4][4],
|
2017-08-04 15:05:02 +10:00
|
|
|
const float m1[4][4],
|
|
|
|
const float m2[4][4],
|
|
|
|
const float m3[4][4])
|
2014-07-20 14:01:42 +10:00
|
|
|
{
|
2014-07-20 20:44:42 +06:00
|
|
|
mul_m4_m4m4(r, m1, m2);
|
|
|
|
mul_m4_m4m4(r, r, m3);
|
2014-07-20 14:01:42 +10:00
|
|
|
}
|
2014-07-21 18:55:12 +10:00
|
|
|
void _va_mul_m4_series_5(float r[4][4],
|
2017-08-04 15:05:02 +10:00
|
|
|
const float m1[4][4],
|
|
|
|
const float m2[4][4],
|
|
|
|
const float m3[4][4],
|
|
|
|
const float m4[4][4])
|
2014-07-20 14:01:42 +10:00
|
|
|
{
|
2014-07-20 20:44:42 +06:00
|
|
|
mul_m4_m4m4(r, m1, m2);
|
|
|
|
mul_m4_m4m4(r, r, m3);
|
|
|
|
mul_m4_m4m4(r, r, m4);
|
2014-07-20 14:01:42 +10:00
|
|
|
}
|
2014-07-21 18:55:12 +10:00
|
|
|
void _va_mul_m4_series_6(float r[4][4],
|
2017-08-04 15:05:02 +10:00
|
|
|
const float m1[4][4],
|
|
|
|
const float m2[4][4],
|
|
|
|
const float m3[4][4],
|
|
|
|
const float m4[4][4],
|
|
|
|
const float m5[4][4])
|
2014-07-20 14:01:42 +10:00
|
|
|
{
|
2014-07-20 20:44:42 +06:00
|
|
|
mul_m4_m4m4(r, m1, m2);
|
|
|
|
mul_m4_m4m4(r, r, m3);
|
|
|
|
mul_m4_m4m4(r, r, m4);
|
|
|
|
mul_m4_m4m4(r, r, m5);
|
2014-07-20 14:01:42 +10:00
|
|
|
}
|
2014-07-21 18:55:12 +10:00
|
|
|
void _va_mul_m4_series_7(float r[4][4],
|
2017-08-04 15:05:02 +10:00
|
|
|
const float m1[4][4],
|
|
|
|
const float m2[4][4],
|
|
|
|
const float m3[4][4],
|
|
|
|
const float m4[4][4],
|
|
|
|
const float m5[4][4],
|
|
|
|
const float m6[4][4])
|
2014-07-20 14:01:42 +10:00
|
|
|
{
|
2014-07-20 20:44:42 +06:00
|
|
|
mul_m4_m4m4(r, m1, m2);
|
|
|
|
mul_m4_m4m4(r, r, m3);
|
|
|
|
mul_m4_m4m4(r, r, m4);
|
|
|
|
mul_m4_m4m4(r, r, m5);
|
|
|
|
mul_m4_m4m4(r, r, m6);
|
2014-07-20 14:01:42 +10:00
|
|
|
}
|
2014-07-21 18:55:12 +10:00
|
|
|
void _va_mul_m4_series_8(float r[4][4],
|
2017-08-04 15:05:02 +10:00
|
|
|
const float m1[4][4],
|
|
|
|
const float m2[4][4],
|
|
|
|
const float m3[4][4],
|
|
|
|
const float m4[4][4],
|
|
|
|
const float m5[4][4],
|
|
|
|
const float m6[4][4],
|
|
|
|
const float m7[4][4])
|
2014-07-20 14:01:42 +10:00
|
|
|
{
|
2014-07-20 20:44:42 +06:00
|
|
|
mul_m4_m4m4(r, m1, m2);
|
|
|
|
mul_m4_m4m4(r, r, m3);
|
|
|
|
mul_m4_m4m4(r, r, m4);
|
|
|
|
mul_m4_m4m4(r, r, m5);
|
|
|
|
mul_m4_m4m4(r, r, m6);
|
|
|
|
mul_m4_m4m4(r, r, m7);
|
2014-07-20 14:01:42 +10:00
|
|
|
}
|
2014-07-21 18:55:12 +10:00
|
|
|
void _va_mul_m4_series_9(float r[4][4],
|
2017-08-04 15:05:02 +10:00
|
|
|
const float m1[4][4],
|
|
|
|
const float m2[4][4],
|
|
|
|
const float m3[4][4],
|
|
|
|
const float m4[4][4],
|
|
|
|
const float m5[4][4],
|
|
|
|
const float m6[4][4],
|
|
|
|
const float m7[4][4],
|
|
|
|
const float m8[4][4])
|
2014-07-20 14:01:42 +10:00
|
|
|
{
|
2014-07-20 20:44:42 +06:00
|
|
|
mul_m4_m4m4(r, m1, m2);
|
|
|
|
mul_m4_m4m4(r, r, m3);
|
|
|
|
mul_m4_m4m4(r, r, m4);
|
|
|
|
mul_m4_m4m4(r, r, m5);
|
|
|
|
mul_m4_m4m4(r, r, m6);
|
|
|
|
mul_m4_m4m4(r, r, m7);
|
|
|
|
mul_m4_m4m4(r, r, m8);
|
2014-07-20 14:01:42 +10:00
|
|
|
}
|
2021-12-14 15:49:31 +11:00
|
|
|
|
2014-07-20 14:01:42 +10:00
|
|
|
/** \} */
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_v2_m3v2(float r[2], const float m[3][3], const float v[2])
|
2013-09-11 10:06:54 +00:00
|
|
|
{
|
|
|
|
float temp[3], warped[3];
|
|
|
|
|
|
|
|
copy_v2_v2(temp, v);
|
|
|
|
temp[2] = 1.0f;
|
|
|
|
|
|
|
|
mul_v3_m3v3(warped, m, temp);
|
|
|
|
|
|
|
|
r[0] = warped[0] / warped[2];
|
|
|
|
r[1] = warped[1] / warped[2];
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_m3_v2(const float m[3][3], float r[2])
|
2013-09-11 10:06:54 +00:00
|
|
|
{
|
|
|
|
mul_v2_m3v2(r, m, r);
|
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void mul_m4_v3(const float M[4][4], float r[3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
const float x = r[0];
|
|
|
|
const float y = r[1];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
r[0] = x * M[0][0] + y * M[1][0] + M[2][0] * r[2] + M[3][0];
|
|
|
|
r[1] = x * M[0][1] + y * M[1][1] + M[2][1] * r[2] + M[3][1];
|
|
|
|
r[2] = x * M[0][2] + y * M[1][2] + M[2][2] * r[2] + M[3][2];
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2014-07-30 11:00:59 +02:00
|
|
|
const float x = vec[0];
|
|
|
|
const float y = vec[1];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2013-03-09 11:55:12 +00:00
|
|
|
r[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2] + mat[3][0];
|
|
|
|
r[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2] + mat[3][1];
|
|
|
|
r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2] + mat[3][2];
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2019-08-20 21:09:55 +08:00
|
|
|
void mul_v3_m4v3_db(double r[3], const double mat[4][4], const double vec[3])
|
|
|
|
{
|
|
|
|
const double x = vec[0];
|
|
|
|
const double y = vec[1];
|
|
|
|
|
|
|
|
r[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2] + mat[3][0];
|
|
|
|
r[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2] + mat[3][1];
|
|
|
|
r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2] + mat[3][2];
|
|
|
|
}
|
|
|
|
void mul_v4_m4v3_db(double r[4], const double mat[4][4], const double vec[3])
|
|
|
|
{
|
|
|
|
const double x = vec[0];
|
|
|
|
const double y = vec[1];
|
|
|
|
|
|
|
|
r[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2] + mat[3][0];
|
|
|
|
r[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2] + mat[3][1];
|
|
|
|
r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2] + mat[3][2];
|
|
|
|
r[3] = x * mat[0][3] + y * mat[1][3] + mat[2][3] * vec[2] + mat[3][3];
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_v2_m4v3(float r[2], const float mat[4][4], const float vec[3])
|
2013-05-08 12:55:36 +00:00
|
|
|
{
|
2014-07-30 11:00:59 +02:00
|
|
|
const float x = vec[0];
|
2013-05-08 12:55:36 +00:00
|
|
|
|
|
|
|
r[0] = x * mat[0][0] + vec[1] * mat[1][0] + mat[2][0] * vec[2] + mat[3][0];
|
|
|
|
r[1] = x * mat[0][1] + vec[1] * mat[1][1] + mat[2][1] * vec[2] + mat[3][1];
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_v2_m2v2(float r[2], const float mat[2][2], const float vec[2])
|
2013-02-11 22:52:13 +00:00
|
|
|
{
|
2014-07-30 11:00:59 +02:00
|
|
|
const float x = vec[0];
|
2013-02-12 00:35:31 +00:00
|
|
|
|
|
|
|
r[0] = mat[0][0] * x + mat[1][0] * vec[1];
|
|
|
|
r[1] = mat[0][1] * x + mat[1][1] * vec[1];
|
2013-02-11 22:52:13 +00:00
|
|
|
}
|
|
|
|
|
2020-02-20 13:25:53 +11:00
|
|
|
void mul_m2_v2(const float mat[2][2], float vec[2])
|
2014-01-05 22:12:21 +11:00
|
|
|
{
|
|
|
|
mul_v2_m2v2(vec, mat, vec);
|
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void mul_mat3_m4_v3(const float M[4][4], float r[3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
const float x = r[0];
|
|
|
|
const float y = r[1];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
r[0] = x * M[0][0] + y * M[1][0] + M[2][0] * r[2];
|
|
|
|
r[1] = x * M[0][1] + y * M[1][1] + M[2][1] * r[2];
|
|
|
|
r[2] = x * M[0][2] + y * M[1][2] + M[2][2] * r[2];
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_v3_mat3_m4v3(float r[3], const float mat[4][4], const float vec[3])
|
2015-04-27 21:50:38 +10:00
|
|
|
{
|
|
|
|
const float x = vec[0];
|
|
|
|
const float y = vec[1];
|
|
|
|
|
|
|
|
r[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2];
|
|
|
|
r[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2];
|
2019-08-20 21:09:55 +08:00
|
|
|
r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
void mul_v3_mat3_m4v3_db(double r[3], const double mat[4][4], const double vec[3])
|
|
|
|
{
|
|
|
|
const double x = vec[0];
|
|
|
|
const double y = vec[1];
|
|
|
|
|
|
|
|
r[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2];
|
|
|
|
r[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2];
|
2015-04-27 21:50:38 +10:00
|
|
|
r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2];
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_project_m4_v3(const float mat[4][4], float vec[3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2015-10-11 20:25:33 +02:00
|
|
|
/* absolute value to not flip the frustum upside down behind the camera */
|
|
|
|
const float w = fabsf(mul_project_m4_v3_zfac(mat, vec));
|
2009-11-09 22:42:41 +00:00
|
|
|
mul_m4_v3(mat, vec);
|
|
|
|
|
|
|
|
vec[0] /= w;
|
|
|
|
vec[1] /= w;
|
|
|
|
vec[2] /= w;
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_v3_project_m4_v3(float r[3], const float mat[4][4], const float vec[3])
|
2014-09-16 15:41:17 +10:00
|
|
|
{
|
2015-10-11 20:25:33 +02:00
|
|
|
const float w = fabsf(mul_project_m4_v3_zfac(mat, vec));
|
2014-09-16 15:41:17 +10:00
|
|
|
mul_v3_m4v3(r, mat, vec);
|
|
|
|
|
|
|
|
r[0] /= w;
|
|
|
|
r[1] /= w;
|
|
|
|
r[2] /= w;
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_v2_project_m4_v3(float r[2], const float mat[4][4], const float vec[3])
|
2013-05-08 12:55:36 +00:00
|
|
|
{
|
2015-10-11 20:25:33 +02:00
|
|
|
const float w = fabsf(mul_project_m4_v3_zfac(mat, vec));
|
2013-05-08 12:55:36 +00:00
|
|
|
mul_v2_m4v3(r, mat, vec);
|
|
|
|
|
|
|
|
r[0] /= w;
|
|
|
|
r[1] /= w;
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_v4_m4v4(float r[4], const float mat[4][4], const float v[4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2014-07-30 11:00:59 +02:00
|
|
|
const float x = v[0];
|
|
|
|
const float y = v[1];
|
|
|
|
const float z = v[2];
|
2010-04-15 10:28:32 +00:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
r[0] = x * mat[0][0] + y * mat[1][0] + z * mat[2][0] + mat[3][0] * v[3];
|
|
|
|
r[1] = x * mat[0][1] + y * mat[1][1] + z * mat[2][1] + mat[3][1] * v[3];
|
|
|
|
r[2] = x * mat[0][2] + y * mat[1][2] + z * mat[2][2] + mat[3][2] * v[3];
|
|
|
|
r[3] = x * mat[0][3] + y * mat[1][3] + z * mat[2][3] + mat[3][3] * v[3];
|
2010-04-15 10:28:32 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_m4_v4(const float mat[4][4], float r[4])
|
2010-04-15 10:28:32 +00:00
|
|
|
{
|
|
|
|
mul_v4_m4v4(r, mat, r);
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_v4d_m4v4d(double r[4], const float mat[4][4], const double v[4])
|
2012-03-08 11:57:51 +00:00
|
|
|
{
|
2014-07-30 11:00:59 +02:00
|
|
|
const double x = v[0];
|
|
|
|
const double y = v[1];
|
|
|
|
const double z = v[2];
|
2012-03-08 11:57:51 +00:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
r[0] = x * (double)mat[0][0] + y * (double)mat[1][0] + z * (double)mat[2][0] +
|
|
|
|
(double)mat[3][0] * v[3];
|
|
|
|
r[1] = x * (double)mat[0][1] + y * (double)mat[1][1] + z * (double)mat[2][1] +
|
|
|
|
(double)mat[3][1] * v[3];
|
|
|
|
r[2] = x * (double)mat[0][2] + y * (double)mat[1][2] + z * (double)mat[2][2] +
|
|
|
|
(double)mat[3][2] * v[3];
|
|
|
|
r[3] = x * (double)mat[0][3] + y * (double)mat[1][3] + z * (double)mat[2][3] +
|
|
|
|
(double)mat[3][3] * v[3];
|
2012-03-08 11:57:51 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_m4_v4d(const float mat[4][4], double r[4])
|
2012-03-08 11:57:51 +00:00
|
|
|
{
|
|
|
|
mul_v4d_m4v4d(r, mat, r);
|
|
|
|
}
|
|
|
|
|
2016-09-25 19:01:18 +02:00
|
|
|
void mul_v4_m4v3(float r[4], const float M[4][4], const float v[3])
|
|
|
|
{
|
|
|
|
/* v has implicit w = 1.0f */
|
|
|
|
r[0] = v[0] * M[0][0] + v[1] * M[1][0] + M[2][0] * v[2] + M[3][0];
|
|
|
|
r[1] = v[0] * M[0][1] + v[1] * M[1][1] + M[2][1] * v[2] + M[3][1];
|
|
|
|
r[2] = v[0] * M[0][2] + v[1] * M[1][2] + M[2][2] * v[2] + M[3][2];
|
|
|
|
r[3] = v[0] * M[0][3] + v[1] * M[1][3] + M[2][3] * v[2] + M[3][3];
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2019-01-17 15:41:27 +01:00
|
|
|
float t[3];
|
|
|
|
copy_v3_v3(t, a);
|
2013-08-06 02:37:02 +00:00
|
|
|
|
2019-01-17 15:41:27 +01:00
|
|
|
r[0] = M[0][0] * t[0] + M[1][0] * t[1] + M[2][0] * t[2];
|
|
|
|
r[1] = M[0][1] * t[0] + M[1][1] * t[1] + M[2][1] * t[2];
|
|
|
|
r[2] = M[0][2] * t[0] + M[1][2] * t[1] + M[2][2] * t[2];
|
2009-11-28 13:11:41 +00:00
|
|
|
}
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_v3_m3v3_db(double r[3], const double M[3][3], const double a[3])
|
2016-06-14 16:43:14 +10:00
|
|
|
{
|
2019-01-17 15:41:27 +01:00
|
|
|
double t[3];
|
|
|
|
copy_v3_v3_db(t, a);
|
2016-06-14 16:43:14 +10:00
|
|
|
|
2019-01-17 15:41:27 +01:00
|
|
|
r[0] = M[0][0] * t[0] + M[1][0] * t[1] + M[2][0] * t[2];
|
|
|
|
r[1] = M[0][1] * t[0] + M[1][1] * t[1] + M[2][1] * t[2];
|
|
|
|
r[2] = M[0][2] * t[0] + M[1][2] * t[1] + M[2][2] * t[2];
|
2016-06-14 16:43:14 +10:00
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
|
2013-01-29 15:05:23 +00:00
|
|
|
{
|
2019-01-17 15:41:27 +01:00
|
|
|
float t[3];
|
|
|
|
copy_v3_v3(t, a);
|
2013-08-06 02:37:02 +00:00
|
|
|
|
2019-01-17 15:41:27 +01:00
|
|
|
r[0] = M[0][0] * t[0] + M[1][0] * t[1] + M[2][0] * t[2];
|
|
|
|
r[1] = M[0][1] * t[0] + M[1][1] * t[1] + M[2][1] * t[2];
|
2013-01-29 15:05:23 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_m3_v3(const float M[3][3], float r[3])
|
2009-11-28 13:11:41 +00:00
|
|
|
{
|
2016-06-14 16:43:14 +10:00
|
|
|
mul_v3_m3v3(r, M, (const float[3]){UNPACK3(r)});
|
|
|
|
}
|
2009-11-28 13:11:41 +00:00
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mul_m3_v3_db(const double M[3][3], double r[3])
|
2016-06-14 16:43:14 +10:00
|
|
|
{
|
|
|
|
mul_v3_m3v3_db(r, M, (const double[3]){UNPACK3(r)});
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void mul_transposed_m3_v3(const float M[3][3], float r[3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
const float x = r[0];
|
|
|
|
const float y = r[1];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
r[0] = x * M[0][0] + y * M[0][1] + M[0][2] * r[2];
|
|
|
|
r[1] = x * M[1][0] + y * M[1][1] + M[1][2] * r[2];
|
|
|
|
r[2] = x * M[2][0] + y * M[2][1] + M[2][2] * r[2];
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3])
|
2013-04-17 23:30:19 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
const float x = r[0];
|
|
|
|
const float y = r[1];
|
2013-04-17 23:30:19 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
r[0] = x * M[0][0] + y * M[0][1] + M[0][2] * r[2];
|
|
|
|
r[1] = x * M[1][0] + y * M[1][1] + M[1][2] * r[2];
|
|
|
|
r[2] = x * M[2][0] + y * M[2][1] + M[2][2] * r[2];
|
2013-04-17 23:30:19 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void mul_m3_fl(float R[3][3], float f)
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2009-11-10 19:13:05 +00:00
|
|
|
int i, j;
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2019-03-27 13:16:10 +11:00
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
for (j = 0; j < 3; j++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
R[i][j] *= f;
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
|
|
|
}
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void mul_m4_fl(float R[4][4], float f)
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2009-11-10 19:13:05 +00:00
|
|
|
int i, j;
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2019-03-27 13:16:10 +11:00
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
for (j = 0; j < 4; j++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
R[i][j] *= f;
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
|
|
|
}
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void mul_mat3_m4_fl(float R[4][4], float f)
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2009-11-10 19:13:05 +00:00
|
|
|
int i, j;
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2019-03-27 13:16:10 +11:00
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
for (j = 0; j < 3; j++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
R[i][j] *= f;
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
|
|
|
}
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void negate_m3(float R[3][3])
|
2014-05-30 00:26:05 +10:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
2019-03-27 13:16:10 +11:00
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
for (j = 0; j < 3; j++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
R[i][j] *= -1.0f;
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
|
|
|
}
|
2014-05-30 00:26:05 +10:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void negate_mat3_m4(float R[4][4])
|
2014-10-30 15:26:41 +01:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
2019-03-27 13:16:10 +11:00
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
for (j = 0; j < 3; j++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
R[i][j] *= -1.0f;
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
|
|
|
}
|
2014-10-30 15:26:41 +01:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void negate_m4(float R[4][4])
|
2014-05-30 00:26:05 +10:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
2019-03-27 13:16:10 +11:00
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
for (j = 0; j < 4; j++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
R[i][j] *= -1.0f;
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
|
|
|
}
|
2014-05-30 00:26:05 +10:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void mul_m3_v3_double(const float M[3][3], double r[3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
const double x = r[0];
|
|
|
|
const double y = r[1];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
r[0] = x * (double)M[0][0] + y * (double)M[1][0] + (double)M[2][0] * r[2];
|
|
|
|
r[1] = x * (double)M[0][1] + y * (double)M[1][1] + (double)M[2][1] * r[2];
|
|
|
|
r[2] = x * (double)M[0][2] + y * (double)M[1][2] + (double)M[2][2] * r[2];
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void add_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
2019-03-27 13:16:10 +11:00
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
for (j = 0; j < 3; j++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
R[i][j] = A[i][j] + B[i][j];
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
|
|
|
}
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void add_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
2019-03-27 13:16:10 +11:00
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
for (j = 0; j < 4; j++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
R[i][j] = A[i][j] + B[i][j];
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
|
|
|
}
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void madd_m3_m3m3fl(float R[3][3], const float A[3][3], const float B[3][3], const float f)
|
2019-04-05 18:40:59 +03:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
for (j = 0; j < 3; j++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
R[i][j] = A[i][j] + B[i][j] * f;
|
2019-04-05 18:40:59 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void madd_m4_m4m4fl(float R[4][4], const float A[4][4], const float B[4][4], const float f)
|
2019-04-05 18:40:59 +03:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
for (j = 0; j < 4; j++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
R[i][j] = A[i][j] + B[i][j] * f;
|
2019-04-05 18:40:59 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void sub_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
|
2011-09-05 21:01:50 +00:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
2019-03-27 13:16:10 +11:00
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
for (j = 0; j < 3; j++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
R[i][j] = A[i][j] - B[i][j];
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
|
|
|
}
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void sub_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
|
2011-09-05 21:01:50 +00:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
2019-03-27 13:16:10 +11:00
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
for (j = 0; j < 4; j++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
R[i][j] = A[i][j] - B[i][j];
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
|
|
|
}
|
2011-09-05 21:01:50 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
float determinant_m3_array(const float m[3][3])
|
2012-11-07 09:28:59 +00:00
|
|
|
{
|
|
|
|
return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) -
|
|
|
|
m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) +
|
|
|
|
m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1]));
|
|
|
|
}
|
|
|
|
|
2019-05-05 13:25:43 +03:00
|
|
|
float determinant_m4_mat3_array(const float m[4][4])
|
|
|
|
{
|
|
|
|
return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) -
|
|
|
|
m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) +
|
|
|
|
m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1]));
|
|
|
|
}
|
|
|
|
|
2020-11-21 16:06:02 +03:00
|
|
|
double determinant_m3_array_db(const double m[3][3])
|
|
|
|
{
|
|
|
|
return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) -
|
|
|
|
m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) +
|
|
|
|
m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1]));
|
|
|
|
}
|
|
|
|
|
2014-04-01 11:34:00 +11:00
|
|
|
bool invert_m3_ex(float m[3][3], const float epsilon)
|
2012-11-07 09:28:59 +00:00
|
|
|
{
|
|
|
|
float tmp[3][3];
|
2014-07-30 11:00:59 +02:00
|
|
|
const bool success = invert_m3_m3_ex(tmp, m, epsilon);
|
2012-11-07 09:28:59 +00:00
|
|
|
|
|
|
|
copy_m3_m3(m, tmp);
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
bool invert_m3_m3_ex(float m1[3][3], const float m2[3][3], const float epsilon)
|
2012-11-07 09:28:59 +00:00
|
|
|
{
|
|
|
|
float det;
|
2014-04-01 11:34:00 +11:00
|
|
|
int a, b;
|
|
|
|
bool success;
|
2012-11-07 09:28:59 +00:00
|
|
|
|
|
|
|
BLI_assert(epsilon >= 0.0f);
|
|
|
|
|
|
|
|
/* calc adjoint */
|
|
|
|
adjoint_m3_m3(m1, m2);
|
|
|
|
|
|
|
|
/* then determinant old matrix! */
|
2012-12-14 21:41:22 +00:00
|
|
|
det = determinant_m3_array(m2);
|
2012-11-07 09:28:59 +00:00
|
|
|
|
|
|
|
success = (fabsf(det) > epsilon);
|
|
|
|
|
|
|
|
if (LIKELY(det != 0.0f)) {
|
|
|
|
det = 1.0f / det;
|
|
|
|
for (a = 0; a < 3; a++) {
|
|
|
|
for (b = 0; b < 3; b++) {
|
|
|
|
m1[a][b] *= det;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2014-04-01 11:34:00 +11:00
|
|
|
bool invert_m3(float m[3][3])
|
2009-11-10 19:13:05 +00:00
|
|
|
{
|
|
|
|
float tmp[3][3];
|
2014-07-30 11:00:59 +02:00
|
|
|
const bool success = invert_m3_m3(tmp, m);
|
2009-11-10 19:13:05 +00:00
|
|
|
|
|
|
|
copy_m3_m3(m, tmp);
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
bool invert_m3_m3(float m1[3][3], const float m2[3][3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
float det;
|
2014-04-01 11:34:00 +11:00
|
|
|
int a, b;
|
|
|
|
bool success;
|
2009-11-09 22:42:41 +00:00
|
|
|
|
|
|
|
/* calc adjoint */
|
2012-03-25 12:41:58 +00:00
|
|
|
adjoint_m3_m3(m1, m2);
|
2009-11-09 22:42:41 +00:00
|
|
|
|
|
|
|
/* then determinant old matrix! */
|
2012-12-14 21:41:22 +00:00
|
|
|
det = determinant_m3_array(m2);
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2012-11-07 09:28:59 +00:00
|
|
|
success = (det != 0.0f);
|
2009-11-10 19:13:05 +00:00
|
|
|
|
2012-11-07 09:28:59 +00:00
|
|
|
if (LIKELY(det != 0.0f)) {
|
|
|
|
det = 1.0f / det;
|
|
|
|
for (a = 0; a < 3; a++) {
|
|
|
|
for (b = 0; b < 3; b++) {
|
|
|
|
m1[a][b] *= det;
|
|
|
|
}
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
}
|
2009-11-10 19:13:05 +00:00
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2014-04-01 11:34:00 +11:00
|
|
|
bool invert_m4(float m[4][4])
|
2009-11-10 19:13:05 +00:00
|
|
|
{
|
|
|
|
float tmp[4][4];
|
2014-07-30 11:00:59 +02:00
|
|
|
const bool success = invert_m4_m4(tmp, m);
|
2009-11-10 19:13:05 +00:00
|
|
|
|
|
|
|
copy_m4_m4(m, tmp);
|
|
|
|
return success;
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2019-05-05 16:04:10 +02:00
|
|
|
bool invert_m4_m4_fallback(float inverse[4][4], const float mat[4][4])
|
|
|
|
{
|
2019-10-22 15:21:59 +11:00
|
|
|
#ifndef MATH_STANDALONE
|
2019-05-05 16:04:10 +02:00
|
|
|
if (EIG_invert_m4_m4(inverse, mat)) {
|
|
|
|
return true;
|
|
|
|
}
|
2019-10-22 15:21:59 +11:00
|
|
|
#endif
|
2019-05-05 16:04:10 +02:00
|
|
|
|
|
|
|
int i, j, k;
|
|
|
|
double temp;
|
|
|
|
float tempmat[4][4];
|
|
|
|
float max;
|
|
|
|
int maxj;
|
|
|
|
|
|
|
|
BLI_assert(inverse != mat);
|
|
|
|
|
|
|
|
/* Set inverse to identity */
|
2019-05-31 22:51:19 +10:00
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
for (j = 0; j < 4; j++) {
|
2019-05-05 16:04:10 +02:00
|
|
|
inverse[i][j] = 0;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < 4; i++) {
|
2019-05-05 16:04:10 +02:00
|
|
|
inverse[i][i] = 1;
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2019-05-05 16:04:10 +02:00
|
|
|
|
|
|
|
/* Copy original matrix so we don't mess it up */
|
2019-05-31 22:51:19 +10:00
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
for (j = 0; j < 4; j++) {
|
2019-05-05 16:04:10 +02:00
|
|
|
tempmat[i][j] = mat[i][j];
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
|
|
|
}
|
2019-05-05 16:04:10 +02:00
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
/* Look for row with max pivot */
|
|
|
|
max = fabsf(tempmat[i][i]);
|
|
|
|
maxj = i;
|
|
|
|
for (j = i + 1; j < 4; j++) {
|
|
|
|
if (fabsf(tempmat[j][i]) > max) {
|
|
|
|
max = fabsf(tempmat[j][i]);
|
|
|
|
maxj = j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Swap rows if necessary */
|
|
|
|
if (maxj != i) {
|
|
|
|
for (k = 0; k < 4; k++) {
|
|
|
|
SWAP(float, tempmat[i][k], tempmat[maxj][k]);
|
|
|
|
SWAP(float, inverse[i][k], inverse[maxj][k]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (UNLIKELY(tempmat[i][i] == 0.0f)) {
|
2019-05-08 09:20:12 +10:00
|
|
|
return false; /* No non-zero pivot */
|
2019-05-05 16:04:10 +02:00
|
|
|
}
|
|
|
|
temp = (double)tempmat[i][i];
|
|
|
|
for (k = 0; k < 4; k++) {
|
|
|
|
tempmat[i][k] = (float)((double)tempmat[i][k] / temp);
|
|
|
|
inverse[i][k] = (float)((double)inverse[i][k] / temp);
|
|
|
|
}
|
|
|
|
for (j = 0; j < 4; j++) {
|
|
|
|
if (j != i) {
|
|
|
|
temp = tempmat[j][i];
|
|
|
|
for (k = 0; k < 4; k++) {
|
|
|
|
tempmat[j][k] -= (float)((double)tempmat[i][k] * temp);
|
|
|
|
inverse[j][k] -= (float)((double)inverse[i][k] * temp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2019-10-22 15:21:59 +11:00
|
|
|
#ifndef MATH_STANDALONE
|
2018-05-31 16:36:20 +02:00
|
|
|
/* Use optimized matrix inverse from Eigen, since performance
|
|
|
|
* impact of this function is significant in complex rigs. */
|
|
|
|
return EIG_invert_m4_m4(inverse, mat);
|
2019-10-22 15:21:59 +11:00
|
|
|
#else
|
|
|
|
return invert_m4_m4_fallback(inverse, mat);
|
|
|
|
#endif
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
Action Constraint: introduce a mix mode setting.
Currently the action channels are applied after the existing
transformation, as if the action controlled a child of the
bone. This is not very natural, but more importantly, the
transform tools are not designed to work conveniently with an
additional 'pseudo-child' transformation, resulting in effects
like an unexpected pivot location.
Implementing a Before mode that integrates the action channels
as if applied to a parent allows using the special transform
tool code intended for dealing with such constraints.
Note that in either mode, Action constraints should be added
in reverse order, putting a new constraint before the existing
ones that the Action was keyframed to work together.
In order to implement the option, extract a utility from
the Copy Transform constraint code for combining transforms
with special anti-shear scale handling that matches the
Aligned Inherit Scale mode.
The Before mode also requires switching the constraint to
the Local owner space, while the After mode can still use the
World space for efficiency as before. Since the constraint
doesn't have an Owner space option in the UI, this has to be
handled in an RNA setter.
For full backward compatibility, the original simple matrix
multiplication mode is preserved as the third option, but it
is not recommended due to creating shear.
Differential Revision: https://developer.blender.org/D6297
2019-11-23 13:11:39 +03:00
|
|
|
void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4])
|
|
|
|
{
|
|
|
|
float loc_a[3], rot_a[3][3], size_a[3];
|
|
|
|
float loc_b[3], rot_b[3][3], size_b[3];
|
|
|
|
float loc_r[3], rot_r[3][3], size_r[3];
|
|
|
|
|
|
|
|
mat4_to_loc_rot_size(loc_a, rot_a, size_a, A);
|
|
|
|
mat4_to_loc_rot_size(loc_b, rot_b, size_b, B);
|
|
|
|
|
|
|
|
mul_v3_m4v3(loc_r, A, loc_b);
|
|
|
|
mul_m3_m3m3_uniq(rot_r, rot_a, rot_b);
|
|
|
|
mul_v3_v3v3(size_r, size_a, size_b);
|
2020-11-04 19:29:27 +03:00
|
|
|
|
|
|
|
loc_rot_size_to_mat4(R, loc_r, rot_r, size_r);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mul_m4_m4m4_split_channels(float R[4][4], const float A[4][4], const float B[4][4])
|
|
|
|
{
|
|
|
|
float loc_a[3], rot_a[3][3], size_a[3];
|
|
|
|
float loc_b[3], rot_b[3][3], size_b[3];
|
|
|
|
float loc_r[3], rot_r[3][3], size_r[3];
|
|
|
|
|
|
|
|
mat4_to_loc_rot_size(loc_a, rot_a, size_a, A);
|
|
|
|
mat4_to_loc_rot_size(loc_b, rot_b, size_b, B);
|
|
|
|
|
|
|
|
add_v3_v3v3(loc_r, loc_a, loc_b);
|
|
|
|
mul_m3_m3m3_uniq(rot_r, rot_a, rot_b);
|
|
|
|
mul_v3_v3v3(size_r, size_a, size_b);
|
Action Constraint: introduce a mix mode setting.
Currently the action channels are applied after the existing
transformation, as if the action controlled a child of the
bone. This is not very natural, but more importantly, the
transform tools are not designed to work conveniently with an
additional 'pseudo-child' transformation, resulting in effects
like an unexpected pivot location.
Implementing a Before mode that integrates the action channels
as if applied to a parent allows using the special transform
tool code intended for dealing with such constraints.
Note that in either mode, Action constraints should be added
in reverse order, putting a new constraint before the existing
ones that the Action was keyframed to work together.
In order to implement the option, extract a utility from
the Copy Transform constraint code for combining transforms
with special anti-shear scale handling that matches the
Aligned Inherit Scale mode.
The Before mode also requires switching the constraint to
the Local owner space, while the After mode can still use the
World space for efficiency as before. Since the constraint
doesn't have an Owner space option in the UI, this has to be
handled in an RNA setter.
For full backward compatibility, the original simple matrix
multiplication mode is preserved as the third option, but it
is not recommended due to creating shear.
Differential Revision: https://developer.blender.org/D6297
2019-11-23 13:11:39 +03:00
|
|
|
|
|
|
|
loc_rot_size_to_mat4(R, loc_r, rot_r, size_r);
|
|
|
|
}
|
|
|
|
|
2009-11-09 22:42:41 +00:00
|
|
|
/****************************** Linear Algebra *******************************/
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void transpose_m3(float R[3][3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
float t;
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
t = R[0][1];
|
|
|
|
R[0][1] = R[1][0];
|
|
|
|
R[1][0] = t;
|
|
|
|
t = R[0][2];
|
|
|
|
R[0][2] = R[2][0];
|
|
|
|
R[2][0] = t;
|
|
|
|
t = R[1][2];
|
|
|
|
R[1][2] = R[2][1];
|
|
|
|
R[2][1] = t;
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void transpose_m3_m3(float R[3][3], const float M[3][3])
|
2014-10-30 12:13:00 +01:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
BLI_assert(R != M);
|
2014-10-30 12:13:00 +01:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
R[0][0] = M[0][0];
|
|
|
|
R[0][1] = M[1][0];
|
|
|
|
R[0][2] = M[2][0];
|
|
|
|
R[1][0] = M[0][1];
|
|
|
|
R[1][1] = M[1][1];
|
|
|
|
R[1][2] = M[2][1];
|
|
|
|
R[2][0] = M[0][2];
|
|
|
|
R[2][1] = M[1][2];
|
|
|
|
R[2][2] = M[2][2];
|
2014-10-30 12:13:00 +01:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void transpose_m3_m4(float R[3][3], const float M[4][4])
|
2014-10-30 12:13:00 +01:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
BLI_assert(&R[0][0] != &M[0][0]);
|
2014-10-30 12:13:00 +01:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
R[0][0] = M[0][0];
|
|
|
|
R[0][1] = M[1][0];
|
|
|
|
R[0][2] = M[2][0];
|
|
|
|
R[1][0] = M[0][1];
|
|
|
|
R[1][1] = M[1][1];
|
|
|
|
R[1][2] = M[2][1];
|
|
|
|
R[2][0] = M[0][2];
|
|
|
|
R[2][1] = M[1][2];
|
|
|
|
R[2][2] = M[2][2];
|
2014-10-30 12:13:00 +01:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void transpose_m4(float R[4][4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
float t;
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
t = R[0][1];
|
|
|
|
R[0][1] = R[1][0];
|
|
|
|
R[1][0] = t;
|
|
|
|
t = R[0][2];
|
|
|
|
R[0][2] = R[2][0];
|
|
|
|
R[2][0] = t;
|
|
|
|
t = R[0][3];
|
|
|
|
R[0][3] = R[3][0];
|
|
|
|
R[3][0] = t;
|
|
|
|
|
|
|
|
t = R[1][2];
|
|
|
|
R[1][2] = R[2][1];
|
|
|
|
R[2][1] = t;
|
|
|
|
t = R[1][3];
|
|
|
|
R[1][3] = R[3][1];
|
|
|
|
R[3][1] = t;
|
|
|
|
|
|
|
|
t = R[2][3];
|
|
|
|
R[2][3] = R[3][2];
|
|
|
|
R[3][2] = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
void transpose_m4_m4(float R[4][4], const float M[4][4])
|
|
|
|
{
|
|
|
|
BLI_assert(R != M);
|
|
|
|
|
|
|
|
R[0][0] = M[0][0];
|
|
|
|
R[0][1] = M[1][0];
|
|
|
|
R[0][2] = M[2][0];
|
|
|
|
R[0][3] = M[3][0];
|
|
|
|
R[1][0] = M[0][1];
|
|
|
|
R[1][1] = M[1][1];
|
|
|
|
R[1][2] = M[2][1];
|
|
|
|
R[1][3] = M[3][1];
|
|
|
|
R[2][0] = M[0][2];
|
|
|
|
R[2][1] = M[1][2];
|
|
|
|
R[2][2] = M[2][2];
|
|
|
|
R[2][3] = M[3][2];
|
|
|
|
R[3][0] = M[0][3];
|
|
|
|
R[3][1] = M[1][3];
|
|
|
|
R[3][2] = M[2][3];
|
|
|
|
R[3][3] = M[3][3];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool compare_m4m4(const float mat1[4][4], const float mat2[4][4], float limit)
|
Blender Internal Render in viewport
Because of our release soon, feature has been added behind the Debug Menu.
CTRL+ALT+D and set it to -1. Or commandline --debug-value -1.
When debug set to -1, you can put the viewport to 'render' mode, just like
for Cycles. Notes for testers: (and please no bugs in tracker for this :)
- It renders without AA, MBlur, Panorama, Sequence, Composite
- Only active render layer gets rendered. Select another layer will re-render.
- But yes: it works for FreeStyle renders!
- Also does great for local view.
- BI is not well suited for incremental renders on view changes. This only
works for non-raytrace scenes, or zoom in ortho or camera mode, or for
Material changes. In most cases a full re-render is being done.
- ESC works to stop the preview render.
- Borders render as well. (CTRL+B)
- Force a refresh with arrow key left/right. A lot of settings don't trigger
re-render yet.
Tech notes:
- FreeStyle is adding a lot of temp objects/meshes in the Main database. This
caused DepsGraph to trigger changes (and redraws). I've prepended the names
for these temp objects with char number 27 (ESC), and made these names be
ignored for tag update checking.
- Fixed some bugs that were noticable with such excessive re-renders, like
for opening file window, quit during renders.
2013-04-16 17:39:20 +00:00
|
|
|
{
|
2019-03-27 13:16:10 +11:00
|
|
|
if (compare_v4v4(mat1[0], mat2[0], limit)) {
|
|
|
|
if (compare_v4v4(mat1[1], mat2[1], limit)) {
|
|
|
|
if (compare_v4v4(mat1[2], mat2[2], limit)) {
|
|
|
|
if (compare_v4v4(mat1[3], mat2[3], limit)) {
|
2020-09-04 20:59:13 +02:00
|
|
|
return true;
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
return false;
|
Blender Internal Render in viewport
Because of our release soon, feature has been added behind the Debug Menu.
CTRL+ALT+D and set it to -1. Or commandline --debug-value -1.
When debug set to -1, you can put the viewport to 'render' mode, just like
for Cycles. Notes for testers: (and please no bugs in tracker for this :)
- It renders without AA, MBlur, Panorama, Sequence, Composite
- Only active render layer gets rendered. Select another layer will re-render.
- But yes: it works for FreeStyle renders!
- Also does great for local view.
- BI is not well suited for incremental renders on view changes. This only
works for non-raytrace scenes, or zoom in ortho or camera mode, or for
Material changes. In most cases a full re-render is being done.
- ESC works to stop the preview render.
- Borders render as well. (CTRL+B)
- Force a refresh with arrow key left/right. A lot of settings don't trigger
re-render yet.
Tech notes:
- FreeStyle is adding a lot of temp objects/meshes in the Main database. This
caused DepsGraph to trigger changes (and redraws). I've prepended the names
for these temp objects with char number 27 (ESC), and made these names be
ignored for tag update checking.
- Fixed some bugs that were noticable with such excessive re-renders, like
for opening file window, quit during renders.
2013-04-16 17:39:20 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void orthogonalize_m3(float R[3][3], int axis)
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
float size[3];
|
2020-09-04 20:59:13 +02:00
|
|
|
mat3_to_size(size, R);
|
|
|
|
normalize_v3(R[axis]);
|
2012-03-25 12:41:58 +00:00
|
|
|
switch (axis) {
|
2009-11-09 22:42:41 +00:00
|
|
|
case 0:
|
2020-09-04 20:59:13 +02:00
|
|
|
if (dot_v3v3(R[0], R[1]) < 1) {
|
|
|
|
cross_v3_v3v3(R[2], R[0], R[1]);
|
|
|
|
normalize_v3(R[2]);
|
|
|
|
cross_v3_v3v3(R[1], R[2], R[0]);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
else if (dot_v3v3(R[0], R[2]) < 1) {
|
|
|
|
cross_v3_v3v3(R[1], R[2], R[0]);
|
|
|
|
normalize_v3(R[1]);
|
|
|
|
cross_v3_v3v3(R[2], R[0], R[1]);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2010-11-02 13:12:30 +00:00
|
|
|
float vec[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
vec[0] = R[0][1];
|
|
|
|
vec[1] = R[0][2];
|
|
|
|
vec[2] = R[0][0];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
cross_v3_v3v3(R[2], R[0], vec);
|
|
|
|
normalize_v3(R[2]);
|
|
|
|
cross_v3_v3v3(R[1], R[2], R[0]);
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
2013-07-13 06:54:44 +00:00
|
|
|
break;
|
2009-11-09 22:42:41 +00:00
|
|
|
case 1:
|
2020-09-04 20:59:13 +02:00
|
|
|
if (dot_v3v3(R[1], R[0]) < 1) {
|
|
|
|
cross_v3_v3v3(R[2], R[0], R[1]);
|
|
|
|
normalize_v3(R[2]);
|
|
|
|
cross_v3_v3v3(R[0], R[1], R[2]);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
else if (dot_v3v3(R[0], R[2]) < 1) {
|
|
|
|
cross_v3_v3v3(R[0], R[1], R[2]);
|
|
|
|
normalize_v3(R[0]);
|
|
|
|
cross_v3_v3v3(R[2], R[0], R[1]);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2010-11-02 13:12:30 +00:00
|
|
|
float vec[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
vec[0] = R[1][1];
|
|
|
|
vec[1] = R[1][2];
|
|
|
|
vec[2] = R[1][0];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
cross_v3_v3v3(R[0], R[1], vec);
|
|
|
|
normalize_v3(R[0]);
|
|
|
|
cross_v3_v3v3(R[2], R[0], R[1]);
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
2013-07-13 06:54:44 +00:00
|
|
|
break;
|
2009-11-09 22:42:41 +00:00
|
|
|
case 2:
|
2020-09-04 20:59:13 +02:00
|
|
|
if (dot_v3v3(R[2], R[0]) < 1) {
|
|
|
|
cross_v3_v3v3(R[1], R[2], R[0]);
|
|
|
|
normalize_v3(R[1]);
|
|
|
|
cross_v3_v3v3(R[0], R[1], R[2]);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
else if (dot_v3v3(R[2], R[1]) < 1) {
|
|
|
|
cross_v3_v3v3(R[0], R[1], R[2]);
|
|
|
|
normalize_v3(R[0]);
|
|
|
|
cross_v3_v3v3(R[1], R[2], R[0]);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2010-11-02 13:12:30 +00:00
|
|
|
float vec[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
vec[0] = R[2][1];
|
|
|
|
vec[1] = R[2][2];
|
|
|
|
vec[2] = R[2][0];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
cross_v3_v3v3(R[0], vec, R[2]);
|
|
|
|
normalize_v3(R[0]);
|
|
|
|
cross_v3_v3v3(R[1], R[2], R[0]);
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
2013-07-16 11:39:48 +00:00
|
|
|
break;
|
2013-07-13 06:54:44 +00:00
|
|
|
default:
|
|
|
|
BLI_assert(0);
|
2013-07-21 08:16:37 +00:00
|
|
|
break;
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
mul_v3_fl(R[0], size[0]);
|
|
|
|
mul_v3_fl(R[1], size[1]);
|
|
|
|
mul_v3_fl(R[2], size[2]);
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void orthogonalize_m4(float R[4][4], int axis)
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
float size[3];
|
2020-09-04 20:59:13 +02:00
|
|
|
mat4_to_size(size, R);
|
|
|
|
normalize_v3(R[axis]);
|
2012-03-25 12:41:58 +00:00
|
|
|
switch (axis) {
|
2009-11-09 22:42:41 +00:00
|
|
|
case 0:
|
2020-09-04 20:59:13 +02:00
|
|
|
if (dot_v3v3(R[0], R[1]) < 1) {
|
|
|
|
cross_v3_v3v3(R[2], R[0], R[1]);
|
|
|
|
normalize_v3(R[2]);
|
|
|
|
cross_v3_v3v3(R[1], R[2], R[0]);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
else if (dot_v3v3(R[0], R[2]) < 1) {
|
|
|
|
cross_v3_v3v3(R[1], R[2], R[0]);
|
|
|
|
normalize_v3(R[1]);
|
|
|
|
cross_v3_v3v3(R[2], R[0], R[1]);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2010-11-02 13:12:30 +00:00
|
|
|
float vec[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
vec[0] = R[0][1];
|
|
|
|
vec[1] = R[0][2];
|
|
|
|
vec[2] = R[0][0];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
cross_v3_v3v3(R[2], R[0], vec);
|
|
|
|
normalize_v3(R[2]);
|
|
|
|
cross_v3_v3v3(R[1], R[2], R[0]);
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
2013-07-13 06:54:44 +00:00
|
|
|
break;
|
2009-11-09 22:42:41 +00:00
|
|
|
case 1:
|
2020-09-04 20:59:13 +02:00
|
|
|
if (dot_v3v3(R[1], R[0]) < 1) {
|
|
|
|
cross_v3_v3v3(R[2], R[0], R[1]);
|
|
|
|
normalize_v3(R[2]);
|
|
|
|
cross_v3_v3v3(R[0], R[1], R[2]);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
else if (dot_v3v3(R[0], R[2]) < 1) {
|
|
|
|
cross_v3_v3v3(R[0], R[1], R[2]);
|
|
|
|
normalize_v3(R[0]);
|
|
|
|
cross_v3_v3v3(R[2], R[0], R[1]);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2010-11-02 13:12:30 +00:00
|
|
|
float vec[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
vec[0] = R[1][1];
|
|
|
|
vec[1] = R[1][2];
|
|
|
|
vec[2] = R[1][0];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
cross_v3_v3v3(R[0], R[1], vec);
|
|
|
|
normalize_v3(R[0]);
|
|
|
|
cross_v3_v3v3(R[2], R[0], R[1]);
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
2013-07-13 06:54:44 +00:00
|
|
|
break;
|
2009-11-09 22:42:41 +00:00
|
|
|
case 2:
|
2020-09-04 20:59:13 +02:00
|
|
|
if (dot_v3v3(R[2], R[0]) < 1) {
|
|
|
|
cross_v3_v3v3(R[1], R[2], R[0]);
|
|
|
|
normalize_v3(R[1]);
|
|
|
|
cross_v3_v3v3(R[0], R[1], R[2]);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
else if (dot_v3v3(R[2], R[1]) < 1) {
|
|
|
|
cross_v3_v3v3(R[0], R[1], R[2]);
|
|
|
|
normalize_v3(R[0]);
|
|
|
|
cross_v3_v3v3(R[1], R[2], R[0]);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2010-11-02 13:12:30 +00:00
|
|
|
float vec[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
vec[0] = R[2][1];
|
|
|
|
vec[1] = R[2][2];
|
|
|
|
vec[2] = R[2][0];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
cross_v3_v3v3(R[0], vec, R[2]);
|
|
|
|
normalize_v3(R[0]);
|
|
|
|
cross_v3_v3v3(R[1], R[2], R[0]);
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
2013-07-13 06:54:44 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BLI_assert(0);
|
2013-07-21 08:16:37 +00:00
|
|
|
break;
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
mul_v3_fl(R[0], size[0]);
|
|
|
|
mul_v3_fl(R[1], size[1]);
|
|
|
|
mul_v3_fl(R[2], size[2]);
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
Armature: add Inherit Scale options to remove shear or average the scale.
As an inherent property of matrix-based transformation math, non-
uniform scaling of a parent bone induces shear into the transform
matrix of any rotated child. Such matrices cannot be cleanly
decomposed into a combination of location/rotation/scale, which
causes issues for rigging and animation tools.
Blender bones have options to exclude rotation and/or scale from the
inherited transformation, but don't have any support for removing the
often undesired shear component. That goal requires replacing simple
parenting with a combination of multiple bones and constraints. The
same is true about the goal of inheriting some scale, but completely
avoiding shear.
This patch replaces the old Inherit Scale checkbox with a enum that
supports multiple options:
* Full: inherit all effects of scale, like with enabled Inherit Scale.
* Fix Shear: removes shear from the final inherited transformation.
The cleanup math is specifically designed to preserve the main
axis of the bone, its length and total volume, and minimally
affect roll on average. It however will not prevent reappearance
of shear due to local rotation of the child or its children.
* Average: inherit uniform scale that represents the parent volume.
This is the simplest foolproof solution that will inherit some
scale without ever causing shear.
* None: completely remove scale and shear.
* None (Legacy): old disabled Inherit Scale checkbox.
This mode does not handle parent shear in any way, so the child
is likely to end up having both scale and shear. It is retained
for backward compatibility.
Since many rigging-related addons access the use_inherit_scale
property from Python, it is retained as a backward compatibility
stub that provides the old functionality.
As a side effect of reworking the code, this also fixes a matrix
multiplication order bug in the Inherit Rotation code, which caused
the parent local scale to be applied in world space. In rigger
opinion this option is useless in production rigs, so this fix
should not be a problem.
Reviewers: brecht
Differential Revision: https://developer.blender.org/D5588
2019-09-04 10:10:27 +03:00
|
|
|
/** Make an orthonormal basis around v1 in a way that is stable and symmetric. */
|
|
|
|
static void orthogonalize_stable(float v1[3], float v2[3], float v3[3], bool normalize)
|
|
|
|
{
|
|
|
|
/* Make secondary axis vectors orthogonal to the primary via
|
|
|
|
* plane projection, which preserves the determinant. */
|
|
|
|
float len_sq_v1 = len_squared_v3(v1);
|
|
|
|
|
|
|
|
if (len_sq_v1 > 0.0f) {
|
|
|
|
madd_v3_v3fl(v2, v1, -dot_v3v3(v2, v1) / len_sq_v1);
|
|
|
|
madd_v3_v3fl(v3, v1, -dot_v3v3(v3, v1) / len_sq_v1);
|
|
|
|
|
|
|
|
if (normalize) {
|
|
|
|
mul_v3_fl(v1, 1.0f / sqrtf(len_sq_v1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make secondary axis vectors orthogonal relative to each other. */
|
|
|
|
float norm_v2[3], norm_v3[3], tmp[3];
|
|
|
|
float length_v2 = normalize_v3_v3(norm_v2, v2);
|
|
|
|
float length_v3 = normalize_v3_v3(norm_v3, v3);
|
|
|
|
float cos_angle = dot_v3v3(norm_v2, norm_v3);
|
|
|
|
float abs_cos_angle = fabsf(cos_angle);
|
|
|
|
|
|
|
|
/* Apply correction if the shear angle is significant, and not degenerate. */
|
|
|
|
if (abs_cos_angle > 1e-4f && abs_cos_angle < 1.0f - FLT_EPSILON) {
|
|
|
|
/* Adjust v2 by half of the necessary angle correction.
|
|
|
|
* Thus the angle change is the same for both axis directions. */
|
|
|
|
float angle = acosf(cos_angle);
|
|
|
|
float target_angle = angle + ((float)M_PI_2 - angle) / 2;
|
|
|
|
|
|
|
|
madd_v3_v3fl(norm_v2, norm_v3, -cos_angle);
|
|
|
|
mul_v3_fl(norm_v2, sinf(target_angle) / len_v3(norm_v2));
|
|
|
|
madd_v3_v3fl(norm_v2, norm_v3, cosf(target_angle));
|
|
|
|
|
|
|
|
/* Make v3 orthogonal. */
|
|
|
|
cross_v3_v3v3(tmp, norm_v2, norm_v3);
|
|
|
|
cross_v3_v3v3(norm_v3, tmp, norm_v2);
|
|
|
|
normalize_v3(norm_v3);
|
|
|
|
|
|
|
|
/* Re-apply scale, preserving area and proportion. */
|
|
|
|
if (!normalize) {
|
|
|
|
float scale_fac = sqrtf(sinf(angle));
|
|
|
|
mul_v3_v3fl(v2, norm_v2, length_v2 * scale_fac);
|
|
|
|
mul_v3_v3fl(v3, norm_v3, length_v3 * scale_fac);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (normalize) {
|
|
|
|
copy_v3_v3(v2, norm_v2);
|
|
|
|
copy_v3_v3(v3, norm_v3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize)
|
|
|
|
{
|
|
|
|
switch (axis) {
|
|
|
|
case 0:
|
|
|
|
orthogonalize_stable(R[0], R[1], R[2], normalize);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
orthogonalize_stable(R[1], R[0], R[2], normalize);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
orthogonalize_stable(R[2], R[0], R[1], normalize);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BLI_assert(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize)
|
|
|
|
{
|
|
|
|
switch (axis) {
|
|
|
|
case 0:
|
|
|
|
orthogonalize_stable(R[0], R[1], R[2], normalize);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
orthogonalize_stable(R[1], R[0], R[2], normalize);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
orthogonalize_stable(R[2], R[0], R[1], normalize);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BLI_assert(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-01 21:16:09 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Orthogonalize Matrix Zeroed Axes
|
|
|
|
*
|
|
|
|
* Set any zeroed axes to an orthogonal vector in relation to the other axes.
|
|
|
|
*
|
|
|
|
* Typically used so matrix inversion can be performed.
|
|
|
|
*
|
|
|
|
* \note If an object has a zero scaled axis, this function can be used to "clean" the matrix
|
|
|
|
* to behave as if the scale on that axis was `unit_length`. So it can be inverted
|
|
|
|
* or used in matrix multiply without creating degenerate matrices, see: T50103
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \return true if any axis needed to be modified.
|
|
|
|
*/
|
|
|
|
static bool orthogonalize_m3_zero_axes_impl(float *mat[3], const float unit_length)
|
|
|
|
{
|
|
|
|
enum { X = 1 << 0, Y = 1 << 1, Z = 1 << 2 };
|
|
|
|
int flag = 0;
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
flag |= (len_squared_v3(mat[i]) == 0.0f) ? (1 << i) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Either all or none are zero, either way we can't properly resolve this
|
|
|
|
* since we need to fill invalid axes from valid ones. */
|
|
|
|
if (ELEM(flag, 0, X | Y | Z)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (flag) {
|
|
|
|
case X | Y: {
|
|
|
|
ortho_v3_v3(mat[1], mat[2]);
|
|
|
|
ATTR_FALLTHROUGH;
|
|
|
|
}
|
|
|
|
case X: {
|
|
|
|
cross_v3_v3v3(mat[0], mat[1], mat[2]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Y | Z: {
|
|
|
|
ortho_v3_v3(mat[2], mat[0]);
|
|
|
|
ATTR_FALLTHROUGH;
|
|
|
|
}
|
|
|
|
case Y: {
|
|
|
|
cross_v3_v3v3(mat[1], mat[0], mat[2]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case Z | X: {
|
|
|
|
ortho_v3_v3(mat[0], mat[1]);
|
|
|
|
ATTR_FALLTHROUGH;
|
|
|
|
}
|
|
|
|
case Z: {
|
|
|
|
cross_v3_v3v3(mat[2], mat[0], mat[1]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
BLI_assert(0); /* Unreachable! */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
if (flag & (1 << i)) {
|
|
|
|
if (UNLIKELY(normalize_v3_length(mat[i], unit_length) == 0.0f)) {
|
|
|
|
mat[i][i] = unit_length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool orthogonalize_m3_zero_axes(float m[3][3], const float unit_length)
|
|
|
|
{
|
|
|
|
return orthogonalize_m3_zero_axes_impl((float *[3]){UNPACK3(m)}, unit_length);
|
|
|
|
}
|
|
|
|
bool orthogonalize_m4_zero_axes(float m[4][4], const float unit_length)
|
|
|
|
{
|
|
|
|
return orthogonalize_m3_zero_axes_impl((float *[3]){UNPACK3(m)}, unit_length);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
bool is_orthogonal_m3(const float m[3][3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2012-03-24 07:36:32 +00:00
|
|
|
int i, j;
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2012-03-24 07:36:32 +00:00
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
for (j = 0; j < i; j++) {
|
2019-03-27 13:16:10 +11:00
|
|
|
if (fabsf(dot_v3v3(m[i], m[j])) > 1e-5f) {
|
2014-12-01 14:33:38 +01:00
|
|
|
return false;
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
2012-03-24 07:36:32 +00:00
|
|
|
}
|
|
|
|
}
|
2012-01-26 17:11:43 +00:00
|
|
|
|
2014-12-01 14:33:38 +01:00
|
|
|
return true;
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
bool is_orthogonal_m4(const float m[4][4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2012-03-24 07:36:32 +00:00
|
|
|
int i, j;
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2012-03-24 07:36:32 +00:00
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
for (j = 0; j < i; j++) {
|
2019-03-27 13:16:10 +11:00
|
|
|
if (fabsf(dot_v4v4(m[i], m[j])) > 1e-5f) {
|
2014-12-01 14:33:38 +01:00
|
|
|
return false;
|
2012-03-24 07:36:32 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
2012-01-26 17:11:43 +00:00
|
|
|
|
2014-12-01 14:33:38 +01:00
|
|
|
return true;
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
bool is_orthonormal_m3(const float m[3][3])
|
2012-04-01 00:14:41 +00:00
|
|
|
{
|
|
|
|
if (is_orthogonal_m3(m)) {
|
|
|
|
int i;
|
|
|
|
|
2019-03-27 13:16:10 +11:00
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
if (fabsf(dot_v3v3(m[i], m[i]) - 1) > 1e-5f) {
|
2014-12-01 14:33:38 +01:00
|
|
|
return false;
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
|
|
|
}
|
2012-04-01 00:14:41 +00:00
|
|
|
|
2014-12-01 14:33:38 +01:00
|
|
|
return true;
|
2012-04-01 00:14:41 +00:00
|
|
|
}
|
|
|
|
|
2014-12-01 14:33:38 +01:00
|
|
|
return false;
|
2012-04-01 00:14:41 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
bool is_orthonormal_m4(const float m[4][4])
|
2012-04-01 00:14:41 +00:00
|
|
|
{
|
|
|
|
if (is_orthogonal_m4(m)) {
|
|
|
|
int i;
|
|
|
|
|
2019-05-31 22:51:19 +10:00
|
|
|
for (i = 0; i < 4; i++) {
|
2019-03-27 13:16:10 +11:00
|
|
|
if (fabsf(dot_v4v4(m[i], m[i]) - 1) > 1e-5f) {
|
2014-12-01 14:33:38 +01:00
|
|
|
return false;
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
2019-05-31 22:51:19 +10:00
|
|
|
}
|
2012-04-01 00:14:41 +00:00
|
|
|
|
2014-12-01 14:33:38 +01:00
|
|
|
return true;
|
2012-04-01 00:14:41 +00:00
|
|
|
}
|
|
|
|
|
2014-12-01 14:33:38 +01:00
|
|
|
return false;
|
2012-04-01 00:14:41 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
bool is_uniform_scaled_m3(const float m[3][3])
|
2012-05-01 11:01:24 +00:00
|
|
|
{
|
2013-12-06 03:46:27 +11:00
|
|
|
const float eps = 1e-7f;
|
2012-05-01 11:01:24 +00:00
|
|
|
float t[3][3];
|
|
|
|
float l1, l2, l3, l4, l5, l6;
|
|
|
|
|
2014-10-30 12:13:00 +01:00
|
|
|
transpose_m3_m3(t, m);
|
2012-05-01 11:01:24 +00:00
|
|
|
|
|
|
|
l1 = len_squared_v3(m[0]);
|
|
|
|
l2 = len_squared_v3(m[1]);
|
|
|
|
l3 = len_squared_v3(m[2]);
|
|
|
|
|
|
|
|
l4 = len_squared_v3(t[0]);
|
|
|
|
l5 = len_squared_v3(t[1]);
|
|
|
|
l6 = len_squared_v3(t[2]);
|
|
|
|
|
|
|
|
if (fabsf(l2 - l1) <= eps && fabsf(l3 - l1) <= eps && fabsf(l4 - l1) <= eps &&
|
|
|
|
fabsf(l5 - l1) <= eps && fabsf(l6 - l1) <= eps) {
|
2014-05-22 21:35:41 -03:00
|
|
|
return true;
|
2012-05-01 11:01:24 +00:00
|
|
|
}
|
|
|
|
|
2014-05-22 21:35:41 -03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
bool is_uniform_scaled_m4(const float m[4][4])
|
2014-05-22 21:35:41 -03:00
|
|
|
{
|
|
|
|
float t[3][3];
|
|
|
|
copy_m3_m4(t, m);
|
|
|
|
return is_uniform_scaled_m3(t);
|
2012-05-01 11:01:24 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void normalize_m2_ex(float R[2][2], float r_scale[2])
|
2020-02-20 12:48:42 +11:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 2; i++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
r_scale[i] = normalize_v2(R[i]);
|
2020-02-20 12:48:42 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void normalize_m2(float R[2][2])
|
2020-02-20 12:48:42 +11:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 2; i++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
normalize_v2(R[i]);
|
2020-02-20 12:48:42 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void normalize_m2_m2_ex(float R[2][2], const float M[2][2], float r_scale[2])
|
2020-02-20 12:48:42 +11:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 2; i++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
r_scale[i] = normalize_v2_v2(R[i], M[i]);
|
2020-02-20 12:48:42 +11:00
|
|
|
}
|
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
void normalize_m2_m2(float R[2][2], const float M[2][2])
|
2020-02-20 12:48:42 +11:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 2; i++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
normalize_v2_v2(R[i], M[i]);
|
2020-02-20 12:48:42 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void normalize_m3_ex(float R[3][3], float r_scale[3])
|
2015-10-15 21:03:27 +11:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 3; i++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
r_scale[i] = normalize_v3(R[i]);
|
2015-10-15 21:03:27 +11:00
|
|
|
}
|
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
void normalize_m3(float R[3][3])
|
2012-03-25 12:41:58 +00:00
|
|
|
{
|
2015-10-15 21:03:27 +11:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < 3; i++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
normalize_v3(R[i]);
|
2015-10-15 21:03:27 +11:00
|
|
|
}
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void normalize_m3_m3_ex(float R[3][3], const float M[3][3], float r_scale[3])
|
2015-10-15 21:03:27 +11:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 3; i++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
r_scale[i] = normalize_v3_v3(R[i], M[i]);
|
2015-10-15 21:03:27 +11:00
|
|
|
}
|
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
void normalize_m3_m3(float R[3][3], const float M[3][3])
|
2012-03-25 12:41:58 +00:00
|
|
|
{
|
2015-10-15 21:03:27 +11:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < 3; i++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
normalize_v3_v3(R[i], M[i]);
|
2015-10-15 21:03:27 +11:00
|
|
|
}
|
2010-10-18 02:36:43 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void normalize_m4_ex(float R[4][4], float r_scale[3])
|
2015-10-15 21:03:27 +11:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 3; i++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
r_scale[i] = normalize_v3(R[i]);
|
2015-10-15 21:03:27 +11:00
|
|
|
if (r_scale[i] != 0.0f) {
|
2020-09-04 20:59:13 +02:00
|
|
|
R[i][3] /= r_scale[i];
|
2015-10-15 21:03:27 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-04 20:59:13 +02:00
|
|
|
void normalize_m4(float R[4][4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2015-10-15 21:03:27 +11:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < 3; i++) {
|
2020-09-04 20:59:13 +02:00
|
|
|
float len = normalize_v3(R[i]);
|
2015-10-15 21:03:27 +11:00
|
|
|
if (len != 0.0f) {
|
2020-09-04 20:59:13 +02:00
|
|
|
R[i][3] /= len;
|
2015-10-15 21:03:27 +11:00
|
|
|
}
|
|
|
|
}
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void normalize_m4_m4_ex(float rmat[4][4], const float mat[4][4], float r_scale[3])
|
2015-10-15 21:03:27 +11:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
r_scale[i] = normalize_v3_v3(rmat[i], mat[i]);
|
|
|
|
rmat[i][3] = (r_scale[i] != 0.0f) ? (mat[i][3] / r_scale[i]) : mat[i][3];
|
|
|
|
}
|
2015-10-15 21:28:07 +11:00
|
|
|
copy_v4_v4(rmat[3], mat[3]);
|
2015-10-15 21:03:27 +11:00
|
|
|
}
|
2016-09-24 16:21:38 +02:00
|
|
|
void normalize_m4_m4(float rmat[4][4], const float mat[4][4])
|
2010-10-18 02:36:43 +00:00
|
|
|
{
|
2015-10-15 21:03:27 +11:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
float len = normalize_v3_v3(rmat[i], mat[i]);
|
|
|
|
rmat[i][3] = (len != 0.0f) ? (mat[i][3] / len) : mat[i][3];
|
|
|
|
}
|
2015-10-15 21:28:07 +11:00
|
|
|
copy_v4_v4(rmat[3], mat[3]);
|
2010-10-18 02:36:43 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void adjoint_m2_m2(float R[2][2], const float M[2][2])
|
2012-10-29 03:36:55 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
BLI_assert(R != M);
|
|
|
|
R[0][0] = M[1][1];
|
|
|
|
R[0][1] = -M[0][1];
|
|
|
|
R[1][0] = -M[1][0];
|
|
|
|
R[1][1] = M[0][0];
|
2012-10-29 03:36:55 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void adjoint_m3_m3(float R[3][3], const float M[3][3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
BLI_assert(R != M);
|
|
|
|
R[0][0] = M[1][1] * M[2][2] - M[1][2] * M[2][1];
|
|
|
|
R[0][1] = -M[0][1] * M[2][2] + M[0][2] * M[2][1];
|
|
|
|
R[0][2] = M[0][1] * M[1][2] - M[0][2] * M[1][1];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
R[1][0] = -M[1][0] * M[2][2] + M[1][2] * M[2][0];
|
|
|
|
R[1][1] = M[0][0] * M[2][2] - M[0][2] * M[2][0];
|
|
|
|
R[1][2] = -M[0][0] * M[1][2] + M[0][2] * M[1][0];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
R[2][0] = M[1][0] * M[2][1] - M[1][1] * M[2][0];
|
|
|
|
R[2][1] = -M[0][0] * M[2][1] + M[0][1] * M[2][0];
|
|
|
|
R[2][2] = M[0][0] * M[1][1] - M[0][1] * M[1][0];
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void adjoint_m4_m4(float R[4][4], const float M[4][4]) /* out = ADJ(in) */
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
float a1, a2, a3, a4, b1, b2, b3, b4;
|
|
|
|
float c1, c2, c3, c4, d1, d2, d3, d4;
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
a1 = M[0][0];
|
|
|
|
b1 = M[0][1];
|
|
|
|
c1 = M[0][2];
|
|
|
|
d1 = M[0][3];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
a2 = M[1][0];
|
|
|
|
b2 = M[1][1];
|
|
|
|
c2 = M[1][2];
|
|
|
|
d2 = M[1][3];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
a3 = M[2][0];
|
|
|
|
b3 = M[2][1];
|
|
|
|
c3 = M[2][2];
|
|
|
|
d3 = M[2][3];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
a4 = M[3][0];
|
|
|
|
b4 = M[3][1];
|
|
|
|
c4 = M[3][2];
|
|
|
|
d4 = M[3][3];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
R[0][0] = determinant_m3(b2, b3, b4, c2, c3, c4, d2, d3, d4);
|
|
|
|
R[1][0] = -determinant_m3(a2, a3, a4, c2, c3, c4, d2, d3, d4);
|
|
|
|
R[2][0] = determinant_m3(a2, a3, a4, b2, b3, b4, d2, d3, d4);
|
|
|
|
R[3][0] = -determinant_m3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
R[0][1] = -determinant_m3(b1, b3, b4, c1, c3, c4, d1, d3, d4);
|
|
|
|
R[1][1] = determinant_m3(a1, a3, a4, c1, c3, c4, d1, d3, d4);
|
|
|
|
R[2][1] = -determinant_m3(a1, a3, a4, b1, b3, b4, d1, d3, d4);
|
|
|
|
R[3][1] = determinant_m3(a1, a3, a4, b1, b3, b4, c1, c3, c4);
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
R[0][2] = determinant_m3(b1, b2, b4, c1, c2, c4, d1, d2, d4);
|
|
|
|
R[1][2] = -determinant_m3(a1, a2, a4, c1, c2, c4, d1, d2, d4);
|
|
|
|
R[2][2] = determinant_m3(a1, a2, a4, b1, b2, b4, d1, d2, d4);
|
|
|
|
R[3][2] = -determinant_m3(a1, a2, a4, b1, b2, b4, c1, c2, c4);
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
R[0][3] = -determinant_m3(b1, b2, b3, c1, c2, c3, d1, d2, d3);
|
|
|
|
R[1][3] = determinant_m3(a1, a2, a3, c1, c2, c3, d1, d2, d3);
|
|
|
|
R[2][3] = -determinant_m3(a1, a2, a3, b1, b2, b3, d1, d2, d3);
|
|
|
|
R[3][3] = determinant_m3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
float determinant_m2(float a, float b, float c, float d)
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
return a * d - b * c;
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
float determinant_m3(
|
|
|
|
float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3)
|
|
|
|
{
|
|
|
|
float ans;
|
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
ans = (a1 * determinant_m2(b2, b3, c2, c3) - b1 * determinant_m2(a2, a3, c2, c3) +
|
|
|
|
c1 * determinant_m2(a2, a3, b2, b3));
|
2009-11-09 22:42:41 +00:00
|
|
|
|
|
|
|
return ans;
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
float determinant_m4(const float m[4][4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
float ans;
|
2012-03-25 12:41:58 +00:00
|
|
|
float a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4;
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
a1 = m[0][0];
|
|
|
|
b1 = m[0][1];
|
|
|
|
c1 = m[0][2];
|
|
|
|
d1 = m[0][3];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
a2 = m[1][0];
|
|
|
|
b2 = m[1][1];
|
|
|
|
c2 = m[1][2];
|
|
|
|
d2 = m[1][3];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
a3 = m[2][0];
|
|
|
|
b3 = m[2][1];
|
|
|
|
c3 = m[2][2];
|
|
|
|
d3 = m[2][3];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
a4 = m[3][0];
|
|
|
|
b4 = m[3][1];
|
|
|
|
c4 = m[3][2];
|
|
|
|
d4 = m[3][3];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
ans = (a1 * determinant_m3(b2, b3, b4, c2, c3, c4, d2, d3, d4) -
|
|
|
|
b1 * determinant_m3(a2, a3, a4, c2, c3, c4, d2, d3, d4) +
|
|
|
|
c1 * determinant_m3(a2, a3, a4, b2, b3, b4, d2, d3, d4) -
|
|
|
|
d1 * determinant_m3(a2, a3, a4, b2, b3, b4, c2, c3, c4));
|
2009-11-09 22:42:41 +00:00
|
|
|
|
|
|
|
return ans;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************** Transformations ******************************/
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void size_to_mat3(float R[3][3], const float size[3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
R[0][0] = size[0];
|
|
|
|
R[0][1] = 0.0f;
|
|
|
|
R[0][2] = 0.0f;
|
|
|
|
R[1][1] = size[1];
|
|
|
|
R[1][0] = 0.0f;
|
|
|
|
R[1][2] = 0.0f;
|
|
|
|
R[2][2] = size[2];
|
|
|
|
R[2][1] = 0.0f;
|
|
|
|
R[2][0] = 0.0f;
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void size_to_mat4(float R[4][4], const float size[3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
R[0][0] = size[0];
|
|
|
|
R[0][1] = 0.0f;
|
|
|
|
R[0][2] = 0.0f;
|
|
|
|
R[0][3] = 0.0f;
|
|
|
|
R[1][0] = 0.0f;
|
|
|
|
R[1][1] = size[1];
|
|
|
|
R[1][2] = 0.0f;
|
|
|
|
R[1][3] = 0.0f;
|
|
|
|
R[2][0] = 0.0f;
|
|
|
|
R[2][1] = 0.0f;
|
|
|
|
R[2][2] = size[2];
|
|
|
|
R[2][3] = 0.0f;
|
|
|
|
R[3][0] = 0.0f;
|
|
|
|
R[3][1] = 0.0f;
|
|
|
|
R[3][2] = 0.0f;
|
|
|
|
R[3][3] = 1.0f;
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void mat3_to_size(float size[3], const float M[3][3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
size[0] = len_v3(M[0]);
|
|
|
|
size[1] = len_v3(M[1]);
|
|
|
|
size[2] = len_v3(M[2]);
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void mat4_to_size(float size[3], const float M[4][4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
size[0] = len_v3(M[0]);
|
|
|
|
size[1] = len_v3(M[1]);
|
|
|
|
size[2] = len_v3(M[2]);
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2022-02-08 22:16:51 +11:00
|
|
|
float mat3_to_size_max_axis(const float M[3][3])
|
|
|
|
{
|
|
|
|
return sqrtf(max_fff(len_squared_v3(M[0]), len_squared_v3(M[1]), len_squared_v3(M[2])));
|
|
|
|
}
|
|
|
|
|
|
|
|
float mat4_to_size_max_axis(const float M[4][4])
|
|
|
|
{
|
|
|
|
return sqrtf(max_fff(len_squared_v3(M[0]), len_squared_v3(M[1]), len_squared_v3(M[2])));
|
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void mat4_to_size_fix_shear(float size[3], const float M[4][4])
|
Armature: add Inherit Scale options to remove shear or average the scale.
As an inherent property of matrix-based transformation math, non-
uniform scaling of a parent bone induces shear into the transform
matrix of any rotated child. Such matrices cannot be cleanly
decomposed into a combination of location/rotation/scale, which
causes issues for rigging and animation tools.
Blender bones have options to exclude rotation and/or scale from the
inherited transformation, but don't have any support for removing the
often undesired shear component. That goal requires replacing simple
parenting with a combination of multiple bones and constraints. The
same is true about the goal of inheriting some scale, but completely
avoiding shear.
This patch replaces the old Inherit Scale checkbox with a enum that
supports multiple options:
* Full: inherit all effects of scale, like with enabled Inherit Scale.
* Fix Shear: removes shear from the final inherited transformation.
The cleanup math is specifically designed to preserve the main
axis of the bone, its length and total volume, and minimally
affect roll on average. It however will not prevent reappearance
of shear due to local rotation of the child or its children.
* Average: inherit uniform scale that represents the parent volume.
This is the simplest foolproof solution that will inherit some
scale without ever causing shear.
* None: completely remove scale and shear.
* None (Legacy): old disabled Inherit Scale checkbox.
This mode does not handle parent shear in any way, so the child
is likely to end up having both scale and shear. It is retained
for backward compatibility.
Since many rigging-related addons access the use_inherit_scale
property from Python, it is retained as a backward compatibility
stub that provides the old functionality.
As a side effect of reworking the code, this also fixes a matrix
multiplication order bug in the Inherit Rotation code, which caused
the parent local scale to be applied in world space. In rigger
opinion this option is useless in production rigs, so this fix
should not be a problem.
Reviewers: brecht
Differential Revision: https://developer.blender.org/D5588
2019-09-04 10:10:27 +03:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
mat4_to_size(size, M);
|
Armature: add Inherit Scale options to remove shear or average the scale.
As an inherent property of matrix-based transformation math, non-
uniform scaling of a parent bone induces shear into the transform
matrix of any rotated child. Such matrices cannot be cleanly
decomposed into a combination of location/rotation/scale, which
causes issues for rigging and animation tools.
Blender bones have options to exclude rotation and/or scale from the
inherited transformation, but don't have any support for removing the
often undesired shear component. That goal requires replacing simple
parenting with a combination of multiple bones and constraints. The
same is true about the goal of inheriting some scale, but completely
avoiding shear.
This patch replaces the old Inherit Scale checkbox with a enum that
supports multiple options:
* Full: inherit all effects of scale, like with enabled Inherit Scale.
* Fix Shear: removes shear from the final inherited transformation.
The cleanup math is specifically designed to preserve the main
axis of the bone, its length and total volume, and minimally
affect roll on average. It however will not prevent reappearance
of shear due to local rotation of the child or its children.
* Average: inherit uniform scale that represents the parent volume.
This is the simplest foolproof solution that will inherit some
scale without ever causing shear.
* None: completely remove scale and shear.
* None (Legacy): old disabled Inherit Scale checkbox.
This mode does not handle parent shear in any way, so the child
is likely to end up having both scale and shear. It is retained
for backward compatibility.
Since many rigging-related addons access the use_inherit_scale
property from Python, it is retained as a backward compatibility
stub that provides the old functionality.
As a side effect of reworking the code, this also fixes a matrix
multiplication order bug in the Inherit Rotation code, which caused
the parent local scale to be applied in world space. In rigger
opinion this option is useless in production rigs, so this fix
should not be a problem.
Reviewers: brecht
Differential Revision: https://developer.blender.org/D5588
2019-09-04 10:10:27 +03:00
|
|
|
|
|
|
|
float volume = size[0] * size[1] * size[2];
|
|
|
|
|
|
|
|
if (volume != 0.0f) {
|
2020-09-04 20:59:13 +02:00
|
|
|
mul_v3_fl(size, cbrtf(fabsf(mat4_to_volume_scale(M) / volume)));
|
Armature: add Inherit Scale options to remove shear or average the scale.
As an inherent property of matrix-based transformation math, non-
uniform scaling of a parent bone induces shear into the transform
matrix of any rotated child. Such matrices cannot be cleanly
decomposed into a combination of location/rotation/scale, which
causes issues for rigging and animation tools.
Blender bones have options to exclude rotation and/or scale from the
inherited transformation, but don't have any support for removing the
often undesired shear component. That goal requires replacing simple
parenting with a combination of multiple bones and constraints. The
same is true about the goal of inheriting some scale, but completely
avoiding shear.
This patch replaces the old Inherit Scale checkbox with a enum that
supports multiple options:
* Full: inherit all effects of scale, like with enabled Inherit Scale.
* Fix Shear: removes shear from the final inherited transformation.
The cleanup math is specifically designed to preserve the main
axis of the bone, its length and total volume, and minimally
affect roll on average. It however will not prevent reappearance
of shear due to local rotation of the child or its children.
* Average: inherit uniform scale that represents the parent volume.
This is the simplest foolproof solution that will inherit some
scale without ever causing shear.
* None: completely remove scale and shear.
* None (Legacy): old disabled Inherit Scale checkbox.
This mode does not handle parent shear in any way, so the child
is likely to end up having both scale and shear. It is retained
for backward compatibility.
Since many rigging-related addons access the use_inherit_scale
property from Python, it is retained as a backward compatibility
stub that provides the old functionality.
As a side effect of reworking the code, this also fixes a matrix
multiplication order bug in the Inherit Rotation code, which caused
the parent local scale to be applied in world space. In rigger
opinion this option is useless in production rigs, so this fix
should not be a problem.
Reviewers: brecht
Differential Revision: https://developer.blender.org/D5588
2019-09-04 10:10:27 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-05 13:25:43 +03:00
|
|
|
float mat3_to_volume_scale(const float mat[3][3])
|
|
|
|
{
|
|
|
|
return determinant_m3_array(mat);
|
|
|
|
}
|
|
|
|
|
|
|
|
float mat4_to_volume_scale(const float mat[4][4])
|
|
|
|
{
|
|
|
|
return determinant_m4_mat3_array(mat);
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
float mat3_to_scale(const float mat[3][3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
/* unit length vector */
|
2013-07-10 12:12:58 +00:00
|
|
|
float unit_vec[3];
|
2014-11-22 18:11:46 +01:00
|
|
|
copy_v3_fl(unit_vec, (float)M_SQRT1_3);
|
2009-11-09 22:42:41 +00:00
|
|
|
mul_m3_v3(mat, unit_vec);
|
|
|
|
return len_v3(unit_vec);
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
float mat4_to_scale(const float mat[4][4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2013-07-10 12:12:58 +00:00
|
|
|
/* unit length vector */
|
|
|
|
float unit_vec[3];
|
2014-11-22 18:11:46 +01:00
|
|
|
copy_v3_fl(unit_vec, (float)M_SQRT1_3);
|
2013-07-10 12:12:58 +00:00
|
|
|
mul_mat3_m4_v3(mat, unit_vec);
|
|
|
|
return len_v3(unit_vec);
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2017-04-26 11:55:50 +02:00
|
|
|
float mat4_to_xy_scale(const float M[4][4])
|
|
|
|
{
|
|
|
|
/* unit length vector in xy plane */
|
|
|
|
float unit_vec[3] = {(float)M_SQRT1_2, (float)M_SQRT1_2, 0.0f};
|
|
|
|
mul_mat3_m4_v3(M, unit_vec);
|
|
|
|
return len_v3(unit_vec);
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3])
|
2010-10-26 12:48:07 +00:00
|
|
|
{
|
|
|
|
/* keep rot as a 3x3 matrix, the caller can convert into a quat or euler */
|
2015-05-04 22:26:38 +10:00
|
|
|
size[0] = normalize_v3_v3(rot[0], mat3[0]);
|
|
|
|
size[1] = normalize_v3_v3(rot[1], mat3[1]);
|
|
|
|
size[2] = normalize_v3_v3(rot[2], mat3[2]);
|
|
|
|
if (UNLIKELY(is_negative_m3(rot))) {
|
|
|
|
negate_m3(rot);
|
|
|
|
negate_v3(size);
|
|
|
|
}
|
2010-10-26 12:48:07 +00:00
|
|
|
}
|
|
|
|
|
2021-03-08 12:45:06 -05:00
|
|
|
void mat4_to_rot(float rot[3][3], const float wmat[4][4])
|
|
|
|
{
|
|
|
|
normalize_v3_v3(rot[0], wmat[0]);
|
|
|
|
normalize_v3_v3(rot[1], wmat[1]);
|
|
|
|
normalize_v3_v3(rot[2], wmat[2]);
|
|
|
|
if (UNLIKELY(is_negative_m3(rot))) {
|
|
|
|
negate_m3(rot);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4])
|
2010-11-22 10:39:28 +00:00
|
|
|
{
|
2012-03-25 12:41:58 +00:00
|
|
|
float mat3[3][3]; /* wmat -> 3x3 */
|
2010-11-22 10:39:28 +00:00
|
|
|
|
|
|
|
copy_m3_m4(mat3, wmat);
|
|
|
|
mat3_to_rot_size(rot, size, mat3);
|
|
|
|
|
|
|
|
/* location */
|
|
|
|
copy_v3_v3(loc, wmat[3]);
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mat4_to_loc_quat(float loc[3], float quat[4], const float wmat[4][4])
|
2013-01-23 05:56:05 +00:00
|
|
|
{
|
|
|
|
float mat3[3][3];
|
|
|
|
float mat3_n[3][3]; /* normalized mat3 */
|
|
|
|
|
|
|
|
copy_m3_m4(mat3, wmat);
|
|
|
|
normalize_m3_m3(mat3_n, mat3);
|
|
|
|
|
2021-07-03 23:08:40 +10:00
|
|
|
/* So scale doesn't interfere with rotation T24291. */
|
|
|
|
/* FIXME: this is a workaround for negative matrix not working for rotation conversion. */
|
2013-01-23 05:56:05 +00:00
|
|
|
if (is_negative_m3(mat3)) {
|
2014-10-30 12:13:00 +01:00
|
|
|
negate_m3(mat3_n);
|
2013-01-23 05:56:05 +00:00
|
|
|
}
|
|
|
|
|
2015-10-24 07:02:51 +11:00
|
|
|
mat3_normalized_to_quat(quat, mat3_n);
|
2013-01-23 05:56:05 +00:00
|
|
|
copy_v3_v3(loc, wmat[3]);
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat[4][4])
|
2013-01-23 05:56:05 +00:00
|
|
|
{
|
|
|
|
float rot[3][3];
|
|
|
|
mat4_to_loc_rot_size(loc, rot, size, wmat);
|
2015-10-24 07:02:51 +11:00
|
|
|
mat3_normalized_to_quat(quat, rot);
|
2013-01-23 05:56:05 +00:00
|
|
|
}
|
|
|
|
|
2015-10-09 20:57:37 +02:00
|
|
|
/**
|
|
|
|
* Right polar decomposition:
|
|
|
|
* M = UP
|
|
|
|
*
|
|
|
|
* U is the 'rotation'-like component, the closest orthogonal matrix to M.
|
|
|
|
* P is the 'scaling'-like component, defined in U space.
|
|
|
|
*
|
|
|
|
* See https://en.wikipedia.org/wiki/Polar_decomposition for more.
|
|
|
|
*/
|
2015-12-07 11:07:26 +11:00
|
|
|
#ifndef MATH_STANDALONE
|
2016-09-24 16:21:38 +02:00
|
|
|
void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3])
|
2015-10-09 20:57:37 +02:00
|
|
|
{
|
|
|
|
/* From svd decomposition (M = WSV*), we have:
|
|
|
|
* U = WV*
|
|
|
|
* P = VSV*
|
|
|
|
*/
|
|
|
|
float W[3][3], S[3][3], V[3][3], Vt[3][3];
|
|
|
|
float sval[3];
|
|
|
|
|
|
|
|
BLI_svd_m3(mat3, W, sval, V);
|
|
|
|
|
|
|
|
size_to_mat3(S, sval);
|
|
|
|
|
|
|
|
transpose_m3_m3(Vt, V);
|
|
|
|
mul_m3_m3m3(r_U, W, Vt);
|
|
|
|
mul_m3_series(r_P, V, S, Vt);
|
|
|
|
}
|
2015-12-07 11:07:26 +11:00
|
|
|
#endif
|
2015-10-09 20:57:37 +02:00
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void scale_m3_fl(float R[3][3], float scale)
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
R[0][0] = R[1][1] = R[2][2] = scale;
|
|
|
|
R[0][1] = R[0][2] = 0.0;
|
|
|
|
R[1][0] = R[1][2] = 0.0;
|
|
|
|
R[2][0] = R[2][1] = 0.0;
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void scale_m4_fl(float R[4][4], float scale)
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
R[0][0] = R[1][1] = R[2][2] = scale;
|
|
|
|
R[3][3] = 1.0;
|
|
|
|
R[0][1] = R[0][2] = R[0][3] = 0.0;
|
|
|
|
R[1][0] = R[1][2] = R[1][3] = 0.0;
|
|
|
|
R[2][0] = R[2][1] = R[2][3] = 0.0;
|
|
|
|
R[3][0] = R[3][1] = R[3][2] = 0.0;
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2022-01-28 08:37:12 +01:00
|
|
|
void scale_m4_v2(float R[4][4], const float scale[2])
|
|
|
|
{
|
|
|
|
R[0][0] = scale[0];
|
|
|
|
R[1][1] = scale[1];
|
|
|
|
R[2][2] = R[3][3] = 1.0;
|
|
|
|
R[0][1] = R[0][2] = R[0][3] = 0.0;
|
|
|
|
R[1][0] = R[1][2] = R[1][3] = 0.0;
|
|
|
|
R[2][0] = R[2][1] = R[2][3] = 0.0;
|
|
|
|
R[3][0] = R[3][1] = R[3][2] = 0.0;
|
|
|
|
}
|
|
|
|
|
2012-12-11 14:29:01 +00:00
|
|
|
void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2012-03-25 12:41:58 +00:00
|
|
|
mat[3][0] += (Tx * mat[0][0] + Ty * mat[1][0] + Tz * mat[2][0]);
|
|
|
|
mat[3][1] += (Tx * mat[0][1] + Ty * mat[1][1] + Tz * mat[2][1]);
|
|
|
|
mat[3][2] += (Tx * mat[0][2] + Ty * mat[1][2] + Tz * mat[2][2]);
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2012-12-11 14:29:01 +00:00
|
|
|
void rotate_m4(float mat[4][4], const char axis, const float angle)
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2016-11-25 21:00:32 +11:00
|
|
|
const float angle_cos = cosf(angle);
|
|
|
|
const float angle_sin = sinf(angle);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-08-26 14:32:35 +10:00
|
|
|
BLI_assert(axis >= 'X' && axis <= 'Z');
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-27 10:35:39 +00:00
|
|
|
switch (axis) {
|
2012-03-25 12:41:58 +00:00
|
|
|
case 'X':
|
2016-11-25 21:00:32 +11:00
|
|
|
for (int col = 0; col < 4; col++) {
|
|
|
|
float temp = angle_cos * mat[1][col] + angle_sin * mat[2][col];
|
|
|
|
mat[2][col] = -angle_sin * mat[1][col] + angle_cos * mat[2][col];
|
|
|
|
mat[1][col] = temp;
|
2012-03-25 12:41:58 +00:00
|
|
|
}
|
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
case 'Y':
|
2016-11-25 21:00:32 +11:00
|
|
|
for (int col = 0; col < 4; col++) {
|
|
|
|
float temp = angle_cos * mat[0][col] - angle_sin * mat[2][col];
|
|
|
|
mat[2][col] = angle_sin * mat[0][col] + angle_cos * mat[2][col];
|
|
|
|
mat[0][col] = temp;
|
2012-03-25 12:41:58 +00:00
|
|
|
}
|
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
case 'Z':
|
2016-11-25 21:00:32 +11:00
|
|
|
for (int col = 0; col < 4; col++) {
|
|
|
|
float temp = angle_cos * mat[0][col] + angle_sin * mat[1][col];
|
|
|
|
mat[1][col] = -angle_sin * mat[0][col] + angle_cos * mat[1][col];
|
|
|
|
mat[0][col] = temp;
|
2012-03-25 12:41:58 +00:00
|
|
|
}
|
|
|
|
break;
|
2017-09-05 22:39:00 +10:00
|
|
|
default:
|
|
|
|
BLI_assert(0);
|
|
|
|
break;
|
2010-03-22 09:30:00 +00:00
|
|
|
}
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2019-09-04 12:06:59 +03:00
|
|
|
void rescale_m4(float mat[4][4], const float scale[3])
|
Armature: add Inherit Scale options to remove shear or average the scale.
As an inherent property of matrix-based transformation math, non-
uniform scaling of a parent bone induces shear into the transform
matrix of any rotated child. Such matrices cannot be cleanly
decomposed into a combination of location/rotation/scale, which
causes issues for rigging and animation tools.
Blender bones have options to exclude rotation and/or scale from the
inherited transformation, but don't have any support for removing the
often undesired shear component. That goal requires replacing simple
parenting with a combination of multiple bones and constraints. The
same is true about the goal of inheriting some scale, but completely
avoiding shear.
This patch replaces the old Inherit Scale checkbox with a enum that
supports multiple options:
* Full: inherit all effects of scale, like with enabled Inherit Scale.
* Fix Shear: removes shear from the final inherited transformation.
The cleanup math is specifically designed to preserve the main
axis of the bone, its length and total volume, and minimally
affect roll on average. It however will not prevent reappearance
of shear due to local rotation of the child or its children.
* Average: inherit uniform scale that represents the parent volume.
This is the simplest foolproof solution that will inherit some
scale without ever causing shear.
* None: completely remove scale and shear.
* None (Legacy): old disabled Inherit Scale checkbox.
This mode does not handle parent shear in any way, so the child
is likely to end up having both scale and shear. It is retained
for backward compatibility.
Since many rigging-related addons access the use_inherit_scale
property from Python, it is retained as a backward compatibility
stub that provides the old functionality.
As a side effect of reworking the code, this also fixes a matrix
multiplication order bug in the Inherit Rotation code, which caused
the parent local scale to be applied in world space. In rigger
opinion this option is useless in production rigs, so this fix
should not be a problem.
Reviewers: brecht
Differential Revision: https://developer.blender.org/D5588
2019-09-04 10:10:27 +03:00
|
|
|
{
|
|
|
|
mul_v3_fl(mat[0], scale[0]);
|
|
|
|
mul_v3_fl(mat[1], scale[1]);
|
|
|
|
mul_v3_fl(mat[2], scale[2]);
|
|
|
|
}
|
|
|
|
|
2013-07-30 10:58:36 +00:00
|
|
|
void transform_pivot_set_m4(float mat[4][4], const float pivot[3])
|
2013-07-26 06:12:49 +00:00
|
|
|
{
|
|
|
|
float tmat[4][4];
|
|
|
|
|
|
|
|
unit_m4(tmat);
|
|
|
|
|
|
|
|
copy_v3_v3(tmat[3], pivot);
|
|
|
|
mul_m4_m4m4(mat, tmat, mat);
|
|
|
|
|
|
|
|
/* invert the matrix */
|
|
|
|
negate_v3(tmat[3]);
|
|
|
|
mul_m4_m4m4(mat, mat, tmat);
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void blend_m3_m3m3(float out[3][3],
|
|
|
|
const float dst[3][3],
|
|
|
|
const float src[3][3],
|
|
|
|
const float srcweight)
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2010-11-22 10:39:28 +00:00
|
|
|
float srot[3][3], drot[3][3];
|
2009-11-09 22:42:41 +00:00
|
|
|
float squat[4], dquat[4], fquat[4];
|
2011-12-04 03:35:54 +00:00
|
|
|
float sscale[3], dscale[3], fsize[3];
|
2009-11-09 22:42:41 +00:00
|
|
|
float rmat[3][3], smat[3][3];
|
2012-03-25 12:41:58 +00:00
|
|
|
|
2011-12-04 03:35:54 +00:00
|
|
|
mat3_to_rot_size(drot, dscale, dst);
|
|
|
|
mat3_to_rot_size(srot, sscale, src);
|
2010-11-22 10:39:28 +00:00
|
|
|
|
2015-10-24 07:02:51 +11:00
|
|
|
mat3_normalized_to_quat(dquat, drot);
|
|
|
|
mat3_normalized_to_quat(squat, srot);
|
2009-11-09 22:42:41 +00:00
|
|
|
|
|
|
|
/* do blending */
|
|
|
|
interp_qt_qtqt(fquat, dquat, squat, srcweight);
|
2011-12-04 03:35:54 +00:00
|
|
|
interp_v3_v3v3(fsize, dscale, sscale, srcweight);
|
2009-11-09 22:42:41 +00:00
|
|
|
|
|
|
|
/* compose new matrix */
|
2012-03-25 12:41:58 +00:00
|
|
|
quat_to_mat3(rmat, fquat);
|
|
|
|
size_to_mat3(smat, fsize);
|
2009-11-09 22:42:41 +00:00
|
|
|
mul_m3_m3m3(out, rmat, smat);
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void blend_m4_m4m4(float out[4][4],
|
|
|
|
const float dst[4][4],
|
|
|
|
const float src[4][4],
|
|
|
|
const float srcweight)
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
2010-11-22 10:39:28 +00:00
|
|
|
float sloc[3], dloc[3], floc[3];
|
|
|
|
float srot[3][3], drot[3][3];
|
2009-11-09 22:42:41 +00:00
|
|
|
float squat[4], dquat[4], fquat[4];
|
2011-12-04 03:35:54 +00:00
|
|
|
float sscale[3], dscale[3], fsize[3];
|
2009-11-09 22:42:41 +00:00
|
|
|
|
2011-12-04 03:35:54 +00:00
|
|
|
mat4_to_loc_rot_size(dloc, drot, dscale, dst);
|
|
|
|
mat4_to_loc_rot_size(sloc, srot, sscale, src);
|
2010-11-22 10:39:28 +00:00
|
|
|
|
2015-10-24 07:02:51 +11:00
|
|
|
mat3_normalized_to_quat(dquat, drot);
|
|
|
|
mat3_normalized_to_quat(squat, srot);
|
2010-11-22 10:39:28 +00:00
|
|
|
|
2009-11-09 22:42:41 +00:00
|
|
|
/* do blending */
|
|
|
|
interp_v3_v3v3(floc, dloc, sloc, srcweight);
|
|
|
|
interp_qt_qtqt(fquat, dquat, squat, srcweight);
|
2011-12-04 03:35:54 +00:00
|
|
|
interp_v3_v3v3(fsize, dscale, sscale, srcweight);
|
2009-11-09 22:42:41 +00:00
|
|
|
|
|
|
|
/* compose new matrix */
|
|
|
|
loc_quat_size_to_mat4(out, floc, fquat, fsize);
|
|
|
|
}
|
|
|
|
|
2015-12-07 11:07:26 +11:00
|
|
|
/* for builds without Eigen */
|
|
|
|
#ifndef MATH_STANDALONE
|
2016-09-24 16:21:38 +02:00
|
|
|
void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t)
|
2015-10-09 20:57:37 +02:00
|
|
|
{
|
2019-01-15 23:15:58 +11:00
|
|
|
/* 'Rotation' component ('U' part of polar decomposition,
|
|
|
|
* the closest orthogonal matrix to M3 rot/scale
|
2015-10-09 20:57:37 +02:00
|
|
|
* transformation matrix), spherically interpolated. */
|
|
|
|
float U_A[3][3], U_B[3][3], U[3][3];
|
|
|
|
float quat_A[4], quat_B[4], quat[4];
|
2019-01-15 23:15:58 +11:00
|
|
|
/* 'Scaling' component ('P' part of polar decomposition, i.e. scaling in U-defined space),
|
|
|
|
* linearly interpolated. */
|
2015-10-09 20:57:37 +02:00
|
|
|
float P_A[3][3], P_B[3][3], P[3][3];
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
mat3_polar_decompose(A, U_A, P_A);
|
|
|
|
mat3_polar_decompose(B, U_B, P_B);
|
|
|
|
|
2020-06-25 23:13:02 +10:00
|
|
|
/* Quaternions cannot represent an axis flip. If such a singularity is detected, choose a
|
Allow interpolation of matrices with negative scale / axis flips
The matrix interpolation function `interp_m3_m3m3()` decomposes the
matrices into rotation and scale matrices, converts the rotation
matrices to quaternions, SLERPs the quaternions, and converts the result
back to a matrix. Since quaternions cannot represent axis flips, this
results in interpolation problems like described in T77154.
Our interpolation function is based on "Matrix Animation and Polar
Decomposition", by Ken Shoemake & Tom Duff. The paper states that it
produces invalid results when there is an axis flip in the rotation
matrix (or negative determinant, or negative scale, those all indicate
the same thing). Their solution is to multiply the rotation matrix with
`-I`, where `I` is the identity matrix. This is the same as element-wise
multiplication with `-1.0f`. My proposed solution is to not only do that
with the rotation matrix `R`, but also with the scale matrix `S`. This
ensures that the decomposition of `A = R * S` remains valid, while also
making it possible to conver the rotation component to a quaternion.
There is still an issue when interpolating between matrices with
different determinant. As the determinant represents the change in
volume when that matrix is applied to an object, interpolating between a
negative and a positive matrix will have to go through a zero
determinant. In this case the volume collapses to zero. I don't see this
as a big issue, though, as without this patch Blender would also produce
invalid results anyway.
Reviewed By: brecht, sergey
Differential Revision: https://developer.blender.org/D8048
2020-06-18 10:37:52 +02:00
|
|
|
* different decomposition of the matrix that still satisfies A = U_A * P_A but which has a
|
|
|
|
* positive determinant and thus no axis flips. This resolves T77154.
|
|
|
|
*
|
|
|
|
* Note that a flip of two axes is just a rotation of 180 degrees around the third axis, and
|
|
|
|
* three flipped axes are just an 180 degree rotation + a single axis flip. It is thus sufficient
|
|
|
|
* to solve this problem for single axis flips. */
|
|
|
|
if (determinant_m3_array(U_A) < 0) {
|
|
|
|
mul_m3_fl(U_A, -1.0f);
|
|
|
|
mul_m3_fl(P_A, -1.0f);
|
|
|
|
}
|
|
|
|
if (determinant_m3_array(U_B) < 0) {
|
|
|
|
mul_m3_fl(U_B, -1.0f);
|
|
|
|
mul_m3_fl(P_B, -1.0f);
|
|
|
|
}
|
|
|
|
|
2015-10-09 20:57:37 +02:00
|
|
|
mat3_to_quat(quat_A, U_A);
|
|
|
|
mat3_to_quat(quat_B, U_B);
|
|
|
|
interp_qt_qtqt(quat, quat_A, quat_B, t);
|
|
|
|
quat_to_mat3(U, quat);
|
|
|
|
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
interp_v3_v3v3(P[i], P_A[i], P_B[i], t);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* And we reconstruct rot/scale matrix from interpolated polar components */
|
|
|
|
mul_m3_m3m3(R, U, P);
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t)
|
2015-10-09 20:57:37 +02:00
|
|
|
{
|
|
|
|
float A3[3][3], B3[3][3], R3[3][3];
|
|
|
|
|
|
|
|
/* Location component, linearly interpolated. */
|
|
|
|
float loc_A[3], loc_B[3], loc[3];
|
|
|
|
|
|
|
|
copy_v3_v3(loc_A, A[3]);
|
|
|
|
copy_v3_v3(loc_B, B[3]);
|
|
|
|
interp_v3_v3v3(loc, loc_A, loc_B, t);
|
|
|
|
|
|
|
|
copy_m3_m4(A3, A);
|
|
|
|
copy_m3_m4(B3, B);
|
|
|
|
|
|
|
|
interp_m3_m3m3(R3, A3, B3, t);
|
|
|
|
|
|
|
|
copy_m4_m3(R, R3);
|
|
|
|
copy_v3_v3(R[3], loc);
|
|
|
|
}
|
2015-12-07 11:07:26 +11:00
|
|
|
#endif /* MATH_STANDALONE */
|
2015-10-09 20:57:37 +02:00
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
bool is_negative_m3(const float mat[3][3])
|
2010-01-30 13:15:39 +00:00
|
|
|
{
|
|
|
|
float vec[3];
|
|
|
|
cross_v3_v3v3(vec, mat[0], mat[1]);
|
|
|
|
return (dot_v3v3(vec, mat[2]) < 0.0f);
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
bool is_negative_m4(const float mat[4][4])
|
2010-01-30 13:15:39 +00:00
|
|
|
{
|
|
|
|
float vec[3];
|
|
|
|
cross_v3_v3v3(vec, mat[0], mat[1]);
|
|
|
|
return (dot_v3v3(vec, mat[2]) < 0.0f);
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
bool is_zero_m3(const float mat[3][3])
|
2013-07-26 11:15:22 +00:00
|
|
|
{
|
|
|
|
return (is_zero_v3(mat[0]) && is_zero_v3(mat[1]) && is_zero_v3(mat[2]));
|
|
|
|
}
|
2016-09-24 16:21:38 +02:00
|
|
|
bool is_zero_m4(const float mat[4][4])
|
2013-07-26 11:15:22 +00:00
|
|
|
{
|
|
|
|
return (is_zero_v4(mat[0]) && is_zero_v4(mat[1]) && is_zero_v4(mat[2]) && is_zero_v4(mat[3]));
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
bool equals_m3m3(const float mat1[3][3], const float mat2[3][3])
|
2016-05-12 12:07:31 +02:00
|
|
|
{
|
|
|
|
return (equals_v3v3(mat1[0], mat2[0]) && equals_v3v3(mat1[1], mat2[1]) &&
|
|
|
|
equals_v3v3(mat1[2], mat2[2]));
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
|
2016-05-12 12:07:31 +02:00
|
|
|
{
|
|
|
|
return (equals_v4v4(mat1[0], mat2[0]) && equals_v4v4(mat1[1], mat2[1]) &&
|
|
|
|
equals_v4v4(mat1[2], mat2[2]) && equals_v4v4(mat1[3], mat2[3]));
|
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void loc_rot_size_to_mat4(float R[4][4],
|
2019-09-04 12:06:59 +03:00
|
|
|
const float loc[3],
|
|
|
|
const float rot[3][3],
|
|
|
|
const float size[3])
|
|
|
|
{
|
2020-09-04 20:59:13 +02:00
|
|
|
copy_m4_m3(R, rot);
|
|
|
|
rescale_m4(R, size);
|
|
|
|
copy_v3_v3(R[3], loc);
|
2019-09-04 12:06:59 +03:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void loc_eul_size_to_mat4(float R[4][4],
|
2010-10-22 03:56:50 +00:00
|
|
|
const float loc[3],
|
|
|
|
const float eul[3],
|
|
|
|
const float size[3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
float rmat[3][3], smat[3][3], tmat[3][3];
|
2012-03-25 12:41:58 +00:00
|
|
|
|
2012-03-02 16:05:54 +00:00
|
|
|
/* initialize new matrix */
|
2020-09-04 20:59:13 +02:00
|
|
|
unit_m4(R);
|
2012-03-25 12:41:58 +00:00
|
|
|
|
2009-11-09 22:42:41 +00:00
|
|
|
/* make rotation + scaling part */
|
2012-03-25 12:41:58 +00:00
|
|
|
eul_to_mat3(rmat, eul);
|
|
|
|
size_to_mat3(smat, size);
|
2009-11-09 22:42:41 +00:00
|
|
|
mul_m3_m3m3(tmat, rmat, smat);
|
2012-03-25 12:41:58 +00:00
|
|
|
|
2021-06-26 21:35:18 +10:00
|
|
|
/* Copy rot/scale part to output matrix. */
|
2020-09-04 20:59:13 +02:00
|
|
|
copy_m4_m3(R, tmat);
|
2012-03-25 12:41:58 +00:00
|
|
|
|
2009-11-09 22:42:41 +00:00
|
|
|
/* copy location to matrix */
|
2020-09-04 20:59:13 +02:00
|
|
|
R[3][0] = loc[0];
|
|
|
|
R[3][1] = loc[1];
|
|
|
|
R[3][2] = loc[2];
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void loc_eulO_size_to_mat4(float R[4][4],
|
2010-10-22 03:56:50 +00:00
|
|
|
const float loc[3],
|
|
|
|
const float eul[3],
|
|
|
|
const float size[3],
|
|
|
|
const short rotOrder)
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
float rmat[3][3], smat[3][3], tmat[3][3];
|
2012-03-25 12:41:58 +00:00
|
|
|
|
2021-06-26 21:35:18 +10:00
|
|
|
/* Initialize new matrix. */
|
2020-09-04 20:59:13 +02:00
|
|
|
unit_m4(R);
|
2012-03-25 12:41:58 +00:00
|
|
|
|
2021-06-26 21:35:18 +10:00
|
|
|
/* Make rotation + scaling part. */
|
2012-03-25 12:41:58 +00:00
|
|
|
eulO_to_mat3(rmat, eul, rotOrder);
|
|
|
|
size_to_mat3(smat, size);
|
2009-11-09 22:42:41 +00:00
|
|
|
mul_m3_m3m3(tmat, rmat, smat);
|
2012-03-25 12:41:58 +00:00
|
|
|
|
2021-06-26 21:35:18 +10:00
|
|
|
/* Copy rot/scale part to output matrix. */
|
2020-09-04 20:59:13 +02:00
|
|
|
copy_m4_m3(R, tmat);
|
2012-03-25 12:41:58 +00:00
|
|
|
|
2021-06-26 21:35:18 +10:00
|
|
|
/* Copy location to matrix. */
|
2020-09-04 20:59:13 +02:00
|
|
|
R[3][0] = loc[0];
|
|
|
|
R[3][1] = loc[1];
|
|
|
|
R[3][2] = loc[2];
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void loc_quat_size_to_mat4(float R[4][4],
|
2010-10-22 03:56:50 +00:00
|
|
|
const float loc[3],
|
|
|
|
const float quat[4],
|
|
|
|
const float size[3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
float rmat[3][3], smat[3][3], tmat[3][3];
|
2012-03-25 12:41:58 +00:00
|
|
|
|
2012-03-02 16:05:54 +00:00
|
|
|
/* initialize new matrix */
|
2020-09-04 20:59:13 +02:00
|
|
|
unit_m4(R);
|
2012-03-25 12:41:58 +00:00
|
|
|
|
2009-11-09 22:42:41 +00:00
|
|
|
/* make rotation + scaling part */
|
2012-03-25 12:41:58 +00:00
|
|
|
quat_to_mat3(rmat, quat);
|
|
|
|
size_to_mat3(smat, size);
|
2009-11-09 22:42:41 +00:00
|
|
|
mul_m3_m3m3(tmat, rmat, smat);
|
2012-03-25 12:41:58 +00:00
|
|
|
|
2021-06-26 21:35:18 +10:00
|
|
|
/* Copy rot/scale part to output matrix. */
|
2020-09-04 20:59:13 +02:00
|
|
|
copy_m4_m3(R, tmat);
|
2012-03-25 12:41:58 +00:00
|
|
|
|
2009-11-09 22:42:41 +00:00
|
|
|
/* copy location to matrix */
|
2020-09-04 20:59:13 +02:00
|
|
|
R[3][0] = loc[0];
|
|
|
|
R[3][1] = loc[1];
|
|
|
|
R[3][2] = loc[2];
|
2009-11-09 22:42:41 +00:00
|
|
|
}
|
|
|
|
|
2020-09-04 20:59:13 +02:00
|
|
|
void loc_axisangle_size_to_mat4(
|
|
|
|
float R[4][4], const float loc[3], const float axis[3], const float angle, const float size[3])
|
2010-10-22 03:56:50 +00:00
|
|
|
{
|
|
|
|
float q[4];
|
|
|
|
axis_angle_to_quat(q, axis, angle);
|
2020-09-04 20:59:13 +02:00
|
|
|
loc_quat_size_to_mat4(R, loc, q, size);
|
2010-10-22 03:56:50 +00:00
|
|
|
}
|
|
|
|
|
2009-11-09 22:42:41 +00:00
|
|
|
/*********************************** Other ***********************************/
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void print_m3(const char *str, const float m[3][3])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
printf("%s\n", str);
|
2012-03-25 12:41:58 +00:00
|
|
|
printf("%f %f %f\n", m[0][0], m[1][0], m[2][0]);
|
|
|
|
printf("%f %f %f\n", m[0][1], m[1][1], m[2][1]);
|
|
|
|
printf("%f %f %f\n", m[0][2], m[1][2], m[2][2]);
|
2009-11-09 22:42:41 +00:00
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void print_m4(const char *str, const float m[4][4])
|
2009-11-09 22:42:41 +00:00
|
|
|
{
|
|
|
|
printf("%s\n", str);
|
2012-03-25 12:41:58 +00:00
|
|
|
printf("%f %f %f %f\n", m[0][0], m[1][0], m[2][0], m[3][0]);
|
|
|
|
printf("%f %f %f %f\n", m[0][1], m[1][1], m[2][1], m[3][1]);
|
|
|
|
printf("%f %f %f %f\n", m[0][2], m[1][2], m[2][2], m[3][2]);
|
|
|
|
printf("%f %f %f %f\n", m[0][3], m[1][3], m[2][3], m[3][3]);
|
2009-11-09 22:42:41 +00:00
|
|
|
printf("\n");
|
|
|
|
}
|
2010-06-22 15:20:06 +00:00
|
|
|
|
|
|
|
void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4])
|
|
|
|
{
|
2021-12-09 20:01:44 +11:00
|
|
|
/* NOTE: originally from TNT (template numeric toolkit) matrix library.
|
|
|
|
* https://math.nist.gov/tnt */
|
|
|
|
|
2010-06-22 15:20:06 +00:00
|
|
|
float A[4][4];
|
|
|
|
float work1[4], work2[4];
|
|
|
|
int m = 4;
|
|
|
|
int n = 4;
|
|
|
|
int maxiter = 200;
|
2013-12-06 03:46:27 +11:00
|
|
|
int nu = min_ii(m, n);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-06-22 15:20:06 +00:00
|
|
|
float *work = work1;
|
|
|
|
float *e = work2;
|
|
|
|
float eps;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
int i = 0, j = 0, k = 0, p, pp, iter;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Reduce A to bidiagonal form, storing the diagonal elements
|
|
|
|
* in s and the super-diagonal elements in e. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-12-06 03:46:27 +11:00
|
|
|
int nct = min_ii(m - 1, n);
|
|
|
|
int nrt = max_ii(0, min_ii(n - 2, m));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-06-22 15:20:06 +00:00
|
|
|
copy_m4_m4(A, A_);
|
|
|
|
zero_m4(U);
|
|
|
|
zero_v4(s);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-12-06 03:46:27 +11:00
|
|
|
for (k = 0; k < max_ii(nct, nrt); k++) {
|
2010-06-22 15:20:06 +00:00
|
|
|
if (k < nct) {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Compute the transformation for the k-th column and
|
|
|
|
* place the k-th diagonal in s[k].
|
|
|
|
* Compute 2-norm of k-th column without under/overflow. */
|
2010-06-22 15:20:06 +00:00
|
|
|
s[k] = 0;
|
|
|
|
for (i = k; i < m; i++) {
|
2012-03-25 12:41:58 +00:00
|
|
|
s[k] = hypotf(s[k], A[i][k]);
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
|
|
|
if (s[k] != 0.0f) {
|
|
|
|
float invsk;
|
|
|
|
if (A[k][k] < 0.0f) {
|
|
|
|
s[k] = -s[k];
|
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
invsk = 1.0f / s[k];
|
2010-06-22 15:20:06 +00:00
|
|
|
for (i = k; i < m; i++) {
|
|
|
|
A[i][k] *= invsk;
|
|
|
|
}
|
|
|
|
A[k][k] += 1.0f;
|
|
|
|
}
|
|
|
|
s[k] = -s[k];
|
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
for (j = k + 1; j < n; j++) {
|
2012-02-27 10:35:39 +00:00
|
|
|
if ((k < nct) && (s[k] != 0.0f)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Apply the transformation. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-06-22 15:20:06 +00:00
|
|
|
float t = 0;
|
|
|
|
for (i = k; i < m; i++) {
|
2012-03-25 12:41:58 +00:00
|
|
|
t += A[i][k] * A[i][j];
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
t = -t / A[k][k];
|
2010-06-22 15:20:06 +00:00
|
|
|
for (i = k; i < m; i++) {
|
2012-03-25 12:41:58 +00:00
|
|
|
A[i][j] += t * A[i][k];
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Place the k-th row of A into e for the */
|
|
|
|
/* subsequent calculation of the row transformation. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-06-22 15:20:06 +00:00
|
|
|
e[j] = A[k][j];
|
|
|
|
}
|
|
|
|
if (k < nct) {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Place the transformation in U for subsequent back
|
|
|
|
* multiplication. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-27 13:16:10 +11:00
|
|
|
for (i = k; i < m; i++) {
|
2010-06-22 15:20:06 +00:00
|
|
|
U[i][k] = A[i][k];
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2010-06-22 15:20:06 +00:00
|
|
|
if (k < nrt) {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Compute the k-th row transformation and place the
|
|
|
|
* k-th super-diagonal in e[k].
|
|
|
|
* Compute 2-norm without under/overflow. */
|
2010-06-22 15:20:06 +00:00
|
|
|
e[k] = 0;
|
2012-03-25 12:41:58 +00:00
|
|
|
for (i = k + 1; i < n; i++) {
|
|
|
|
e[k] = hypotf(e[k], e[i]);
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
|
|
|
if (e[k] != 0.0f) {
|
|
|
|
float invek;
|
2012-03-25 12:41:58 +00:00
|
|
|
if (e[k + 1] < 0.0f) {
|
2010-06-22 15:20:06 +00:00
|
|
|
e[k] = -e[k];
|
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
invek = 1.0f / e[k];
|
|
|
|
for (i = k + 1; i < n; i++) {
|
2010-06-22 15:20:06 +00:00
|
|
|
e[i] *= invek;
|
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
e[k + 1] += 1.0f;
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
|
|
|
e[k] = -e[k];
|
2012-03-25 12:41:58 +00:00
|
|
|
if ((k + 1 < m) & (e[k] != 0.0f)) {
|
2010-06-22 15:20:06 +00:00
|
|
|
float invek1;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Apply the transformation. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
for (i = k + 1; i < m; i++) {
|
2010-06-22 15:20:06 +00:00
|
|
|
work[i] = 0.0f;
|
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
for (j = k + 1; j < n; j++) {
|
|
|
|
for (i = k + 1; i < m; i++) {
|
|
|
|
work[i] += e[j] * A[i][j];
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
invek1 = 1.0f / e[k + 1];
|
|
|
|
for (j = k + 1; j < n; j++) {
|
|
|
|
float t = -e[j] * invek1;
|
|
|
|
for (i = k + 1; i < m; i++) {
|
|
|
|
A[i][j] += t * work[i];
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Place the transformation in V for subsequent
|
|
|
|
* back multiplication. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-27 13:16:10 +11:00
|
|
|
for (i = k + 1; i < n; i++) {
|
2010-06-22 15:20:06 +00:00
|
|
|
V[i][k] = e[i];
|
|
|
|
}
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Set up the final bidiagonal matrix or order p. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-12-06 03:46:27 +11:00
|
|
|
p = min_ii(n, m + 1);
|
2010-06-22 15:20:06 +00:00
|
|
|
if (nct < n) {
|
|
|
|
s[nct] = A[nct][nct];
|
|
|
|
}
|
|
|
|
if (m < p) {
|
2012-03-25 12:41:58 +00:00
|
|
|
s[p - 1] = 0.0f;
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
if (nrt + 1 < p) {
|
|
|
|
e[nrt] = A[nrt][p - 1];
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
e[p - 1] = 0.0f;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* If required, generate U. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-06-22 15:20:06 +00:00
|
|
|
for (j = nct; j < nu; j++) {
|
|
|
|
for (i = 0; i < m; i++) {
|
|
|
|
U[i][j] = 0.0f;
|
|
|
|
}
|
|
|
|
U[j][j] = 1.0f;
|
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
for (k = nct - 1; k >= 0; k--) {
|
2010-06-22 15:20:06 +00:00
|
|
|
if (s[k] != 0.0f) {
|
2012-03-25 12:41:58 +00:00
|
|
|
for (j = k + 1; j < nu; j++) {
|
2010-06-22 15:20:06 +00:00
|
|
|
float t = 0;
|
|
|
|
for (i = k; i < m; i++) {
|
2012-03-25 12:41:58 +00:00
|
|
|
t += U[i][k] * U[i][j];
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
t = -t / U[k][k];
|
2010-06-22 15:20:06 +00:00
|
|
|
for (i = k; i < m; i++) {
|
2012-03-25 12:41:58 +00:00
|
|
|
U[i][j] += t * U[i][k];
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
for (i = k; i < m; i++) {
|
2010-06-22 15:20:06 +00:00
|
|
|
U[i][k] = -U[i][k];
|
|
|
|
}
|
|
|
|
U[k][k] = 1.0f + U[k][k];
|
2012-03-25 12:41:58 +00:00
|
|
|
for (i = 0; i < k - 1; i++) {
|
2010-06-22 15:20:06 +00:00
|
|
|
U[i][k] = 0.0f;
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-03-24 06:18:31 +00:00
|
|
|
else {
|
2010-06-22 15:20:06 +00:00
|
|
|
for (i = 0; i < m; i++) {
|
|
|
|
U[i][k] = 0.0f;
|
|
|
|
}
|
|
|
|
U[k][k] = 1.0f;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* If required, generate V. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
for (k = n - 1; k >= 0; k--) {
|
2010-06-22 15:20:06 +00:00
|
|
|
if ((k < nrt) & (e[k] != 0.0f)) {
|
2012-03-25 12:41:58 +00:00
|
|
|
for (j = k + 1; j < nu; j++) {
|
2010-06-22 15:20:06 +00:00
|
|
|
float t = 0;
|
2012-03-25 12:41:58 +00:00
|
|
|
for (i = k + 1; i < n; i++) {
|
|
|
|
t += V[i][k] * V[i][j];
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
t = -t / V[k + 1][k];
|
|
|
|
for (i = k + 1; i < n; i++) {
|
|
|
|
V[i][j] += t * V[i][k];
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
2010-06-22 15:20:06 +00:00
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
V[i][k] = 0.0f;
|
|
|
|
}
|
|
|
|
V[k][k] = 1.0f;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Main iteration loop for the singular values. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
pp = p - 1;
|
2010-06-22 15:20:06 +00:00
|
|
|
iter = 0;
|
2012-03-25 12:41:58 +00:00
|
|
|
eps = powf(2.0f, -52.0f);
|
2010-06-22 15:20:06 +00:00
|
|
|
while (p > 0) {
|
2012-03-25 12:41:58 +00:00
|
|
|
int kase = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Test for maximum iterations to avoid infinite loop */
|
2019-03-27 13:16:10 +11:00
|
|
|
if (maxiter == 0) {
|
2010-06-22 15:20:06 +00:00
|
|
|
break;
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
2010-06-22 15:20:06 +00:00
|
|
|
maxiter--;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* This section of the program inspects for
|
|
|
|
* negligible elements in the s and e arrays. On
|
|
|
|
* completion the variables kase and k are set as follows.
|
|
|
|
*
|
2018-11-14 12:53:15 +11:00
|
|
|
* kase = 1: if s(p) and e[k - 1] are negligible and k<p
|
|
|
|
* kase = 2: if s(k) is negligible and k<p
|
|
|
|
* kase = 3: if e[k - 1] is negligible, k<p, and
|
|
|
|
* s(k), ..., s(p) are not negligible (qr step).
|
|
|
|
* kase = 4: if e(p - 1) is negligible (convergence). */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
for (k = p - 2; k >= -1; k--) {
|
2010-06-22 15:20:06 +00:00
|
|
|
if (k == -1) {
|
|
|
|
break;
|
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
if (fabsf(e[k]) <= eps * (fabsf(s[k]) + fabsf(s[k + 1]))) {
|
2010-06-22 15:20:06 +00:00
|
|
|
e[k] = 0.0f;
|
|
|
|
break;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
if (k == p - 2) {
|
2010-06-22 15:20:06 +00:00
|
|
|
kase = 4;
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2010-06-22 15:20:06 +00:00
|
|
|
int ks;
|
2012-03-25 12:41:58 +00:00
|
|
|
for (ks = p - 1; ks >= k; ks--) {
|
2010-06-22 15:20:06 +00:00
|
|
|
float t;
|
|
|
|
if (ks == k) {
|
|
|
|
break;
|
|
|
|
}
|
2020-11-06 11:25:27 +11:00
|
|
|
t = (ks != p ? fabsf(e[ks]) : 0.0f) + (ks != k + 1 ? fabsf(e[ks - 1]) : 0.0f);
|
2012-03-25 12:41:58 +00:00
|
|
|
if (fabsf(s[ks]) <= eps * t) {
|
2010-06-22 15:20:06 +00:00
|
|
|
s[ks] = 0.0f;
|
|
|
|
break;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2010-06-22 15:20:06 +00:00
|
|
|
if (ks == k) {
|
|
|
|
kase = 3;
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
else if (ks == p - 1) {
|
2010-06-22 15:20:06 +00:00
|
|
|
kase = 1;
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2010-06-22 15:20:06 +00:00
|
|
|
kase = 2;
|
|
|
|
k = ks;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2010-06-22 15:20:06 +00:00
|
|
|
k++;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Perform the task indicated by kase. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-06-22 15:20:06 +00:00
|
|
|
switch (kase) {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Deflate negligible s(p). */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
case 1: {
|
|
|
|
float f = e[p - 2];
|
|
|
|
e[p - 2] = 0.0f;
|
|
|
|
for (j = p - 2; j >= k; j--) {
|
|
|
|
float t = hypotf(s[j], f);
|
|
|
|
float invt = 1.0f / t;
|
|
|
|
float cs = s[j] * invt;
|
|
|
|
float sn = f * invt;
|
2010-06-22 15:20:06 +00:00
|
|
|
s[j] = t;
|
|
|
|
if (j != k) {
|
2012-03-25 12:41:58 +00:00
|
|
|
f = -sn * e[j - 1];
|
|
|
|
e[j - 1] = cs * e[j - 1];
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-06-22 15:20:06 +00:00
|
|
|
for (i = 0; i < n; i++) {
|
2012-03-25 12:41:58 +00:00
|
|
|
t = cs * V[i][j] + sn * V[i][p - 1];
|
|
|
|
V[i][p - 1] = -sn * V[i][j] + cs * V[i][p - 1];
|
2010-06-22 15:20:06 +00:00
|
|
|
V[i][j] = t;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
break;
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Split at negligible s(k). */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
case 2: {
|
|
|
|
float f = e[k - 1];
|
|
|
|
e[k - 1] = 0.0f;
|
2010-06-22 15:20:06 +00:00
|
|
|
for (j = k; j < p; j++) {
|
2012-03-25 12:41:58 +00:00
|
|
|
float t = hypotf(s[j], f);
|
|
|
|
float invt = 1.0f / t;
|
|
|
|
float cs = s[j] * invt;
|
|
|
|
float sn = f * invt;
|
2010-06-22 15:20:06 +00:00
|
|
|
s[j] = t;
|
2012-03-25 12:41:58 +00:00
|
|
|
f = -sn * e[j];
|
|
|
|
e[j] = cs * e[j];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-06-22 15:20:06 +00:00
|
|
|
for (i = 0; i < m; i++) {
|
2012-03-25 12:41:58 +00:00
|
|
|
t = cs * U[i][j] + sn * U[i][k - 1];
|
|
|
|
U[i][k - 1] = -sn * U[i][j] + cs * U[i][k - 1];
|
2010-06-22 15:20:06 +00:00
|
|
|
U[i][j] = t;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
break;
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Perform one qr step. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
case 3: {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Calculate the shift. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-23 13:28:22 +00:00
|
|
|
float scale = max_ff(
|
2012-04-29 15:47:02 +00:00
|
|
|
max_ff(max_ff(max_ff(fabsf(s[p - 1]), fabsf(s[p - 2])), fabsf(e[p - 2])), fabsf(s[k])),
|
|
|
|
fabsf(e[k]));
|
2012-03-25 12:41:58 +00:00
|
|
|
float invscale = 1.0f / scale;
|
|
|
|
float sp = s[p - 1] * invscale;
|
|
|
|
float spm1 = s[p - 2] * invscale;
|
|
|
|
float epm1 = e[p - 2] * invscale;
|
|
|
|
float sk = s[k] * invscale;
|
|
|
|
float ek = e[k] * invscale;
|
|
|
|
float b = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) * 0.5f;
|
|
|
|
float c = (sp * epm1) * (sp * epm1);
|
2010-06-22 15:20:06 +00:00
|
|
|
float shift = 0.0f;
|
|
|
|
float f, g;
|
|
|
|
if ((b != 0.0f) || (c != 0.0f)) {
|
2012-03-25 12:41:58 +00:00
|
|
|
shift = sqrtf(b * b + c);
|
2010-06-22 15:20:06 +00:00
|
|
|
if (b < 0.0f) {
|
|
|
|
shift = -shift;
|
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
shift = c / (b + shift);
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
f = (sk + sp) * (sk - sp) + shift;
|
|
|
|
g = sk * ek;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Chase zeros. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
for (j = k; j < p - 1; j++) {
|
|
|
|
float t = hypotf(f, g);
|
2010-06-22 15:20:06 +00:00
|
|
|
/* division by zero checks added to avoid NaN (brecht) */
|
2012-03-25 12:41:58 +00:00
|
|
|
float cs = (t == 0.0f) ? 0.0f : f / t;
|
|
|
|
float sn = (t == 0.0f) ? 0.0f : g / t;
|
2010-06-22 15:20:06 +00:00
|
|
|
if (j != k) {
|
2012-03-25 12:41:58 +00:00
|
|
|
e[j - 1] = t;
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
f = cs * s[j] + sn * e[j];
|
|
|
|
e[j] = cs * e[j] - sn * s[j];
|
|
|
|
g = sn * s[j + 1];
|
|
|
|
s[j + 1] = cs * s[j + 1];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-06-22 15:20:06 +00:00
|
|
|
for (i = 0; i < n; i++) {
|
2012-03-25 12:41:58 +00:00
|
|
|
t = cs * V[i][j] + sn * V[i][j + 1];
|
|
|
|
V[i][j + 1] = -sn * V[i][j] + cs * V[i][j + 1];
|
2010-06-22 15:20:06 +00:00
|
|
|
V[i][j] = t;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
t = hypotf(f, g);
|
2010-06-22 15:20:06 +00:00
|
|
|
/* division by zero checks added to avoid NaN (brecht) */
|
2012-03-25 12:41:58 +00:00
|
|
|
cs = (t == 0.0f) ? 0.0f : f / t;
|
|
|
|
sn = (t == 0.0f) ? 0.0f : g / t;
|
2010-06-22 15:20:06 +00:00
|
|
|
s[j] = t;
|
2012-03-25 12:41:58 +00:00
|
|
|
f = cs * e[j] + sn * s[j + 1];
|
|
|
|
s[j + 1] = -sn * e[j] + cs * s[j + 1];
|
|
|
|
g = sn * e[j + 1];
|
|
|
|
e[j + 1] = cs * e[j + 1];
|
|
|
|
if (j < m - 1) {
|
2010-06-22 15:20:06 +00:00
|
|
|
for (i = 0; i < m; i++) {
|
2012-03-25 12:41:58 +00:00
|
|
|
t = cs * U[i][j] + sn * U[i][j + 1];
|
|
|
|
U[i][j + 1] = -sn * U[i][j] + cs * U[i][j + 1];
|
2010-06-22 15:20:06 +00:00
|
|
|
U[i][j] = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
e[p - 2] = f;
|
2010-06-22 15:20:06 +00:00
|
|
|
iter = iter + 1;
|
2012-03-25 12:41:58 +00:00
|
|
|
break;
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Convergence. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-25 12:41:58 +00:00
|
|
|
case 4: {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Make the singular values positive. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-06-22 15:20:06 +00:00
|
|
|
if (s[k] <= 0.0f) {
|
|
|
|
s[k] = (s[k] < 0.0f ? -s[k] : 0.0f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-27 13:16:10 +11:00
|
|
|
for (i = 0; i <= pp; i++) {
|
2010-06-22 15:20:06 +00:00
|
|
|
V[i][k] = -V[i][k];
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Order the singular values. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-06-22 15:20:06 +00:00
|
|
|
while (k < pp) {
|
|
|
|
float t;
|
2012-03-25 12:41:58 +00:00
|
|
|
if (s[k] >= s[k + 1]) {
|
2010-06-22 15:20:06 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
t = s[k];
|
2012-03-25 12:41:58 +00:00
|
|
|
s[k] = s[k + 1];
|
|
|
|
s[k + 1] = t;
|
|
|
|
if (k < n - 1) {
|
2010-06-22 15:20:06 +00:00
|
|
|
for (i = 0; i < n; i++) {
|
2012-03-25 12:41:58 +00:00
|
|
|
t = V[i][k + 1];
|
|
|
|
V[i][k + 1] = V[i][k];
|
|
|
|
V[i][k] = t;
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
|
|
|
}
|
2012-03-25 12:41:58 +00:00
|
|
|
if (k < m - 1) {
|
2010-06-22 15:20:06 +00:00
|
|
|
for (i = 0; i < m; i++) {
|
2012-03-25 12:41:58 +00:00
|
|
|
t = U[i][k + 1];
|
|
|
|
U[i][k + 1] = U[i][k];
|
|
|
|
U[i][k] = t;
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
k++;
|
|
|
|
}
|
|
|
|
iter = 0;
|
|
|
|
p--;
|
2012-03-25 12:41:58 +00:00
|
|
|
break;
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void pseudoinverse_m4_m4(float Ainv[4][4], const float A_[4][4], float epsilon)
|
2010-06-22 15:20:06 +00:00
|
|
|
{
|
2015-05-04 14:30:46 +02:00
|
|
|
/* compute Moore-Penrose pseudo inverse of matrix, singular values
|
2012-03-03 20:19:11 +00:00
|
|
|
* below epsilon are ignored for stability (truncated SVD) */
|
2014-10-30 14:49:57 +01:00
|
|
|
float A[4][4], V[4][4], W[4], Wm[4][4], U[4][4];
|
2010-06-22 15:20:06 +00:00
|
|
|
int i;
|
|
|
|
|
2014-10-30 14:49:57 +01:00
|
|
|
transpose_m4_m4(A, A_);
|
2010-06-22 15:20:06 +00:00
|
|
|
svd_m4(V, W, U, A);
|
|
|
|
transpose_m4(U);
|
|
|
|
transpose_m4(V);
|
|
|
|
|
|
|
|
zero_m4(Wm);
|
2019-03-27 13:16:10 +11:00
|
|
|
for (i = 0; i < 4; i++) {
|
2012-03-25 12:41:58 +00:00
|
|
|
Wm[i][i] = (W[i] < epsilon) ? 0.0f : 1.0f / W[i];
|
2019-03-27 13:16:10 +11:00
|
|
|
}
|
2010-06-22 15:20:06 +00:00
|
|
|
|
|
|
|
transpose_m4(V);
|
|
|
|
|
2014-07-21 18:55:12 +10:00
|
|
|
mul_m4_series(Ainv, U, Wm, V);
|
2010-06-22 15:20:06 +00:00
|
|
|
}
|
2012-12-14 21:41:22 +00:00
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void pseudoinverse_m3_m3(float Ainv[3][3], const float A[3][3], float epsilon)
|
2012-12-14 21:41:22 +00:00
|
|
|
{
|
|
|
|
/* try regular inverse when possible, otherwise fall back to slow svd */
|
2012-12-15 02:48:25 +00:00
|
|
|
if (!invert_m3_m3(Ainv, A)) {
|
2012-12-14 21:41:22 +00:00
|
|
|
float tmp[4][4], tmpinv[4][4];
|
|
|
|
|
|
|
|
copy_m4_m3(tmp, A);
|
|
|
|
pseudoinverse_m4_m4(tmpinv, tmp, epsilon);
|
|
|
|
copy_m3_m4(Ainv, tmpinv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
bool has_zero_axis_m4(const float matrix[4][4])
|
2013-10-18 23:38:51 +00:00
|
|
|
{
|
|
|
|
return len_squared_v3(matrix[0]) < FLT_EPSILON || len_squared_v3(matrix[1]) < FLT_EPSILON ||
|
|
|
|
len_squared_v3(matrix[2]) < FLT_EPSILON;
|
|
|
|
}
|
2014-03-25 16:05:28 +06:00
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4])
|
2014-03-25 16:05:28 +06:00
|
|
|
{
|
|
|
|
if (!invert_m4_m4(Ainv, A)) {
|
|
|
|
float Atemp[4][4];
|
|
|
|
|
|
|
|
copy_m4_m4(Atemp, A);
|
|
|
|
|
|
|
|
/* Matrix is degenerate (e.g. 0 scale on some axis), ideally we should
|
|
|
|
* never be in this situation, but try to invert it anyway with tweak.
|
|
|
|
*/
|
|
|
|
Atemp[0][0] += 1e-8f;
|
|
|
|
Atemp[1][1] += 1e-8f;
|
|
|
|
Atemp[2][2] += 1e-8f;
|
|
|
|
|
|
|
|
if (!invert_m4_m4(Ainv, Atemp)) {
|
2014-03-25 16:22:47 +06:00
|
|
|
unit_m4(Ainv);
|
2014-03-25 16:05:28 +06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-08-01 16:28:31 +02:00
|
|
|
|
2020-08-25 12:35:44 +10:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Invert (Safe Orthographic)
|
|
|
|
*
|
|
|
|
* Invert the matrix, filling in zeroed axes using the valid ones where possible.
|
|
|
|
*
|
|
|
|
* Unlike #invert_m4_m4_safe set degenerate axis unit length instead of adding a small value,
|
|
|
|
* which has the results in:
|
|
|
|
*
|
|
|
|
* - Scaling by a large value on the resulting matrix.
|
|
|
|
* - Changing axis which aren't degenerate.
|
|
|
|
*
|
|
|
|
* \note We could support passing in a length value if there is a good use-case
|
|
|
|
* where we want to specify the length of the degenerate axes.
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4])
|
|
|
|
{
|
|
|
|
if (UNLIKELY(!invert_m4_m4(Ainv, A))) {
|
|
|
|
float Atemp[4][4];
|
|
|
|
copy_m4_m4(Atemp, A);
|
2021-04-01 21:16:09 +11:00
|
|
|
if (UNLIKELY(!(orthogonalize_m4_zero_axes(Atemp, 1.0f) && invert_m4_m4(Ainv, Atemp)))) {
|
2020-08-25 12:35:44 +10:00
|
|
|
unit_m4(Ainv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void invert_m3_m3_safe_ortho(float Ainv[3][3], const float A[3][3])
|
|
|
|
{
|
|
|
|
if (UNLIKELY(!invert_m3_m3(Ainv, A))) {
|
|
|
|
float Atemp[3][3];
|
|
|
|
copy_m3_m3(Atemp, A);
|
2021-04-01 21:16:09 +11:00
|
|
|
if (UNLIKELY(!(orthogonalize_m3_zero_axes(Atemp, 1.0f) && invert_m3_m3(Ainv, Atemp)))) {
|
2020-08-25 12:35:44 +10:00
|
|
|
unit_m3(Ainv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void BLI_space_transform_from_matrices(SpaceTransform *data,
|
|
|
|
const float local[4][4],
|
|
|
|
const float target[4][4])
|
2014-08-01 16:28:31 +02:00
|
|
|
{
|
|
|
|
float itarget[4][4];
|
|
|
|
invert_m4_m4(itarget, target);
|
|
|
|
mul_m4_m4m4(data->local2target, itarget, local);
|
|
|
|
invert_m4_m4(data->target2local, data->local2target);
|
|
|
|
}
|
|
|
|
|
2016-09-24 16:21:38 +02:00
|
|
|
void BLI_space_transform_global_from_matrices(SpaceTransform *data,
|
|
|
|
const float local[4][4],
|
|
|
|
const float target[4][4])
|
2015-07-11 00:04:27 +02:00
|
|
|
{
|
|
|
|
float ilocal[4][4];
|
|
|
|
invert_m4_m4(ilocal, local);
|
|
|
|
mul_m4_m4m4(data->local2target, target, ilocal);
|
|
|
|
invert_m4_m4(data->target2local, data->local2target);
|
|
|
|
}
|
|
|
|
|
2014-08-01 16:28:31 +02:00
|
|
|
void BLI_space_transform_apply(const SpaceTransform *data, float co[3])
|
|
|
|
{
|
|
|
|
mul_v3_m4v3(co, ((SpaceTransform *)data)->local2target, co);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BLI_space_transform_invert(const SpaceTransform *data, float co[3])
|
|
|
|
{
|
|
|
|
mul_v3_m4v3(co, ((SpaceTransform *)data)->target2local, co);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BLI_space_transform_apply_normal(const SpaceTransform *data, float no[3])
|
|
|
|
{
|
|
|
|
mul_mat3_m4_v3(((SpaceTransform *)data)->local2target, no);
|
|
|
|
normalize_v3(no);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BLI_space_transform_invert_normal(const SpaceTransform *data, float no[3])
|
|
|
|
{
|
|
|
|
mul_mat3_m4_v3(((SpaceTransform *)data)->target2local, no);
|
|
|
|
normalize_v3(no);
|
|
|
|
}
|