Mat4 inverse
Closed this issue · 2 comments
jimon commented
Would be nice to have mat inverse functions, they are quite useful for projecting screen coordinates back to world/model space. In most cases just having mat4 affine inverse will suffice.
jimon commented
Hm, I made a prototype for generic 4x4 inverse:
bool gb_mat4_inverse(gbMat4 * out, gbMat4 * in)
{
#define _M(__i, __j) in->col[__j].e[__i]
#define _MO(__i, __j) out->col[__j].e[__i]
#define _M3(a0, a1, a2, a3, a4, a5, a6, a7, a8) \
( a0 * (a4 * a8 - a5 * a7) \
- a1 * (a3 * a8 - a5 * a6) \
+ a2 * (a3 * a7 - a4 * a6) ) * d
float ka = _M(2, 2) * _M(3, 3) - _M(2, 3) * _M(3, 2);
float kb = _M(2, 1) * _M(3, 3) - _M(2, 3) * _M(3, 1);
float kc = _M(2, 1) * _M(3, 2) - _M(2, 2) * _M(3, 1);
float kd = _M(2, 0) * _M(3, 3) - _M(2, 3) * _M(3, 0);
float ke = _M(2, 0) * _M(3, 2) - _M(2, 2) * _M(3, 0);
float kf = _M(2, 0) * _M(3, 1) - _M(2, 1) * _M(3, 0);
float d = _M(0, 0) * (ka * _M(1, 1) - kb * _M(1, 2) + kc * _M(1, 3))
- _M(0, 1) * (ka * _M(1, 0) - kd * _M(1, 2) + ke * _M(1, 3))
+ _M(0, 2) * (kb * _M(1, 0) - kd * _M(1, 1) + kf * _M(1, 3))
- _M(0, 3) * (kc * _M(1, 0) - ke * _M(1, 1) + kf * _M(1, 2));
if(fabs(d) <= 0.0000000001f) // find a good epsilon
{
gb_mat4_identity(out);
return false;
}
d = 1.0f / d;
_MO(0, 0) = _M3(_M(1, 1), _M(1, 2), _M(1, 3), _M(2, 1), _M(2, 2), _M(2, 3), _M(3, 1), _M(3, 2), _M(3, 3));
_MO(0, 1) = -_M3(_M(0, 1), _M(0, 2), _M(0, 3), _M(2, 1), _M(2, 2), _M(2, 3), _M(3, 1), _M(3, 2), _M(3, 3));
_MO(0, 2) = _M3(_M(0, 1), _M(0, 2), _M(0, 3), _M(1, 1), _M(1, 2), _M(1, 3), _M(3, 1), _M(3, 2), _M(3, 3));
_MO(0, 3) = -_M3(_M(0, 1), _M(0, 2), _M(0, 3), _M(1, 1), _M(1, 2), _M(1, 3), _M(2, 1), _M(2, 2), _M(2, 3));
_MO(1, 0) = -_M3(_M(1, 0), _M(1, 2), _M(1, 3), _M(2, 0), _M(2, 2), _M(2, 3), _M(3, 0), _M(3, 2), _M(3, 3));
_MO(1, 1) = _M3(_M(0, 0), _M(0, 2), _M(0, 3), _M(2, 0), _M(2, 2), _M(2, 3), _M(3, 0), _M(3, 2), _M(3, 3));
_MO(1, 2) = -_M3(_M(0, 0), _M(0, 2), _M(0, 3), _M(1, 0), _M(1, 2), _M(1, 3), _M(3, 0), _M(3, 2), _M(3, 3));
_MO(1, 3) = _M3(_M(0, 0), _M(0, 2), _M(0, 3), _M(1, 0), _M(1, 2), _M(1, 3), _M(2, 0), _M(2, 2), _M(2, 3));
_MO(2, 0) = _M3(_M(1, 0), _M(1, 1), _M(1, 3), _M(2, 0), _M(2, 1), _M(2, 3), _M(3, 0), _M(3, 1), _M(3, 3));
_MO(2, 1) = -_M3(_M(0, 0), _M(0, 1), _M(0, 3), _M(2, 0), _M(2, 1), _M(2, 3), _M(3, 0), _M(3, 1), _M(3, 3));
_MO(2, 2) = _M3(_M(0, 0), _M(0, 1), _M(0, 3), _M(1, 0), _M(1, 1), _M(1, 3), _M(3, 0), _M(3, 1), _M(3, 3));
_MO(2, 3) = -_M3(_M(0, 0), _M(0, 1), _M(0, 3), _M(1, 0), _M(1, 1), _M(1, 3), _M(2, 0), _M(2, 1), _M(2, 3));
_MO(3, 0) = -_M3(_M(1, 0), _M(1, 1), _M(1, 2), _M(2, 0), _M(2, 1), _M(2, 2), _M(3, 0), _M(3, 1), _M(3, 2));
_MO(3, 1) = _M3(_M(0, 0), _M(0, 1), _M(0, 2), _M(2, 0), _M(2, 1), _M(2, 2), _M(3, 0), _M(3, 1), _M(3, 2));
_MO(3, 2) = -_M3(_M(0, 0), _M(0, 1), _M(0, 2), _M(1, 0), _M(1, 1), _M(1, 2), _M(3, 0), _M(3, 1), _M(3, 2));
_MO(3, 3) = _M3(_M(0, 0), _M(0, 1), _M(0, 2), _M(1, 0), _M(1, 1), _M(1, 2), _M(2, 0), _M(2, 1), _M(2, 2));
#undef _M3
#undef _M
#undef _MO
return true;
}
Is it something we can merge to upstream? Probably would be nice to have affine and generic versions for all implemented matrix sizes as well.
gingerBill commented
In the next update (v0.07), I will have inverse functions for all the matrix types.