github.com/xlab/linmath@v0.0.0-20220922225318-40b6290c3b40/linmath.go (about)

     1  package linmath
     2  
     3  type Mat4x4 [4]Vec4
     4  
     5  func (m *Mat4x4) Fill(d float32) {
     6  	for i := 0; i < 4; i++ {
     7  		for j := 0; j < 4; j++ {
     8  			m[i][j] = d
     9  		}
    10  	}
    11  }
    12  
    13  func (m *Mat4x4) Identity() {
    14  	for i := 0; i < 4; i++ {
    15  		for j := 0; j < 4; j++ {
    16  			if i == j {
    17  				m[i][j] = 1
    18  			} else {
    19  				m[i][j] = 0
    20  			}
    21  		}
    22  	}
    23  }
    24  
    25  func (m *Mat4x4) Dup(n *Mat4x4) {
    26  	for i := 0; i < 4; i++ {
    27  		for j := 0; j < 4; j++ {
    28  			m[i][j] = n[i][j]
    29  		}
    30  	}
    31  }
    32  
    33  func (r *Vec4) Mat4x4Row(m *Mat4x4, i int) {
    34  	for k := 0; k < 4; k++ {
    35  		r[k] = m[k][i]
    36  	}
    37  }
    38  
    39  func (r *Vec4) Mat4x4Col(m *Mat4x4, i int) {
    40  	for k := 0; k < 4; k++ {
    41  		r[k] = m[i][k]
    42  	}
    43  }
    44  
    45  func (m *Mat4x4) Transpose(n *Mat4x4) {
    46  	for i := 0; i < 4; i++ {
    47  		for j := 0; j < 4; j++ {
    48  			m[i][j] = n[j][i]
    49  		}
    50  	}
    51  }
    52  
    53  func (m *Mat4x4) Add(a, b *Mat4x4) {
    54  	for i := 0; i < 4; i++ {
    55  		m[i].Add(&a[i], &b[i])
    56  	}
    57  }
    58  
    59  func (m *Mat4x4) Sub(a, b *Mat4x4) {
    60  	for i := 0; i < 4; i++ {
    61  		m[i].Sub(&a[i], &b[i])
    62  	}
    63  }
    64  
    65  func (m *Mat4x4) Scale(a *Mat4x4, k float32) {
    66  	for i := 0; i < 4; i++ {
    67  		m[i].Scale(&a[i], k)
    68  	}
    69  }
    70  
    71  func (m *Mat4x4) ScaleAniso(a *Mat4x4, x, y, z float32) {
    72  	m[0].Scale(&a[0], x)
    73  	m[1].Scale(&a[1], y)
    74  	m[2].Scale(&a[2], z)
    75  	for i := 0; i < 4; i++ {
    76  		m[3][i] = a[3][i]
    77  	}
    78  }
    79  
    80  func (m *Mat4x4) Mult(a, b *Mat4x4) {
    81  	var temp = new(Mat4x4)
    82  
    83  	for c := 0; c < 4; c++ {
    84  		for r := 0; r < 4; r++ {
    85  			temp[c][r] = 0
    86  			for k := 0; k < 4; k++ {
    87  				temp[c][r] += a[k][r] * b[c][k]
    88  			}
    89  		}
    90  	}
    91  
    92  	m.Dup(temp)
    93  }
    94  
    95  func (r *Vec4) Mat4x4MultVec4(m *Mat4x4, v Vec4) {
    96  	for j := 0; j < 4; j++ {
    97  		r[j] = 0
    98  		for i := 0; i < 4; i++ {
    99  			r[j] += m[i][j] * v[i]
   100  		}
   101  	}
   102  }
   103  
   104  func (m *Mat4x4) Translate(x, y, z float32) {
   105  	m.Identity()
   106  	m[3][0] = x
   107  	m[3][1] = y
   108  	m[3][2] = z
   109  }
   110  
   111  func (m *Mat4x4) TranslateInPlace(x, y, z float32) {
   112  	var t = &Vec4{x, y, z, 0}
   113  	var r = new(Vec4)
   114  	for i := 0; i < 4; i++ {
   115  		r.Mat4x4Row(m, i)
   116  		m[3][i] += Vec4MultInner(r, t)
   117  	}
   118  }
   119  
   120  func (m *Mat4x4) FromVec3MultOuter(a, b *Vec3) {
   121  	for i := 0; i < 4; i++ {
   122  		for j := 0; j < 4; j++ {
   123  			if i < 3 && j < 3 {
   124  				m[i][j] = a[i] * b[j]
   125  			} else {
   126  				m[i][j] = 0
   127  			}
   128  		}
   129  	}
   130  }
   131  
   132  func (r *Mat4x4) Rotate(m *Mat4x4, x, y, z, angle float32) {
   133  	var s = sinf(angle)
   134  	var c = cosf(angle)
   135  	var u = &Vec3{x, y, z}
   136  
   137  	if u.Len() > 1e-4 {
   138  		u.Norm(u)
   139  		var T = new(Mat4x4)
   140  		T.FromVec3MultOuter(u, u)
   141  
   142  		var S = &Mat4x4{
   143  			{0, u[2], -u[1], 0},
   144  			{-u[2], 0, u[0], 0},
   145  			{u[1], -u[0], 0, 0},
   146  			{0, 0, 0, 0},
   147  		}
   148  		S.Scale(S, s)
   149  
   150  		var C = new(Mat4x4)
   151  		C.Identity()
   152  		C.Sub(C, T)
   153  
   154  		C.Scale(C, c)
   155  
   156  		T.Add(T, C)
   157  		T.Add(T, S)
   158  
   159  		T[3][3] = 1
   160  		r.Mult(m, T)
   161  	} else {
   162  		r.Dup(m)
   163  	}
   164  }
   165  
   166  func (q *Mat4x4) RotateX(m *Mat4x4, angle float32) {
   167  	var s = sinf(angle)
   168  	var c = cosf(angle)
   169  	var R = &Mat4x4{
   170  		{1, 0, 0, 0},
   171  		{0, c, s, 0},
   172  		{0, -s, c, 0},
   173  		{0, 0, 0, 1},
   174  	}
   175  	q.Mult(m, R)
   176  }
   177  
   178  func (q *Mat4x4) RotateY(m *Mat4x4, angle float32) {
   179  	var s = sinf(angle)
   180  	var c = cosf(angle)
   181  	var R = &Mat4x4{
   182  		{c, 0, s, 0},
   183  		{0, 1, 0, 0},
   184  		{-s, 0, c, 0},
   185  		{0, 0, 0, 1},
   186  	}
   187  	q.Mult(m, R)
   188  }
   189  
   190  func (q *Mat4x4) RotateZ(m *Mat4x4, angle float32) {
   191  	var s = sinf(angle)
   192  	var c = cosf(angle)
   193  	var R = &Mat4x4{
   194  		{c, s, 0, 0},
   195  		{-s, c, 0, 0},
   196  		{0, 0, 1, 0},
   197  		{0, 0, 0, 1},
   198  	}
   199  	q.Mult(m, R)
   200  }
   201  
   202  func (t *Mat4x4) Invert(m *Mat4x4) {
   203  	var s = new([6]float32)
   204  	s[0] = m[0][0]*m[1][1] - m[1][0]*m[0][1]
   205  	s[1] = m[0][0]*m[1][2] - m[1][0]*m[0][2]
   206  	s[2] = m[0][0]*m[1][3] - m[1][0]*m[0][3]
   207  	s[3] = m[0][1]*m[1][2] - m[1][1]*m[0][2]
   208  	s[4] = m[0][1]*m[1][3] - m[1][1]*m[0][3]
   209  	s[5] = m[0][2]*m[1][3] - m[1][2]*m[0][3]
   210  
   211  	var c = new([6]float32)
   212  	c[0] = m[2][0]*m[3][1] - m[3][0]*m[2][1]
   213  	c[1] = m[2][0]*m[3][2] - m[3][0]*m[2][2]
   214  	c[2] = m[2][0]*m[3][3] - m[3][0]*m[2][3]
   215  	c[3] = m[2][1]*m[3][2] - m[3][1]*m[2][2]
   216  	c[4] = m[2][1]*m[3][3] - m[3][1]*m[2][3]
   217  	c[5] = m[2][2]*m[3][3] - m[3][2]*m[2][3]
   218  
   219  	// Assumes it is invertible
   220  	var idet float32 = 1.0 / (s[0]*c[5] - s[1]*c[4] + s[2]*c[3] + s[3]*c[2] - s[4]*c[1] + s[5]*c[0])
   221  
   222  	t[0][0] = (m[1][1]*c[5] - m[1][2]*c[4] + m[1][3]*c[3]) * idet
   223  	t[0][1] = (-m[0][1]*c[5] + m[0][2]*c[4] - m[0][3]*c[3]) * idet
   224  	t[0][2] = (m[3][1]*s[5] - m[3][2]*s[4] + m[3][3]*s[3]) * idet
   225  	t[0][3] = (-m[2][1]*s[5] + m[2][2]*s[4] - m[2][3]*s[3]) * idet
   226  
   227  	t[1][0] = (-m[1][0]*c[5] + m[1][2]*c[2] - m[1][3]*c[1]) * idet
   228  	t[1][1] = (m[0][0]*c[5] - m[0][2]*c[2] + m[0][3]*c[1]) * idet
   229  	t[1][2] = (-m[3][0]*s[5] + m[3][2]*s[2] - m[3][3]*s[1]) * idet
   230  	t[1][3] = (m[2][0]*s[5] - m[2][2]*s[2] + m[2][3]*s[1]) * idet
   231  	t[2][0] = (m[1][0]*c[4] - m[1][1]*c[2] + m[1][3]*c[0]) * idet
   232  	t[2][1] = (-m[0][0]*c[4] + m[0][1]*c[2] - m[0][3]*c[0]) * idet
   233  	t[2][2] = (m[3][0]*s[4] - m[3][1]*s[2] + m[3][3]*s[0]) * idet
   234  	t[2][3] = (-m[2][0]*s[4] + m[2][1]*s[2] - m[2][3]*s[0]) * idet
   235  
   236  	t[3][0] = (-m[1][0]*c[3] + m[1][1]*c[1] - m[1][2]*c[0]) * idet
   237  	t[3][1] = (m[0][0]*c[3] - m[0][1]*c[1] + m[0][2]*c[0]) * idet
   238  	t[3][2] = (-m[3][0]*s[3] + m[3][1]*s[1] - m[3][2]*s[0]) * idet
   239  	t[3][3] = (m[2][0]*s[3] - m[2][1]*s[1] + m[2][2]*s[0]) * idet
   240  }
   241  
   242  func (r *Mat4x4) OrthoNormalize(m *Mat4x4) {
   243  	r.Dup(m)
   244  	var s float32
   245  	var h = new(Vec3)
   246  	r[2].Norm(&r[2])
   247  
   248  	s = Vec4MultInner3(&r[1], &r[2])
   249  	h.ScaleVec4(&r[2], s)
   250  	r[1].SubVec3(&r[1], h)
   251  	r[2].Norm(&r[2])
   252  
   253  	s = Vec4MultInner3(&r[1], &r[2])
   254  	h.ScaleVec4(&r[2], s)
   255  	r[1].SubVec3(&r[1], h)
   256  	r[1].Norm(&r[1])
   257  
   258  	s = Vec4MultInner3(&r[0], &r[1])
   259  	h.ScaleVec4(&r[1], s)
   260  	r[0].SubVec3(&r[0], h)
   261  	r[0].Norm(&r[0])
   262  }
   263  
   264  func (m *Mat4x4) Frustum(l, r, b, t, n, f float32) {
   265  	m[0][0] = 2 * n / (r - l)
   266  	m[0][1] = 0
   267  	m[0][2] = 0
   268  	m[0][3] = 0
   269  
   270  	m[1][1] = 2 * n / (t - b)
   271  	m[1][0] = 0
   272  	m[1][2] = 0
   273  	m[1][3] = 0
   274  
   275  	m[2][0] = (r + l) / (r - l)
   276  	m[2][1] = (t + b) / (t - b)
   277  	m[2][2] = -(f + n) / (f - n)
   278  	m[2][3] = -1
   279  
   280  	m[3][2] = -2 * (f * n) / (f - n)
   281  	m[3][0] = 0
   282  	m[3][1] = 0
   283  	m[3][3] = 0
   284  }
   285  
   286  func (m *Mat4x4) Ortho(l, r, b, t, n, f float32) {
   287  	m[0][0] = 2 / (r - l)
   288  	m[0][1] = 0
   289  	m[0][2] = 0
   290  	m[0][3] = 0
   291  
   292  	m[1][1] = 2 / (t - b)
   293  	m[1][0] = 0
   294  	m[1][2] = 0
   295  	m[1][3] = 0
   296  
   297  	m[2][2] = -2 / (f - n)
   298  	m[2][0] = 0
   299  	m[2][1] = 0
   300  	m[2][3] = 0
   301  
   302  	m[3][0] = -(r + l) / (r - l)
   303  	m[3][1] = -(t + b) / (t - b)
   304  	m[3][2] = -(f + n) / (f - n)
   305  	m[3][3] = 1
   306  }
   307  
   308  func (m *Mat4x4) Perspective(y_fov, aspect, n, f float32) {
   309  	// NOTE: Degrees are an unhandy unit to work with.
   310  	// linmath.go uses radians for everything!
   311  	var a float32 = 1 / tanf(y_fov/2)
   312  
   313  	m[0][0] = a / aspect
   314  	m[0][1] = 0
   315  	m[0][2] = 0
   316  	m[0][3] = 0
   317  
   318  	m[1][0] = 0
   319  	m[1][1] = a
   320  	m[1][2] = 0
   321  	m[1][3] = 0
   322  
   323  	m[2][0] = 0
   324  	m[2][1] = 0
   325  	m[2][2] = -((f + n) / (f - n))
   326  	m[2][3] = -1
   327  
   328  	m[3][0] = 0
   329  	m[3][1] = 0
   330  	m[3][2] = -((2 * f * n) / (f - n))
   331  	m[3][3] = 0
   332  }
   333  
   334  func (m *Mat4x4) LookAt(eye, center, up *Vec3) {
   335  	// Adapted from Android's OpenGL Matrix.java.
   336  	// See the OpenGL GLUT documentation for gluLookAt for a description
   337  	// of the algorithm. We implement it in a straightforward way:
   338  	//
   339  	// TODO: The negation of of can be spared by swapping the order of
   340  	//       operands in the following cross products in the right way.
   341  	var f = new(Vec3)
   342  	f.Sub(center, eye)
   343  	f.Norm(f)
   344  
   345  	var s = new(Vec3)
   346  	s.MultCross(f, up)
   347  	s.Norm(s)
   348  
   349  	var t = new(Vec3)
   350  	t.MultCross(s, f)
   351  
   352  	m[0][0] = s[0]
   353  	m[0][1] = t[0]
   354  	m[0][2] = -f[0]
   355  	m[0][3] = 0
   356  
   357  	m[1][0] = s[1]
   358  	m[1][1] = t[1]
   359  	m[1][2] = -f[1]
   360  	m[1][3] = 0
   361  
   362  	m[2][0] = s[2]
   363  	m[2][1] = t[2]
   364  	m[2][2] = -f[2]
   365  	m[2][3] = 0
   366  
   367  	m[3][0] = 0
   368  	m[3][1] = 0
   369  	m[3][2] = 0
   370  	m[3][3] = 1
   371  
   372  	m.TranslateInPlace(-eye[0], -eye[1], -eye[2])
   373  }
   374  
   375  func (r *Vec3) QuatMultVec3(q *Quat, v *Vec3) {
   376  	// Method by Fabian 'ryg' Giessen (of Farbrausch)
   377  	//   t = 2 * cross(q.xyz, v)
   378  	//   v' = v + q.w * t + cross(q.xyz, t)
   379  	var t = new(Vec3)
   380  	var q_xyz = &Vec3{q[0], q[1], q[2]}
   381  	var u = &Vec3{q[0], q[1], q[2]}
   382  
   383  	t.MultCross(q_xyz, v)
   384  	t.Scale(t, 2)
   385  
   386  	u.MultCross(q_xyz, t)
   387  	t.Scale(t, q[3])
   388  
   389  	r.Add(v, t)
   390  	r.Add(r, u)
   391  }
   392  
   393  func (r *Vec4) QuatMultVec4(q *Quat, v *Vec4) {
   394  	// Method by Fabian 'ryg' Giessen (of Farbrausch)
   395  	//   t = 2 * cross(q.xyz, v)
   396  	//   v' = v + q.w * t + cross(q.xyz, t)
   397  	var t = new(Vec4)
   398  	var q_xyz = &Vec4{q[0], q[1], q[2]}
   399  	var u = &Vec4{q[0], q[1], q[2]}
   400  
   401  	t.MultCross(q_xyz, v)
   402  	t.Scale(t, 2)
   403  
   404  	u.MultCross(q_xyz, t)
   405  	t.Scale(t, q[3])
   406  
   407  	r.Add(v, t)
   408  	r.Add(r, u)
   409  }
   410  
   411  func (m *Mat4x4) FromQuat(q *Quat) {
   412  	var a float32 = q[3]
   413  	var b float32 = q[0]
   414  	var c float32 = q[1]
   415  	var d float32 = q[2]
   416  	var a2 float32 = a * a
   417  	var b2 float32 = b * b
   418  	var c2 float32 = c * c
   419  	var d2 float32 = d * d
   420  
   421  	m[0][0] = a2 + b2 - c2 - d2
   422  	m[0][1] = 2 * (b*c + a*d)
   423  	m[0][2] = 2 * (b*d - a*c)
   424  	m[0][3] = 0
   425  
   426  	m[1][0] = 2 * (b*c - a*d)
   427  	m[1][1] = a2 - b2 + c2 - d2
   428  	m[1][2] = 2 * (c*d + a*b)
   429  	m[1][3] = 0
   430  
   431  	m[2][0] = 2 * (b*d + a*c)
   432  	m[2][1] = 2 * (c*d - a*b)
   433  	m[2][2] = a2 - b2 - c2 + d2
   434  	m[2][3] = 0
   435  
   436  	m[3][0] = 0
   437  	m[3][1] = 0
   438  	m[3][2] = 0
   439  	m[3][3] = 1
   440  }
   441  
   442  func (r *Mat4x4) MultQuat(m *Mat4x4, q *Quat) {
   443  	// XXX: The way this is written only works for othogonal matrices.
   444  	// TODO: Take care of non-orthogonal case.
   445  	r[0].QuatMultVec4(q, &m[0])
   446  	r[1].QuatMultVec4(q, &m[1])
   447  	r[2].QuatMultVec4(q, &m[2])
   448  
   449  	r[3][0] = 0
   450  	r[3][1] = 0
   451  	r[3][2] = 0
   452  	r[3][3] = 1
   453  }
   454  
   455  func (q *Quat) FromMat4x4(m *Mat4x4) {
   456  	var r float32
   457  	var p = []int{0, 1, 2, 0, 1}
   458  	var idx int
   459  
   460  	for i := 0; i < 3; i++ {
   461  		var m float32 = m[i][i]
   462  		if m < r {
   463  			continue
   464  		}
   465  		m = r
   466  		idx = i
   467  	}
   468  
   469  	p = p[idx:] // reslice p starting from idx
   470  	r = sqrtf(1 + m[p[0]][p[0]] - m[p[1]][p[1]] - m[p[2]][p[2]])
   471  
   472  	if r < 1e-6 {
   473  		q[0] = 1
   474  		q[1] = 0
   475  		q[2] = 0
   476  		q[3] = 0
   477  		return
   478  	}
   479  
   480  	q[0] = r / 2
   481  	q[1] = (m[p[0]][p[1]] - m[p[1]][p[0]]) / (2 * r)
   482  	q[2] = (m[p[2]][p[0]] - m[p[0]][p[2]]) / (2 * r)
   483  	q[3] = (m[p[2]][p[1]] - m[p[1]][p[2]]) / (2 * r)
   484  }