2020-06-13 21:40:56 +08:00

847 lines
17 KiB
Go

// Copyright 2017-2020 The ShadowEditor Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
//
// For more information, please visit: https://github.com/tengge1/ShadowEditor
// You can also visit: https://gitee.com/tengge1/ShadowEditor
//
// This package is translated from three.js, visit `https://github.com/mrdoob/three.js`
// for more information.
package three
import "math"
var _v1Matrix4 = NewVector3(0, 0, 0)
var _m1 = NewMatrix4()
var _zero = NewVector3(0, 0, 0)
var _one = NewVector3(1, 1, 1)
var _x = NewVector3(0, 0, 0)
var _y = NewVector3(0, 0, 0)
var _z = NewVector3(0, 0, 0)
// NewMatrix4 :
func NewMatrix4() *Matrix4 {
elements := [16]float64{
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
}
return &Matrix4{elements}
}
// Matrix4 :
type Matrix4 struct {
Elements [16]float64
}
// Set :
func (m Matrix4) Set(n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 float64) *Matrix4 {
te := m.Elements
te[0] = n11
te[4] = n12
te[8] = n13
te[12] = n14
te[1] = n21
te[5] = n22
te[9] = n23
te[13] = n24
te[2] = n31
te[6] = n32
te[10] = n33
te[14] = n34
te[3] = n41
te[7] = n42
te[11] = n43
te[15] = n44
return &m
}
// Identity :
func (m Matrix4) Identity() *Matrix4 {
m.Set(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
)
return &m
}
// Clone :
func (m Matrix4) Clone() *Matrix4 {
array := make([]float64, 0)
for _, elem := range m.Elements {
array = append(array, elem)
}
return NewMatrix4().FromArray(array, 0)
}
// Copy :
func (m Matrix4) Copy(n Matrix4) *Matrix4 {
te := m.Elements
me := n.Elements
te[0] = me[0]
te[1] = me[1]
te[2] = me[2]
te[3] = me[3]
te[4] = me[4]
te[5] = me[5]
te[6] = me[6]
te[7] = me[7]
te[8] = me[8]
te[9] = me[9]
te[10] = me[10]
te[11] = me[11]
te[12] = me[12]
te[13] = me[13]
te[14] = me[14]
te[15] = me[15]
return &m
}
// CopyPosition :
func (m Matrix4) CopyPosition(n Matrix4) *Matrix4 {
te, me := m.Elements, n.Elements
te[12] = me[12]
te[13] = me[13]
te[14] = me[14]
return &m
}
// ExtractBasis :
func (m Matrix4) ExtractBasis(xAxis, yAxis, zAxis Vector3) *Matrix4 {
xAxis.SetFromMatrixColumn(m, 0)
yAxis.SetFromMatrixColumn(m, 1)
zAxis.SetFromMatrixColumn(m, 2)
return &m
}
// MakeBasis :
func (m Matrix4) MakeBasis(xAxis, yAxis, zAxis Vector3) *Matrix4 {
m.Set(
xAxis.X, yAxis.X, zAxis.X, 0,
xAxis.Y, yAxis.Y, zAxis.Y, 0,
xAxis.Z, yAxis.Z, zAxis.Z, 0,
0, 0, 0, 1,
)
return &m
}
// ExtractRotation :
func (m Matrix4) ExtractRotation(n Matrix4) *Matrix4 {
// m method does not support reflection matrices
te := m.Elements
me := n.Elements
scaleX := 1 / _v1Matrix4.SetFromMatrixColumn(n, 0).Length()
scaleY := 1 / _v1Matrix4.SetFromMatrixColumn(n, 1).Length()
scaleZ := 1 / _v1Matrix4.SetFromMatrixColumn(n, 2).Length()
te[0] = me[0] * scaleX
te[1] = me[1] * scaleX
te[2] = me[2] * scaleX
te[3] = 0
te[4] = me[4] * scaleY
te[5] = me[5] * scaleY
te[6] = me[6] * scaleY
te[7] = 0
te[8] = me[8] * scaleZ
te[9] = me[9] * scaleZ
te[10] = me[10] * scaleZ
te[11] = 0
te[12] = 0
te[13] = 0
te[14] = 0
te[15] = 1
return &m
}
// MakeRotationFromEuler :
func (m Matrix4) MakeRotationFromEuler(euler Euler) *Matrix4 {
te := m.Elements
x, y, z := euler.X(), euler.Y(), euler.Z()
a, b := math.Cos(x), math.Sin(x)
c, d := math.Cos(y), math.Sin(y)
e, f := math.Cos(z), math.Sin(z)
if euler._order == "XYZ" {
ae, af, be, bf := a*e, a*f, b*e, b*f
te[0] = c * e
te[4] = -c * f
te[8] = d
te[1] = af + be*d
te[5] = ae - bf*d
te[9] = -b * c
te[2] = bf - ae*d
te[6] = be + af*d
te[10] = a * c
} else if euler._order == "YXZ" {
ce, cf, de, df := c*e, c*f, d*e, d*f
te[0] = ce + df*b
te[4] = de*b - cf
te[8] = a * d
te[1] = a * f
te[5] = a * e
te[9] = -b
te[2] = cf*b - de
te[6] = df + ce*b
te[10] = a * c
} else if euler._order == "ZXY" {
ce, cf, de, df := c*e, c*f, d*e, d*f
te[0] = ce - df*b
te[4] = -a * f
te[8] = de + cf*b
te[1] = cf + de*b
te[5] = a * e
te[9] = df - ce*b
te[2] = -a * d
te[6] = b
te[10] = a * c
} else if euler._order == "ZYX" {
ae, af, be, bf := a*e, a*f, b*e, b*f
te[0] = c * e
te[4] = be*d - af
te[8] = ae*d + bf
te[1] = c * f
te[5] = bf*d + ae
te[9] = af*d - be
te[2] = -d
te[6] = b * c
te[10] = a * c
} else if euler._order == "YZX" {
ac, ad, bc, bd := a*c, a*d, b*c, b*d
te[0] = c * e
te[4] = bd - ac*f
te[8] = bc*f + ad
te[1] = f
te[5] = a * e
te[9] = -b * e
te[2] = -d * e
te[6] = ad*f + bc
te[10] = ac - bd*f
} else if euler._order == "XZY" {
ac, ad, bc, bd := a*c, a*d, b*c, b*d
te[0] = c * e
te[4] = -f
te[8] = d * e
te[1] = ac*f + bd
te[5] = a * e
te[9] = ad*f - bc
te[2] = bc*f - ad
te[6] = b * e
te[10] = bd*f + ac
}
// bottom row
te[3] = 0
te[7] = 0
te[11] = 0
// last column
te[12] = 0
te[13] = 0
te[14] = 0
te[15] = 1
return &m
}
// MakeRotationFromQuaternion :
func (m Matrix4) MakeRotationFromQuaternion(q Quaternion) *Matrix4 {
return m.Compose(*_zero, q, *_one)
}
// LookAt :
func (m Matrix4) LookAt(eye, target, up Vector3) *Matrix4 {
te := m.Elements
_z.SubVectors(eye, target)
if _z.LengthSq() == 0 {
// eye and target are in the same position
_z.Z = 1
}
_z.Normalize()
_x.CrossVectors(up, *_z)
if _x.LengthSq() == 0 {
// up and z are parallel
if math.Abs(up.Z) == 1 {
_z.X += 0.0001
} else {
_z.Z += 0.0001
}
_z.Normalize()
_x.CrossVectors(up, *_z)
}
_x.Normalize()
_y.CrossVectors(*_z, *_x)
te[0] = _x.X
te[4] = _y.X
te[8] = _z.X
te[1] = _x.Y
te[5] = _y.Y
te[9] = _z.Y
te[2] = _x.Z
te[6] = _y.Z
te[10] = _z.Z
return &m
}
// Multiply :
func (m Matrix4) Multiply(n Matrix4) *Matrix4 {
return m.MultiplyMatrices(m, n)
}
// Premultiply :
func (m Matrix4) Premultiply(n Matrix4) *Matrix4 {
return m.MultiplyMatrices(n, m)
}
// MultiplyMatrices :
func (m Matrix4) MultiplyMatrices(a, b Matrix4) *Matrix4 {
ae := a.Elements
be := b.Elements
te := m.Elements
a11, a12, a13, a14 := ae[0], ae[4], ae[8], ae[12]
a21, a22, a23, a24 := ae[1], ae[5], ae[9], ae[13]
a31, a32, a33, a34 := ae[2], ae[6], ae[10], ae[14]
a41, a42, a43, a44 := ae[3], ae[7], ae[11], ae[15]
b11, b12, b13, b14 := be[0], be[4], be[8], be[12]
b21, b22, b23, b24 := be[1], be[5], be[9], be[13]
b31, b32, b33, b34 := be[2], be[6], be[10], be[14]
b41, b42, b43, b44 := be[3], be[7], be[11], be[15]
te[0] = a11*b11 + a12*b21 + a13*b31 + a14*b41
te[4] = a11*b12 + a12*b22 + a13*b32 + a14*b42
te[8] = a11*b13 + a12*b23 + a13*b33 + a14*b43
te[12] = a11*b14 + a12*b24 + a13*b34 + a14*b44
te[1] = a21*b11 + a22*b21 + a23*b31 + a24*b41
te[5] = a21*b12 + a22*b22 + a23*b32 + a24*b42
te[9] = a21*b13 + a22*b23 + a23*b33 + a24*b43
te[13] = a21*b14 + a22*b24 + a23*b34 + a24*b44
te[2] = a31*b11 + a32*b21 + a33*b31 + a34*b41
te[6] = a31*b12 + a32*b22 + a33*b32 + a34*b42
te[10] = a31*b13 + a32*b23 + a33*b33 + a34*b43
te[14] = a31*b14 + a32*b24 + a33*b34 + a34*b44
te[3] = a41*b11 + a42*b21 + a43*b31 + a44*b41
te[7] = a41*b12 + a42*b22 + a43*b32 + a44*b42
te[11] = a41*b13 + a42*b23 + a43*b33 + a44*b43
te[15] = a41*b14 + a42*b24 + a43*b34 + a44*b44
return &m
}
// MultiplyScalar :
func (m Matrix4) MultiplyScalar(s float64) *Matrix4 {
te := m.Elements
te[0] *= s
te[4] *= s
te[8] *= s
te[12] *= s
te[1] *= s
te[5] *= s
te[9] *= s
te[13] *= s
te[2] *= s
te[6] *= s
te[10] *= s
te[14] *= s
te[3] *= s
te[7] *= s
te[11] *= s
te[15] *= s
return &m
}
// Determinant :
func (m Matrix4) Determinant() float64 {
te := m.Elements
n11, n12, n13, n14 := te[0], te[4], te[8], te[12]
n21, n22, n23, n24 := te[1], te[5], te[9], te[13]
n31, n32, n33, n34 := te[2], te[6], te[10], te[14]
n41, n42, n43, n44 := te[3], te[7], te[11], te[15]
//TODO: make m more efficient
//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
return (n41*(n14*n23*n32-
n13*n24*n32-
n14*n22*n33+
n12*n24*n33+
n13*n22*n34-
n12*n23*n34) +
n42*(n11*n23*n34-
n11*n24*n33+
n14*n21*n33-
n13*n21*n34+
n13*n24*n31-
n14*n23*n31) +
n43*(n11*n24*n32-
n11*n22*n34-
n14*n21*n32+
n12*n21*n34+
n14*n22*n31-
n12*n24*n31) +
n44*(-n13*n22*n31-
n11*n23*n32+
n11*n22*n33+
n13*n21*n32-
n12*n21*n33+
n12*n23*n31))
}
// Transpose :
func (m Matrix4) Transpose() *Matrix4 {
te := m.Elements
var tmp float64
tmp = te[1]
te[1] = te[4]
te[4] = tmp
tmp = te[2]
te[2] = te[8]
te[8] = tmp
tmp = te[6]
te[6] = te[9]
te[9] = tmp
tmp = te[3]
te[3] = te[12]
te[12] = tmp
tmp = te[7]
te[7] = te[13]
te[13] = tmp
tmp = te[11]
te[11] = te[14]
te[14] = tmp
return &m
}
// SetPosition :
func (m Matrix4) SetPosition(x, y, z float64) *Matrix4 {
te := m.Elements
te[12] = x
te[13] = y
te[14] = z
return &m
}
// GetInverse :
func (m Matrix4) GetInverse(n Matrix4) *Matrix4 {
// based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
te := m.Elements
me := n.Elements
n11, n21, n31, n41 := me[0], me[1], me[2], me[3]
n12, n22, n32, n42 := me[4], me[5], me[6], me[7]
n13, n23, n33, n43 := me[8], me[9], me[10], me[11]
n14, n24, n34, n44 := me[12], me[13], me[14], me[15]
t11 := n23*n34*n42 - n24*n33*n42 + n24*n32*n43 - n22*n34*n43 - n23*n32*n44 + n22*n33*n44
t12 := n14*n33*n42 - n13*n34*n42 - n14*n32*n43 + n12*n34*n43 + n13*n32*n44 - n12*n33*n44
t13 := n13*n24*n42 - n14*n23*n42 + n14*n22*n43 - n12*n24*n43 - n13*n22*n44 + n12*n23*n44
t14 := n14*n23*n32 - n13*n24*n32 - n14*n22*n33 + n12*n24*n33 + n13*n22*n34 - n12*n23*n34
det := n11*t11 + n21*t12 + n31*t13 + n41*t14
if det == 0 {
return m.Set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
}
detInv := 1 / det
te[0] = t11 * detInv
te[1] = (n24*n33*n41 - n23*n34*n41 - n24*n31*n43 + n21*n34*n43 + n23*n31*n44 - n21*n33*n44) * detInv
te[2] = (n22*n34*n41 - n24*n32*n41 + n24*n31*n42 - n21*n34*n42 - n22*n31*n44 + n21*n32*n44) * detInv
te[3] = (n23*n32*n41 - n22*n33*n41 - n23*n31*n42 + n21*n33*n42 + n22*n31*n43 - n21*n32*n43) * detInv
te[4] = t12 * detInv
te[5] = (n13*n34*n41 - n14*n33*n41 + n14*n31*n43 - n11*n34*n43 - n13*n31*n44 + n11*n33*n44) * detInv
te[6] = (n14*n32*n41 - n12*n34*n41 - n14*n31*n42 + n11*n34*n42 + n12*n31*n44 - n11*n32*n44) * detInv
te[7] = (n12*n33*n41 - n13*n32*n41 + n13*n31*n42 - n11*n33*n42 - n12*n31*n43 + n11*n32*n43) * detInv
te[8] = t13 * detInv
te[9] = (n14*n23*n41 - n13*n24*n41 - n14*n21*n43 + n11*n24*n43 + n13*n21*n44 - n11*n23*n44) * detInv
te[10] = (n12*n24*n41 - n14*n22*n41 + n14*n21*n42 - n11*n24*n42 - n12*n21*n44 + n11*n22*n44) * detInv
te[11] = (n13*n22*n41 - n12*n23*n41 - n13*n21*n42 + n11*n23*n42 + n12*n21*n43 - n11*n22*n43) * detInv
te[12] = t14 * detInv
te[13] = (n13*n24*n31 - n14*n23*n31 + n14*n21*n33 - n11*n24*n33 - n13*n21*n34 + n11*n23*n34) * detInv
te[14] = (n14*n22*n31 - n12*n24*n31 - n14*n21*n32 + n11*n24*n32 + n12*n21*n34 - n11*n22*n34) * detInv
te[15] = (n12*n23*n31 - n13*n22*n31 + n13*n21*n32 - n11*n23*n32 - n12*n21*n33 + n11*n22*n33) * detInv
return &m
}
// Scale :
func (m Matrix4) Scale(v Vector3) *Matrix4 {
te := m.Elements
x, y, z := v.X, v.Y, v.Z
te[0] *= x
te[4] *= y
te[8] *= z
te[1] *= x
te[5] *= y
te[9] *= z
te[2] *= x
te[6] *= y
te[10] *= z
te[3] *= x
te[7] *= y
te[11] *= z
return &m
}
// GetMaxScaleOnAxis :
func (m Matrix4) GetMaxScaleOnAxis() float64 {
te := m.Elements
scaleXSq := te[0]*te[0] + te[1]*te[1] + te[2]*te[2]
scaleYSq := te[4]*te[4] + te[5]*te[5] + te[6]*te[6]
scaleZSq := te[8]*te[8] + te[9]*te[9] + te[10]*te[10]
return math.Sqrt(math.Max(math.Max(scaleXSq, scaleYSq), scaleZSq))
}
// MakeTranslation :
func (m Matrix4) MakeTranslation(x, y, z float64) *Matrix4 {
m.Set(
1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, z,
0, 0, 0, 1,
)
return &m
}
// MakeRotationX :
func (m Matrix4) MakeRotationX(theta float64) *Matrix4 {
c, s := math.Cos(theta), math.Sin(theta)
m.Set(
1, 0, 0, 0,
0, c, -s, 0,
0, s, c, 0,
0, 0, 0, 1,
)
return &m
}
// MakeRotationY :
func (m Matrix4) MakeRotationY(theta float64) *Matrix4 {
c, s := math.Cos(theta), math.Sin(theta)
m.Set(
c, 0, s, 0,
0, 1, 0, 0,
-s, 0, c, 0,
0, 0, 0, 1,
)
return &m
}
// MakeRotationZ :
func (m Matrix4) MakeRotationZ(theta float64) *Matrix4 {
c, s := math.Cos(theta), math.Sin(theta)
m.Set(
c, -s, 0, 0,
s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
)
return &m
}
// MakeRotationAxis :
func (m Matrix4) MakeRotationAxis(axis Vector3, angle float64) *Matrix4 {
// Based on http://www.gamedev.net/reference/articles/article1199.asp
c := math.Cos(angle)
s := math.Sin(angle)
t := 1 - c
x, y, z := axis.X, axis.Y, axis.Z
tx, ty := t*x, t*y
m.Set(
tx*x+c, tx*y-s*z, tx*z+s*y, 0,
tx*y+s*z, ty*y+c, ty*z-s*x, 0,
tx*z-s*y, ty*z+s*x, t*z*z+c, 0,
0, 0, 0, 1,
)
return &m
}
// MakeScale :
func (m Matrix4) MakeScale(x, y, z float64) *Matrix4 {
m.Set(
x, 0, 0, 0,
0, y, 0, 0,
0, 0, z, 0,
0, 0, 0, 1,
)
return &m
}
// MakeShear :
func (m Matrix4) MakeShear(x, y, z float64) *Matrix4 {
m.Set(
1, y, z, 0,
x, 1, z, 0,
x, y, 1, 0,
0, 0, 0, 1,
)
return &m
}
// Compose :
func (m Matrix4) Compose(position Vector3, quaternion Quaternion, scale Vector3) *Matrix4 {
te := m.Elements
x, y, z, w := quaternion._x, quaternion._y, quaternion._z, quaternion._w
x2, y2, z2 := x+x, y+y, z+z
xx, xy, xz := x*x2, x*y2, x*z2
yy, yz, zz := y*y2, y*z2, z*z2
wx, wy, wz := w*x2, w*y2, w*z2
sx, sy, sz := scale.X, scale.Y, scale.Z
te[0] = (1 - (yy + zz)) * sx
te[1] = (xy + wz) * sx
te[2] = (xz - wy) * sx
te[3] = 0
te[4] = (xy - wz) * sy
te[5] = (1 - (xx + zz)) * sy
te[6] = (yz + wx) * sy
te[7] = 0
te[8] = (xz + wy) * sz
te[9] = (yz - wx) * sz
te[10] = (1 - (xx + yy)) * sz
te[11] = 0
te[12] = position.X
te[13] = position.Y
te[14] = position.Z
te[15] = 1
return &m
}
// Decompose :
func (m Matrix4) Decompose(position Vector3, quaternion Quaternion, scale Vector3) *Matrix4 {
te := m.Elements
sx := _v1Matrix4.Set(te[0], te[1], te[2]).Length()
sy := _v1Matrix4.Set(te[4], te[5], te[6]).Length()
sz := _v1Matrix4.Set(te[8], te[9], te[10]).Length()
// if determine is negative, we need to invert one scale
det := m.Determinant()
if det < 0 {
sx = -sx
}
position.X = te[12]
position.Y = te[13]
position.Z = te[14]
// scale the rotation part
_m1.Copy(m)
invSX := 1 / sx
invSY := 1 / sy
invSZ := 1 / sz
_m1.Elements[0] *= invSX
_m1.Elements[1] *= invSX
_m1.Elements[2] *= invSX
_m1.Elements[4] *= invSY
_m1.Elements[5] *= invSY
_m1.Elements[6] *= invSY
_m1.Elements[8] *= invSZ
_m1.Elements[9] *= invSZ
_m1.Elements[10] *= invSZ
quaternion.SetFromRotationMatrix(*_m1)
scale.X = sx
scale.Y = sy
scale.Z = sz
return &m
}
// MakePerspective :
func (m Matrix4) MakePerspective(left, right, top, bottom, near, far float64) *Matrix4 {
te := m.Elements
x := 2 * near / (right - left)
y := 2 * near / (top - bottom)
a := (right + left) / (right - left)
b := (top + bottom) / (top - bottom)
c := -(far + near) / (far - near)
d := -2 * far * near / (far - near)
te[0] = x
te[4] = 0
te[8] = a
te[12] = 0
te[1] = 0
te[5] = y
te[9] = b
te[13] = 0
te[2] = 0
te[6] = 0
te[10] = c
te[14] = d
te[3] = 0
te[7] = 0
te[11] = -1
te[15] = 0
return &m
}
// MakeOrthographic :
func (m Matrix4) MakeOrthographic(left, right, top, bottom, near, far float64) *Matrix4 {
te := m.Elements
w := 1.0 / (right - left)
h := 1.0 / (top - bottom)
p := 1.0 / (far - near)
x := (right + left) * w
y := (top + bottom) * h
z := (far + near) * p
te[0] = 2 * w
te[4] = 0
te[8] = 0
te[12] = -x
te[1] = 0
te[5] = 2 * h
te[9] = 0
te[13] = -y
te[2] = 0
te[6] = 0
te[10] = -2 * p
te[14] = -z
te[3] = 0
te[7] = 0
te[11] = 0
te[15] = 1
return &m
}
// Equals :
func (m Matrix4) Equals(matrix Matrix4) bool {
te := m.Elements
me := matrix.Elements
for i := 0; i < 16; i++ {
if te[i] != me[i] {
return false
}
}
return true
}
// FromArray :
func (m Matrix4) FromArray(array []float64, offset int) *Matrix4 {
if len(array) < offset+16 {
panic("array length should be greater than offset+16")
}
for i := 0; i < 16; i++ {
m.Elements[i] = array[i+offset]
}
return &m
}
// ToArray :
func (m Matrix4) ToArray(array []float64, offset int) []float64 {
if len(array) < offset+16 {
panic("array length should be greater than offset+16")
}
te := m.Elements
array[offset] = te[0]
array[offset+1] = te[1]
array[offset+2] = te[2]
array[offset+3] = te[3]
array[offset+4] = te[4]
array[offset+5] = te[5]
array[offset+6] = te[6]
array[offset+7] = te[7]
array[offset+8] = te[8]
array[offset+9] = te[9]
array[offset+10] = te[10]
array[offset+11] = te[11]
array[offset+12] = te[12]
array[offset+13] = te[13]
array[offset+14] = te[14]
array[offset+15] = te[15]
return array
}