mirror of
https://github.com/bloeys/gglm.git
synced 2025-12-29 13:38:20 +00:00
Compare commits
4 Commits
v0.44.0
...
95005baf22
| Author | SHA1 | Date | |
|---|---|---|---|
| 95005baf22 | |||
| c08e9d8610 | |||
| cc5e7dcbce | |||
| ca55a67100 |
58
gglm/mat2.go
58
gglm/mat2.go
@ -84,7 +84,6 @@ func (m *Mat2) Eq(m2 *Mat2) bool {
|
||||
}
|
||||
|
||||
func (m *Mat2) Transpose() *Mat2 {
|
||||
|
||||
m.Data = [2][2]float32{
|
||||
{m.Data[0][0], m.Data[1][0]},
|
||||
{m.Data[0][1], m.Data[1][1]},
|
||||
@ -93,6 +92,27 @@ func (m *Mat2) Transpose() *Mat2 {
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *Mat2) Determinant() float32 {
|
||||
return (m.Data[0][0] * m.Data[1][1]) - (m.Data[0][1] * m.Data[1][0])
|
||||
}
|
||||
|
||||
// Invert inverts this matrix.
|
||||
//
|
||||
// Note that the inverse is not defined if the determinant is zero or extremely small.
|
||||
// In the case the determinant is zero the matrix will (usually) get filled with infinities
|
||||
func (m *Mat2) Invert() *Mat2 {
|
||||
|
||||
// https://www.cuemath.com/algebra/inverse-of-2x2-matrix/
|
||||
inverseDet := 1 / m.Determinant()
|
||||
|
||||
m.Data = [2][2]float32{
|
||||
{m.Data[1][1] * inverseDet, -m.Data[0][1] * inverseDet}, // Col0
|
||||
{-m.Data[1][0] * inverseDet, m.Data[0][0] * inverseDet}, // Col1
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// AddMat2 m3 = m1 + m2
|
||||
func AddMat2(m1, m2 *Mat2) *Mat2 {
|
||||
return &Mat2{
|
||||
@ -160,3 +180,39 @@ func NewMat2Id() *Mat2 {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewMat2Diag(diagVal float32) *Mat2 {
|
||||
return &Mat2{
|
||||
Data: [2][2]float32{
|
||||
{diagVal, 0},
|
||||
{0, diagVal},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewMat2DiagArr(diag [2]float32) *Mat2 {
|
||||
return &Mat2{
|
||||
Data: [2][2]float32{
|
||||
{diag[0], 0},
|
||||
{0, diag[1]},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewMat2Vec2(col0, col1 *Vec2) *Mat2 {
|
||||
return &Mat2{
|
||||
Data: [2][2]float32{
|
||||
col0.Data,
|
||||
col1.Data,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewMat2Arr(col0, col1 [2]float32) *Mat2 {
|
||||
return &Mat2{
|
||||
Data: [2][2]float32{
|
||||
col0,
|
||||
col1,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,6 +179,56 @@ func TestTransposeMat2(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeterminantMat2(t *testing.T) {
|
||||
|
||||
m := gglm.NewMat2Id()
|
||||
ans := float32(1)
|
||||
|
||||
if m.Determinant() != ans {
|
||||
t.Errorf("Got: %f; Expected: %f", m.Determinant(), ans)
|
||||
}
|
||||
|
||||
m = &gglm.Mat2{
|
||||
Data: [2][2]float32{
|
||||
{1, 8},
|
||||
{5, 31},
|
||||
},
|
||||
}
|
||||
ans = -9
|
||||
|
||||
if m.Determinant() != ans {
|
||||
t.Errorf("Got: %f; Expected: %f", m.Determinant(), ans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvertMat2(t *testing.T) {
|
||||
|
||||
m := gglm.NewMat2Id()
|
||||
ans := gglm.NewMat2Id()
|
||||
|
||||
if !m.Invert().Eq(ans) {
|
||||
t.Errorf("Got: %v; Expected: %v", m.String(), ans.String())
|
||||
}
|
||||
|
||||
m = &gglm.Mat2{
|
||||
Data: [2][2]float32{
|
||||
{1, 8},
|
||||
{5, 31},
|
||||
},
|
||||
}
|
||||
|
||||
ans = &gglm.Mat2{
|
||||
Data: [2][2]float32{
|
||||
{-31 / 9.0, 8 / 9.0},
|
||||
{5 / 9.0, -1 / 9.0},
|
||||
},
|
||||
}
|
||||
|
||||
if !m.Invert().Eq(ans) {
|
||||
t.Errorf("Got: %v; Expected: %v", m.String(), ans.String())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMulMat2(b *testing.B) {
|
||||
|
||||
m1 := gglm.NewMat2Id()
|
||||
|
||||
99
gglm/mat3.go
99
gglm/mat3.go
@ -145,6 +145,65 @@ func (m *Mat3) Transpose() *Mat3 {
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *Mat3) Determinant() float32 {
|
||||
x := m.Data[0][0] * (m.Data[1][1]*m.Data[2][2] - m.Data[2][1]*m.Data[1][2])
|
||||
y := m.Data[1][0] * (m.Data[2][1]*m.Data[0][2] - m.Data[0][1]*m.Data[2][2])
|
||||
z := m.Data[2][0] * (m.Data[0][1]*m.Data[1][2] - m.Data[1][1]*m.Data[0][2])
|
||||
return x + y + z
|
||||
}
|
||||
|
||||
// Invert inverts this matrix.
|
||||
//
|
||||
// Note that the inverse is not defined if the determinant is zero or extremely small.
|
||||
// In the case the determinant is zero the matrix will (usually) get filled with infinities
|
||||
func (m *Mat3) Invert() *Mat3 {
|
||||
|
||||
// https://www.cuemath.com/algebra/inverse-of-3x3-matrix/
|
||||
|
||||
// Manually inline the determinant function because go doesn't
|
||||
x := m.Data[0][0] * (m.Data[1][1]*m.Data[2][2] - m.Data[2][1]*m.Data[1][2])
|
||||
y := m.Data[1][0] * (m.Data[2][1]*m.Data[0][2] - m.Data[0][1]*m.Data[2][2])
|
||||
z := m.Data[2][0] * (m.Data[0][1]*m.Data[1][2] - m.Data[1][1]*m.Data[0][2])
|
||||
|
||||
inverseDet := 1 / (x + y + z)
|
||||
|
||||
m.Data = [3][3]float32{
|
||||
// Col0
|
||||
{
|
||||
(m.Data[1][1]*m.Data[2][2] - m.Data[2][1]*m.Data[1][2]) * inverseDet,
|
||||
-(m.Data[0][1]*m.Data[2][2] - m.Data[2][1]*m.Data[0][2]) * inverseDet,
|
||||
(m.Data[0][1]*m.Data[1][2] - m.Data[1][1]*m.Data[0][2]) * inverseDet,
|
||||
},
|
||||
|
||||
// Col1
|
||||
{
|
||||
-(m.Data[1][0]*m.Data[2][2] - m.Data[2][0]*m.Data[1][2]) * inverseDet,
|
||||
(m.Data[0][0]*m.Data[2][2] - m.Data[2][0]*m.Data[0][2]) * inverseDet,
|
||||
-(m.Data[0][0]*m.Data[1][2] - m.Data[1][0]*m.Data[0][2]) * inverseDet,
|
||||
},
|
||||
|
||||
// Col2
|
||||
{
|
||||
(m.Data[1][0]*m.Data[2][1] - m.Data[2][0]*m.Data[1][1]) * inverseDet,
|
||||
-(m.Data[0][0]*m.Data[2][1] - m.Data[2][0]*m.Data[0][1]) * inverseDet,
|
||||
(m.Data[0][0]*m.Data[1][1] - m.Data[1][0]*m.Data[0][1]) * inverseDet,
|
||||
},
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// ToMat2 returns a Mat2 that contains the top-left 2x2 section of the Mat3.
|
||||
// That is, column 2 and row 2 are dropped.
|
||||
func (m *Mat3) ToMat2() Mat2 {
|
||||
return Mat2{
|
||||
Data: [2][2]float32{
|
||||
{m.Data[0][0], m.Data[0][1]},
|
||||
{m.Data[1][0], m.Data[1][1]},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// AddMat3 m3 = m1 + m2
|
||||
func AddMat3(m1, m2 *Mat3) *Mat3 {
|
||||
return &Mat3{
|
||||
@ -248,3 +307,43 @@ func NewMat3Id() *Mat3 {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewMat3Diag(diagVal float32) *Mat3 {
|
||||
return &Mat3{
|
||||
Data: [3][3]float32{
|
||||
{diagVal, 0, 0},
|
||||
{0, diagVal, 0},
|
||||
{0, 0, diagVal},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewMat3DiagArr(diag [3]float32) *Mat3 {
|
||||
return &Mat3{
|
||||
Data: [3][3]float32{
|
||||
{diag[0], 0, 0},
|
||||
{0, diag[1], 0},
|
||||
{0, 0, diag[2]},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewMat3Vec3(col0, col1, col2 *Vec3) *Mat3 {
|
||||
return &Mat3{
|
||||
Data: [3][3]float32{
|
||||
col0.Data,
|
||||
col1.Data,
|
||||
col2.Data,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewMat3Arr(col0, col1, col2 [3]float32) *Mat3 {
|
||||
return &Mat3{
|
||||
Data: [3][3]float32{
|
||||
col0,
|
||||
col1,
|
||||
col2,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,6 +196,59 @@ func TestTransposeMat3(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeterminantMat3(t *testing.T) {
|
||||
|
||||
m := gglm.NewMat3Id()
|
||||
ans := float32(1)
|
||||
|
||||
if m.Determinant() != ans {
|
||||
t.Errorf("Got: %f; Expected: %f", m.Determinant(), ans)
|
||||
}
|
||||
|
||||
m = &gglm.Mat3{
|
||||
Data: [3][3]float32{
|
||||
{1, 8, 2},
|
||||
{5, 3, 5},
|
||||
{9, 6, 7},
|
||||
},
|
||||
}
|
||||
ans = 77
|
||||
|
||||
if m.Determinant() != ans {
|
||||
t.Errorf("Got: %f; Expected: %f", m.Determinant(), ans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvertMat3(t *testing.T) {
|
||||
|
||||
m := gglm.NewMat3Id()
|
||||
ans := gglm.NewMat3Id()
|
||||
|
||||
if !m.Invert().Eq(ans) {
|
||||
t.Errorf("Got: %v; Expected: %v", m.String(), ans.String())
|
||||
}
|
||||
|
||||
m = &gglm.Mat3{
|
||||
Data: [3][3]float32{
|
||||
{1, 8, 2},
|
||||
{5, 3, 5},
|
||||
{9, 6, 7},
|
||||
},
|
||||
}
|
||||
|
||||
ans = &gglm.Mat3{
|
||||
Data: [3][3]float32{
|
||||
{-9 / 77.0, -4 / 7.0, 34 / 77.0},
|
||||
{10 / 77.0, -1 / 7.0, 5 / 77.0},
|
||||
{3 / 77.0, 6 / 7.0, -37 / 77.0},
|
||||
},
|
||||
}
|
||||
|
||||
if !m.Invert().Eq(ans) {
|
||||
t.Errorf("Got: %v; Expected: %v", m.String(), ans.String())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMulMat3(b *testing.B) {
|
||||
|
||||
m1 := gglm.NewMat3Id()
|
||||
|
||||
346
gglm/mat4.go
346
gglm/mat4.go
@ -192,6 +192,308 @@ func (m *Mat4) Transpose() *Mat4 {
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *Mat4) Determinant() float32 {
|
||||
|
||||
// Many thanks to the C++ GLM project here :)
|
||||
|
||||
coef00 := m.Data[2][2]*m.Data[3][3] - m.Data[3][2]*m.Data[2][3]
|
||||
coef02 := m.Data[1][2]*m.Data[3][3] - m.Data[3][2]*m.Data[1][3]
|
||||
coef03 := m.Data[1][2]*m.Data[2][3] - m.Data[2][2]*m.Data[1][3]
|
||||
|
||||
coef04 := m.Data[2][1]*m.Data[3][3] - m.Data[3][1]*m.Data[2][3]
|
||||
coef06 := m.Data[1][1]*m.Data[3][3] - m.Data[3][1]*m.Data[1][3]
|
||||
coef07 := m.Data[1][1]*m.Data[2][3] - m.Data[2][1]*m.Data[1][3]
|
||||
|
||||
coef08 := m.Data[2][1]*m.Data[3][2] - m.Data[3][1]*m.Data[2][2]
|
||||
coef10 := m.Data[1][1]*m.Data[3][2] - m.Data[3][1]*m.Data[1][2]
|
||||
coef11 := m.Data[1][1]*m.Data[2][2] - m.Data[2][1]*m.Data[1][2]
|
||||
|
||||
coef12 := m.Data[2][0]*m.Data[3][3] - m.Data[3][0]*m.Data[2][3]
|
||||
coef14 := m.Data[1][0]*m.Data[3][3] - m.Data[3][0]*m.Data[1][3]
|
||||
coef15 := m.Data[1][0]*m.Data[2][3] - m.Data[2][0]*m.Data[1][3]
|
||||
|
||||
coef16 := m.Data[2][0]*m.Data[3][2] - m.Data[3][0]*m.Data[2][2]
|
||||
coef18 := m.Data[1][0]*m.Data[3][2] - m.Data[3][0]*m.Data[1][2]
|
||||
coef19 := m.Data[1][0]*m.Data[2][2] - m.Data[2][0]*m.Data[1][2]
|
||||
|
||||
coef20 := m.Data[2][0]*m.Data[3][1] - m.Data[3][0]*m.Data[2][1]
|
||||
coef22 := m.Data[1][0]*m.Data[3][1] - m.Data[3][0]*m.Data[1][1]
|
||||
coef23 := m.Data[1][0]*m.Data[2][1] - m.Data[2][0]*m.Data[1][1]
|
||||
|
||||
fac0 := NewVec4(coef00, coef00, coef02, coef03)
|
||||
fac1 := NewVec4(coef04, coef04, coef06, coef07)
|
||||
fac2 := NewVec4(coef08, coef08, coef10, coef11)
|
||||
fac3 := NewVec4(coef12, coef12, coef14, coef15)
|
||||
fac4 := NewVec4(coef16, coef16, coef18, coef19)
|
||||
fac5 := NewVec4(coef20, coef20, coef22, coef23)
|
||||
|
||||
vec0 := NewVec4(m.Data[1][0], m.Data[0][0], m.Data[0][0], m.Data[0][0])
|
||||
vec1 := NewVec4(m.Data[1][1], m.Data[0][1], m.Data[0][1], m.Data[0][1])
|
||||
vec2 := NewVec4(m.Data[1][2], m.Data[0][2], m.Data[0][2], m.Data[0][2])
|
||||
vec3 := NewVec4(m.Data[1][3], m.Data[0][3], m.Data[0][3], m.Data[0][3])
|
||||
|
||||
inv0 := NewVec4(
|
||||
vec1.X()*fac0.X()-vec2.X()*fac1.X()+vec3.X()*fac2.X(),
|
||||
vec1.Y()*fac0.Y()-vec2.Y()*fac1.Y()+vec3.Y()*fac2.Y(),
|
||||
vec1.Z()*fac0.Z()-vec2.Z()*fac1.Z()+vec3.Z()*fac2.Z(),
|
||||
vec1.W()*fac0.W()-vec2.W()*fac1.W()+vec3.W()*fac2.W(),
|
||||
)
|
||||
|
||||
inv1 := NewVec4(
|
||||
vec0.X()*fac0.X()-vec2.X()*fac3.X()+vec3.X()*fac4.X(),
|
||||
vec0.Y()*fac0.Y()-vec2.Y()*fac3.Y()+vec3.Y()*fac4.Y(),
|
||||
vec0.Z()*fac0.Z()-vec2.Z()*fac3.Z()+vec3.Z()*fac4.Z(),
|
||||
vec0.W()*fac0.W()-vec2.W()*fac3.W()+vec3.W()*fac4.W(),
|
||||
)
|
||||
|
||||
inv2 := NewVec4(
|
||||
vec0.X()*fac1.X()-vec1.X()*fac3.X()+vec3.X()*fac5.X(),
|
||||
vec0.Y()*fac1.Y()-vec1.Y()*fac3.Y()+vec3.Y()*fac5.Y(),
|
||||
vec0.Z()*fac1.Z()-vec1.Z()*fac3.Z()+vec3.Z()*fac5.Z(),
|
||||
vec0.W()*fac1.W()-vec1.W()*fac3.W()+vec3.W()*fac5.W(),
|
||||
)
|
||||
|
||||
inv3 := NewVec4(
|
||||
vec0.X()*fac2.X()-vec1.X()*fac4.X()+vec2.X()*fac5.X(),
|
||||
vec0.Y()*fac2.Y()-vec1.Y()*fac4.Y()+vec2.Y()*fac5.Y(),
|
||||
vec0.Z()*fac2.Z()-vec1.Z()*fac4.Z()+vec2.Z()*fac5.Z(),
|
||||
vec0.W()*fac2.W()-vec1.W()*fac4.W()+vec2.W()*fac5.W(),
|
||||
)
|
||||
|
||||
signA := NewVec4(+1, -1, +1, -1)
|
||||
signB := NewVec4(-1, +1, -1, +1)
|
||||
|
||||
inverse := NewMat4Arr(
|
||||
inv0.ScaleVec(signA).Data,
|
||||
inv1.ScaleVec(signB).Data,
|
||||
inv2.ScaleVec(signA).Data,
|
||||
inv3.ScaleVec(signB).Data,
|
||||
)
|
||||
|
||||
row0 := NewVec4(inverse.Data[0][0], inverse.Data[1][0], inverse.Data[2][0], inverse.Data[3][0])
|
||||
dot0 := NewVec4Arr(row0.ScaleArr(m.Data[0]).Data)
|
||||
det := (dot0.X() + dot0.Y()) + (dot0.Z() + dot0.W())
|
||||
|
||||
return det
|
||||
}
|
||||
|
||||
// Invert inverts this matrix.
|
||||
//
|
||||
// Note that the inverse is not defined if the determinant is zero or extremely small.
|
||||
// In the case the determinant is zero the matrix will (usually) get filled with infinities
|
||||
func (m *Mat4) Invert() *Mat4 {
|
||||
|
||||
// Many thanks to the C++ GLM project here :)
|
||||
|
||||
coef00 := m.Data[2][2]*m.Data[3][3] - m.Data[3][2]*m.Data[2][3]
|
||||
coef02 := m.Data[1][2]*m.Data[3][3] - m.Data[3][2]*m.Data[1][3]
|
||||
coef03 := m.Data[1][2]*m.Data[2][3] - m.Data[2][2]*m.Data[1][3]
|
||||
|
||||
coef04 := m.Data[2][1]*m.Data[3][3] - m.Data[3][1]*m.Data[2][3]
|
||||
coef06 := m.Data[1][1]*m.Data[3][3] - m.Data[3][1]*m.Data[1][3]
|
||||
coef07 := m.Data[1][1]*m.Data[2][3] - m.Data[2][1]*m.Data[1][3]
|
||||
|
||||
coef08 := m.Data[2][1]*m.Data[3][2] - m.Data[3][1]*m.Data[2][2]
|
||||
coef10 := m.Data[1][1]*m.Data[3][2] - m.Data[3][1]*m.Data[1][2]
|
||||
coef11 := m.Data[1][1]*m.Data[2][2] - m.Data[2][1]*m.Data[1][2]
|
||||
|
||||
coef12 := m.Data[2][0]*m.Data[3][3] - m.Data[3][0]*m.Data[2][3]
|
||||
coef14 := m.Data[1][0]*m.Data[3][3] - m.Data[3][0]*m.Data[1][3]
|
||||
coef15 := m.Data[1][0]*m.Data[2][3] - m.Data[2][0]*m.Data[1][3]
|
||||
|
||||
coef16 := m.Data[2][0]*m.Data[3][2] - m.Data[3][0]*m.Data[2][2]
|
||||
coef18 := m.Data[1][0]*m.Data[3][2] - m.Data[3][0]*m.Data[1][2]
|
||||
coef19 := m.Data[1][0]*m.Data[2][2] - m.Data[2][0]*m.Data[1][2]
|
||||
|
||||
coef20 := m.Data[2][0]*m.Data[3][1] - m.Data[3][0]*m.Data[2][1]
|
||||
coef22 := m.Data[1][0]*m.Data[3][1] - m.Data[3][0]*m.Data[1][1]
|
||||
coef23 := m.Data[1][0]*m.Data[2][1] - m.Data[2][0]*m.Data[1][1]
|
||||
|
||||
fac0 := NewVec4(coef00, coef00, coef02, coef03)
|
||||
fac1 := NewVec4(coef04, coef04, coef06, coef07)
|
||||
fac2 := NewVec4(coef08, coef08, coef10, coef11)
|
||||
fac3 := NewVec4(coef12, coef12, coef14, coef15)
|
||||
fac4 := NewVec4(coef16, coef16, coef18, coef19)
|
||||
fac5 := NewVec4(coef20, coef20, coef22, coef23)
|
||||
|
||||
vec0 := NewVec4(m.Data[1][0], m.Data[0][0], m.Data[0][0], m.Data[0][0])
|
||||
vec1 := NewVec4(m.Data[1][1], m.Data[0][1], m.Data[0][1], m.Data[0][1])
|
||||
vec2 := NewVec4(m.Data[1][2], m.Data[0][2], m.Data[0][2], m.Data[0][2])
|
||||
vec3 := NewVec4(m.Data[1][3], m.Data[0][3], m.Data[0][3], m.Data[0][3])
|
||||
|
||||
inv0 := NewVec4(
|
||||
vec1.X()*fac0.X()-vec2.X()*fac1.X()+vec3.X()*fac2.X(),
|
||||
vec1.Y()*fac0.Y()-vec2.Y()*fac1.Y()+vec3.Y()*fac2.Y(),
|
||||
vec1.Z()*fac0.Z()-vec2.Z()*fac1.Z()+vec3.Z()*fac2.Z(),
|
||||
vec1.W()*fac0.W()-vec2.W()*fac1.W()+vec3.W()*fac2.W(),
|
||||
)
|
||||
|
||||
inv1 := NewVec4(
|
||||
vec0.X()*fac0.X()-vec2.X()*fac3.X()+vec3.X()*fac4.X(),
|
||||
vec0.Y()*fac0.Y()-vec2.Y()*fac3.Y()+vec3.Y()*fac4.Y(),
|
||||
vec0.Z()*fac0.Z()-vec2.Z()*fac3.Z()+vec3.Z()*fac4.Z(),
|
||||
vec0.W()*fac0.W()-vec2.W()*fac3.W()+vec3.W()*fac4.W(),
|
||||
)
|
||||
|
||||
inv2 := NewVec4(
|
||||
vec0.X()*fac1.X()-vec1.X()*fac3.X()+vec3.X()*fac5.X(),
|
||||
vec0.Y()*fac1.Y()-vec1.Y()*fac3.Y()+vec3.Y()*fac5.Y(),
|
||||
vec0.Z()*fac1.Z()-vec1.Z()*fac3.Z()+vec3.Z()*fac5.Z(),
|
||||
vec0.W()*fac1.W()-vec1.W()*fac3.W()+vec3.W()*fac5.W(),
|
||||
)
|
||||
|
||||
inv3 := NewVec4(
|
||||
vec0.X()*fac2.X()-vec1.X()*fac4.X()+vec2.X()*fac5.X(),
|
||||
vec0.Y()*fac2.Y()-vec1.Y()*fac4.Y()+vec2.Y()*fac5.Y(),
|
||||
vec0.Z()*fac2.Z()-vec1.Z()*fac4.Z()+vec2.Z()*fac5.Z(),
|
||||
vec0.W()*fac2.W()-vec1.W()*fac4.W()+vec2.W()*fac5.W(),
|
||||
)
|
||||
|
||||
signA := NewVec4(+1, -1, +1, -1)
|
||||
signB := NewVec4(-1, +1, -1, +1)
|
||||
|
||||
inverse := NewMat4Arr(
|
||||
inv0.ScaleVec(signA).Data,
|
||||
inv1.ScaleVec(signB).Data,
|
||||
inv2.ScaleVec(signA).Data,
|
||||
inv3.ScaleVec(signB).Data,
|
||||
)
|
||||
|
||||
row0 := NewVec4(inverse.Data[0][0], inverse.Data[1][0], inverse.Data[2][0], inverse.Data[3][0])
|
||||
dot0 := NewVec4Arr(row0.ScaleArr(m.Data[0]).Data)
|
||||
det := (dot0.X() + dot0.Y()) + (dot0.Z() + dot0.W())
|
||||
|
||||
inverseDet := 1.0 / det
|
||||
|
||||
m.Data = inverse.Scale(inverseDet).Data
|
||||
return m
|
||||
}
|
||||
|
||||
// InvertAndTranspose is equivalent to m.Invert().Transpose(), that is invert first, then transpose the inverted matrix.
|
||||
//
|
||||
// This function is provided as a convenience and as a small optimization, as it inlines the invert and transpose functions which means we only
|
||||
// have 1 function call.
|
||||
//
|
||||
// Additionally, the inverse of the matrix is written to the matrix immediately transposed instead of writing the inverse and then transposing it in a second operation.
|
||||
func (m *Mat4) InvertAndTranspose() *Mat4 {
|
||||
|
||||
// Many thanks to the C++ GLM project here :)
|
||||
|
||||
coef00 := m.Data[2][2]*m.Data[3][3] - m.Data[3][2]*m.Data[2][3]
|
||||
coef02 := m.Data[1][2]*m.Data[3][3] - m.Data[3][2]*m.Data[1][3]
|
||||
coef03 := m.Data[1][2]*m.Data[2][3] - m.Data[2][2]*m.Data[1][3]
|
||||
|
||||
coef04 := m.Data[2][1]*m.Data[3][3] - m.Data[3][1]*m.Data[2][3]
|
||||
coef06 := m.Data[1][1]*m.Data[3][3] - m.Data[3][1]*m.Data[1][3]
|
||||
coef07 := m.Data[1][1]*m.Data[2][3] - m.Data[2][1]*m.Data[1][3]
|
||||
|
||||
coef08 := m.Data[2][1]*m.Data[3][2] - m.Data[3][1]*m.Data[2][2]
|
||||
coef10 := m.Data[1][1]*m.Data[3][2] - m.Data[3][1]*m.Data[1][2]
|
||||
coef11 := m.Data[1][1]*m.Data[2][2] - m.Data[2][1]*m.Data[1][2]
|
||||
|
||||
coef12 := m.Data[2][0]*m.Data[3][3] - m.Data[3][0]*m.Data[2][3]
|
||||
coef14 := m.Data[1][0]*m.Data[3][3] - m.Data[3][0]*m.Data[1][3]
|
||||
coef15 := m.Data[1][0]*m.Data[2][3] - m.Data[2][0]*m.Data[1][3]
|
||||
|
||||
coef16 := m.Data[2][0]*m.Data[3][2] - m.Data[3][0]*m.Data[2][2]
|
||||
coef18 := m.Data[1][0]*m.Data[3][2] - m.Data[3][0]*m.Data[1][2]
|
||||
coef19 := m.Data[1][0]*m.Data[2][2] - m.Data[2][0]*m.Data[1][2]
|
||||
|
||||
coef20 := m.Data[2][0]*m.Data[3][1] - m.Data[3][0]*m.Data[2][1]
|
||||
coef22 := m.Data[1][0]*m.Data[3][1] - m.Data[3][0]*m.Data[1][1]
|
||||
coef23 := m.Data[1][0]*m.Data[2][1] - m.Data[2][0]*m.Data[1][1]
|
||||
|
||||
fac0 := NewVec4(coef00, coef00, coef02, coef03)
|
||||
fac1 := NewVec4(coef04, coef04, coef06, coef07)
|
||||
fac2 := NewVec4(coef08, coef08, coef10, coef11)
|
||||
fac3 := NewVec4(coef12, coef12, coef14, coef15)
|
||||
fac4 := NewVec4(coef16, coef16, coef18, coef19)
|
||||
fac5 := NewVec4(coef20, coef20, coef22, coef23)
|
||||
|
||||
vec0 := NewVec4(m.Data[1][0], m.Data[0][0], m.Data[0][0], m.Data[0][0])
|
||||
vec1 := NewVec4(m.Data[1][1], m.Data[0][1], m.Data[0][1], m.Data[0][1])
|
||||
vec2 := NewVec4(m.Data[1][2], m.Data[0][2], m.Data[0][2], m.Data[0][2])
|
||||
vec3 := NewVec4(m.Data[1][3], m.Data[0][3], m.Data[0][3], m.Data[0][3])
|
||||
|
||||
inv0 := NewVec4(
|
||||
vec1.X()*fac0.X()-vec2.X()*fac1.X()+vec3.X()*fac2.X(),
|
||||
vec1.Y()*fac0.Y()-vec2.Y()*fac1.Y()+vec3.Y()*fac2.Y(),
|
||||
vec1.Z()*fac0.Z()-vec2.Z()*fac1.Z()+vec3.Z()*fac2.Z(),
|
||||
vec1.W()*fac0.W()-vec2.W()*fac1.W()+vec3.W()*fac2.W(),
|
||||
)
|
||||
|
||||
inv1 := NewVec4(
|
||||
vec0.X()*fac0.X()-vec2.X()*fac3.X()+vec3.X()*fac4.X(),
|
||||
vec0.Y()*fac0.Y()-vec2.Y()*fac3.Y()+vec3.Y()*fac4.Y(),
|
||||
vec0.Z()*fac0.Z()-vec2.Z()*fac3.Z()+vec3.Z()*fac4.Z(),
|
||||
vec0.W()*fac0.W()-vec2.W()*fac3.W()+vec3.W()*fac4.W(),
|
||||
)
|
||||
|
||||
inv2 := NewVec4(
|
||||
vec0.X()*fac1.X()-vec1.X()*fac3.X()+vec3.X()*fac5.X(),
|
||||
vec0.Y()*fac1.Y()-vec1.Y()*fac3.Y()+vec3.Y()*fac5.Y(),
|
||||
vec0.Z()*fac1.Z()-vec1.Z()*fac3.Z()+vec3.Z()*fac5.Z(),
|
||||
vec0.W()*fac1.W()-vec1.W()*fac3.W()+vec3.W()*fac5.W(),
|
||||
)
|
||||
|
||||
inv3 := NewVec4(
|
||||
vec0.X()*fac2.X()-vec1.X()*fac4.X()+vec2.X()*fac5.X(),
|
||||
vec0.Y()*fac2.Y()-vec1.Y()*fac4.Y()+vec2.Y()*fac5.Y(),
|
||||
vec0.Z()*fac2.Z()-vec1.Z()*fac4.Z()+vec2.Z()*fac5.Z(),
|
||||
vec0.W()*fac2.W()-vec1.W()*fac4.W()+vec2.W()*fac5.W(),
|
||||
)
|
||||
|
||||
signA := NewVec4(+1, -1, +1, -1)
|
||||
signB := NewVec4(-1, +1, -1, +1)
|
||||
|
||||
inverse := NewMat4Arr(
|
||||
inv0.ScaleVec(signA).Data,
|
||||
inv1.ScaleVec(signB).Data,
|
||||
inv2.ScaleVec(signA).Data,
|
||||
inv3.ScaleVec(signB).Data,
|
||||
)
|
||||
|
||||
row0 := NewVec4(inverse.Data[0][0], inverse.Data[1][0], inverse.Data[2][0], inverse.Data[3][0])
|
||||
dot0 := NewVec4Arr(row0.ScaleArr(m.Data[0]).Data)
|
||||
det := (dot0.X() + dot0.Y()) + (dot0.Z() + dot0.W())
|
||||
|
||||
inverseDet := 1.0 / det
|
||||
inverse.Scale(inverseDet)
|
||||
|
||||
// Manually inline transpose
|
||||
m.Data = [4][4]float32{
|
||||
{inverse.Data[0][0], inverse.Data[1][0], inverse.Data[2][0], inverse.Data[3][0]},
|
||||
{inverse.Data[0][1], inverse.Data[1][1], inverse.Data[2][1], inverse.Data[3][1]},
|
||||
{inverse.Data[0][2], inverse.Data[1][2], inverse.Data[2][2], inverse.Data[3][2]},
|
||||
{inverse.Data[0][3], inverse.Data[1][3], inverse.Data[2][3], inverse.Data[3][3]},
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// ToMat2 returns a Mat2 that contains the top-left 2x2 section of the Mat4.
|
||||
// That is, columns 2 and 3, and rows 2 and 3, are dropped.
|
||||
func (m *Mat4) ToMat2() Mat2 {
|
||||
return Mat2{
|
||||
Data: [2][2]float32{
|
||||
{m.Data[0][0], m.Data[0][1]},
|
||||
{m.Data[1][0], m.Data[1][1]},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ToMat3 returns a Mat3 that contains the top-left 3x3 section of the Mat4.
|
||||
// That is, column 3 and row 3 are dropped.
|
||||
func (m *Mat4) ToMat3() Mat3 {
|
||||
return Mat3{
|
||||
Data: [3][3]float32{
|
||||
{m.Data[0][0], m.Data[0][1], m.Data[0][2]},
|
||||
{m.Data[1][0], m.Data[1][1], m.Data[1][2]},
|
||||
{m.Data[2][0], m.Data[2][1], m.Data[2][2]},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// AddMat4 m3 = m1 + m2
|
||||
func AddMat4(m1, m2 *Mat4) *Mat4 {
|
||||
return &Mat4{
|
||||
@ -332,3 +634,47 @@ func NewMat4Id() *Mat4 {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewMat4Diag(diagVal float32) *Mat4 {
|
||||
return &Mat4{
|
||||
Data: [4][4]float32{
|
||||
{diagVal, 0, 0, 0},
|
||||
{0, diagVal, 0, 0},
|
||||
{0, 0, diagVal, 0},
|
||||
{0, 0, 0, diagVal},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewMat4DiagArr(diag [4]float32) *Mat4 {
|
||||
return &Mat4{
|
||||
Data: [4][4]float32{
|
||||
{diag[0], 0, 0, 0},
|
||||
{0, diag[1], 0, 0},
|
||||
{0, 0, diag[2], 0},
|
||||
{0, 0, 0, diag[3]},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewMat4Vec4(col0, col1, col2, col3 *Vec4) *Mat4 {
|
||||
return &Mat4{
|
||||
Data: [4][4]float32{
|
||||
col0.Data,
|
||||
col1.Data,
|
||||
col2.Data,
|
||||
col3.Data,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewMat4Arr(col0, col1, col2, col3 [4]float32) *Mat4 {
|
||||
return &Mat4{
|
||||
Data: [4][4]float32{
|
||||
col0,
|
||||
col1,
|
||||
col2,
|
||||
col3,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,6 +218,94 @@ func TestTransposeMat4(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeterminantMat4(t *testing.T) {
|
||||
|
||||
m := gglm.NewMat4Id()
|
||||
ans := float32(1)
|
||||
|
||||
if m.Determinant() != ans {
|
||||
t.Errorf("Got: %f; Expected: %f", m.Determinant(), ans)
|
||||
}
|
||||
|
||||
m = &gglm.Mat4{
|
||||
Data: [4][4]float32{
|
||||
{1, 0, 2, 1},
|
||||
{2, 1, 3, 0},
|
||||
{3, 0, 4, 1},
|
||||
{4, 1, 5, 1},
|
||||
},
|
||||
}
|
||||
ans = -2
|
||||
|
||||
if m.Determinant() != ans {
|
||||
t.Errorf("Got: %f; Expected: %f", m.Determinant(), ans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvertMat4(t *testing.T) {
|
||||
|
||||
m := gglm.NewMat4Id()
|
||||
ans := gglm.NewMat4Id()
|
||||
|
||||
if !m.Invert().Eq(ans) {
|
||||
t.Errorf("Got: %v; Expected: %v", m.String(), ans.String())
|
||||
}
|
||||
|
||||
m = &gglm.Mat4{
|
||||
Data: [4][4]float32{
|
||||
{1, 0, 2, 1},
|
||||
{2, 1, 3, 0},
|
||||
{3, 0, 4, 1},
|
||||
{4, 1, 5, 1},
|
||||
},
|
||||
}
|
||||
|
||||
ans = &gglm.Mat4{
|
||||
Data: [4][4]float32{
|
||||
{-1, -1, 0, 1},
|
||||
{0.5, 0, -3 / 2.0, 1},
|
||||
{0.5, 1, 0.5, -1},
|
||||
{1, -1, -1, 1},
|
||||
},
|
||||
}
|
||||
|
||||
if !m.Invert().Eq(ans) {
|
||||
t.Errorf("Got: %v\nExpected: %v;\n", m.String(), ans.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvertAndTransposeMat4(t *testing.T) {
|
||||
|
||||
m := gglm.NewMat4Id()
|
||||
ans := gglm.NewMat4Id().Transpose()
|
||||
|
||||
if !m.InvertAndTranspose().Eq(ans) {
|
||||
t.Errorf("Got: %v; Expected: %v", m.String(), ans.String())
|
||||
}
|
||||
|
||||
m = &gglm.Mat4{
|
||||
Data: [4][4]float32{
|
||||
{1, 0, 2, 1},
|
||||
{2, 1, 3, 0},
|
||||
{3, 0, 4, 1},
|
||||
{4, 1, 5, 1},
|
||||
},
|
||||
}
|
||||
|
||||
ans = &gglm.Mat4{
|
||||
Data: [4][4]float32{
|
||||
{-1, -1, 0, 1},
|
||||
{0.5, 0, -3 / 2.0, 1},
|
||||
{0.5, 1, 0.5, -1},
|
||||
{1, -1, -1, 1},
|
||||
},
|
||||
}
|
||||
|
||||
if !m.InvertAndTranspose().Eq(ans.Transpose()) {
|
||||
t.Errorf("Got: %v\nExpected: %v;\n", m.String(), ans.String())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMulMat4(b *testing.B) {
|
||||
|
||||
m1 := gglm.NewMat4Id()
|
||||
|
||||
20
gglm/vec2.go
20
gglm/vec2.go
@ -93,6 +93,20 @@ func (v *Vec2) Scale(x float32) *Vec2 {
|
||||
return v
|
||||
}
|
||||
|
||||
// ScaleVec v *= v2 (element wise multiplication)
|
||||
func (v *Vec2) ScaleVec(v2 *Vec2) *Vec2 {
|
||||
v.Data[0] *= v2.X()
|
||||
v.Data[1] *= v2.Y()
|
||||
return v
|
||||
}
|
||||
|
||||
// ScaleArr v *= arr (element wise multiplication)
|
||||
func (v *Vec2) ScaleArr(arr [2]float32) *Vec2 {
|
||||
v.Data[0] *= arr[0]
|
||||
v.Data[1] *= arr[1]
|
||||
return v
|
||||
}
|
||||
|
||||
// Add v += v2
|
||||
func (v *Vec2) Add(v2 *Vec2) *Vec2 {
|
||||
v.Data[0] += v2.X()
|
||||
@ -164,3 +178,9 @@ func NewVec2(x, y float32) *Vec2 {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewVec2Arr(arr [2]float32) *Vec2 {
|
||||
return &Vec2{
|
||||
Data: arr,
|
||||
}
|
||||
}
|
||||
|
||||
22
gglm/vec3.go
22
gglm/vec3.go
@ -140,6 +140,22 @@ func (v *Vec3) Scale(x float32) *Vec3 {
|
||||
return v
|
||||
}
|
||||
|
||||
// ScaleVec v *= v2 (element wise multiplication)
|
||||
func (v *Vec3) ScaleVec(v2 *Vec3) *Vec3 {
|
||||
v.Data[0] *= v2.X()
|
||||
v.Data[1] *= v2.Y()
|
||||
v.Data[2] *= v2.Z()
|
||||
return v
|
||||
}
|
||||
|
||||
// ScaleArr v *= arr (element wise multiplication)
|
||||
func (v *Vec3) ScaleArr(arr [3]float32) *Vec3 {
|
||||
v.Data[0] *= arr[0]
|
||||
v.Data[1] *= arr[1]
|
||||
v.Data[2] *= arr[2]
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *Vec3) Add(v2 *Vec3) *Vec3 {
|
||||
|
||||
v.Data[0] += v2.X()
|
||||
@ -251,3 +267,9 @@ func NewVec3(x, y, z float32) *Vec3 {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewVec3Arr(arr [3]float32) *Vec3 {
|
||||
return &Vec3{
|
||||
Data: arr,
|
||||
}
|
||||
}
|
||||
|
||||
24
gglm/vec4.go
24
gglm/vec4.go
@ -193,6 +193,24 @@ func (v *Vec4) Scale(x float32) *Vec4 {
|
||||
return v
|
||||
}
|
||||
|
||||
// ScaleVec v *= v2 (element wise multiplication)
|
||||
func (v *Vec4) ScaleVec(v2 *Vec4) *Vec4 {
|
||||
v.Data[0] *= v2.X()
|
||||
v.Data[1] *= v2.Y()
|
||||
v.Data[2] *= v2.Z()
|
||||
v.Data[3] *= v2.W()
|
||||
return v
|
||||
}
|
||||
|
||||
// ScaleArr v *= arr (element wise multiplication)
|
||||
func (v *Vec4) ScaleArr(arr [4]float32) *Vec4 {
|
||||
v.Data[0] *= arr[0]
|
||||
v.Data[1] *= arr[1]
|
||||
v.Data[2] *= arr[2]
|
||||
v.Data[3] *= arr[3]
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *Vec4) Add(v2 *Vec4) *Vec4 {
|
||||
v.Data[0] += v2.X()
|
||||
v.Data[1] += v2.Y()
|
||||
@ -277,3 +295,9 @@ func NewVec4(x, y, z, w float32) *Vec4 {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewVec4Arr(arr [4]float32) *Vec4 {
|
||||
return &Vec4{
|
||||
Data: arr,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user