forked from nimsb/Baguette
-
Notifications
You must be signed in to change notification settings - Fork 0
/
matrix.py
327 lines (276 loc) · 12.2 KB
/
matrix.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
'''
All right belong to Grant Laker aka bungnoid
https://github.com/bungnoid/glTools/blob/master/utils/matrix.py
copied in Baguette in june 18 2019
'''
from __future__ import absolute_import
from __future__ import print_function
import maya.cmds as mc
import maya.OpenMaya as OpenMaya
from . import mathUtils
import math
class MissingPluginError(Exception): pass
def getMatrix(transform, local=False, time=None):
'''
@param transform: Transform object to get world matrix from
@type transform: str
@param local: Get local space matrix instead of the world space matrix
@type local: bool
@param time: The frame to get the transforms world matrix for. If left at default, will use the current frame.
@type time: int or float
'''
# Check transform
if not mc.objExists(transform):
raise Exception('Object "' + transform + '" does not exist!!')
# Define Matrix attribute
matAttr = 'worldMatrix[0]'
if local: matAttr = 'matrix'
# Get time
mat = OpenMaya.MMatrix()
if time != None:
mat = mc.getAttr(transform + '.' + matAttr, t=frame)
else:
mat = mc.getAttr(transform + '.' + matAttr)
# Build Matrix
matrix = buildMatrix(translate=(mat[12], mat[13], mat[14]), xAxis=(mat[0], mat[1], mat[2]),
yAxis=(mat[4], mat[5], mat[6]), zAxis=(mat[8], mat[9], mat[10]))
# Return result
return matrix
def buildMatrix(translate=(0, 0, 0), xAxis=(1, 0, 0), yAxis=(0, 1, 0), zAxis=(0, 0, 1)):
'''
Build a transformation matrix based on the input vectors
@param translate: Translate values for the matrix
@type translate: tuple/list
@param xAxis: xAxis of the matrix
@type xAxis: tuple/list
@param yAxis: yAxis of the matrix
@type yAxis: tuple/list
@param zAxis: zAxis of the matrix
@type zAxis: tuple/list
'''
# Create transformation matrix from input vectors
matrix = OpenMaya.MMatrix()
values = []
OpenMaya.MScriptUtil.setDoubleArray(matrix[0], 0, xAxis[0])
OpenMaya.MScriptUtil.setDoubleArray(matrix[0], 1, xAxis[1])
OpenMaya.MScriptUtil.setDoubleArray(matrix[0], 2, xAxis[2])
OpenMaya.MScriptUtil.setDoubleArray(matrix[1], 0, yAxis[0])
OpenMaya.MScriptUtil.setDoubleArray(matrix[1], 1, yAxis[1])
OpenMaya.MScriptUtil.setDoubleArray(matrix[1], 2, yAxis[2])
OpenMaya.MScriptUtil.setDoubleArray(matrix[2], 0, zAxis[0])
OpenMaya.MScriptUtil.setDoubleArray(matrix[2], 1, zAxis[1])
OpenMaya.MScriptUtil.setDoubleArray(matrix[2], 2, zAxis[2])
OpenMaya.MScriptUtil.setDoubleArray(matrix[3], 0, translate[0])
OpenMaya.MScriptUtil.setDoubleArray(matrix[3], 1, translate[1])
OpenMaya.MScriptUtil.setDoubleArray(matrix[3], 2, translate[2])
return matrix
def vectorMatrixMultiply(vector, matrix, transformAsPoint=False, invertMatrix=False):
'''
Transform a vector (or point) by a given transformation matrix.
@param vector: Vector or point to be transformed
@type vector: tuple/list
@param matrix: MMatrix object to provide the transformation
@type matrix: OpenMaya.MMatrix
@param transformAsPoint: Transform the vector as a point
@type transformAsPoint: bool
@param invertMatrix: Use the matrix inverse to transform the vector
@type invertMatrix: bool
'''
# Create MPoint/MVector object for transformation
if transformAsPoint:
vector = OpenMaya.MPoint(vector[0], vector[1], vector[2], 1.0)
else:
vector = OpenMaya.MVector(vector[0], vector[1], vector[2])
# Check input is of type MMatrix
if type(matrix) != OpenMaya.MMatrix:
raise Exception(
'Matrix input variable is not of expected type! Expecting MMatrix, received ' + str(type(matrix)) + '!!')
# Transform vector
if matrix != OpenMaya.MMatrix.identity:
if invertMatrix: matrix = matrix.inverse()
vector *= matrix
# Return new vector
return [vector.x, vector.y, vector.z]
def getTranslation(matrix):
'''
Return the translation component of a matrix.
@param matrix: Matrix to extract translation from
@type matrix: maya.OpenMaya.MMatrix
'''
x = OpenMaya.MScriptUtil.getDoubleArrayItem(matrix[3], 0)
y = OpenMaya.MScriptUtil.getDoubleArrayItem(matrix[3], 1)
z = OpenMaya.MScriptUtil.getDoubleArrayItem(matrix[3], 2)
return (x, y, z)
def getRotation(matrix, rotationOrder='xyz'):
'''
Return the rotation component of a matrix as euler (XYZ) values.
@param matrix: Matrix to extract rotation from
@type matrix: maya.OpenMaya.MMatrix
@param rotationOrder: Rotation order of the matrix
@type rotationOrder: str or int
'''
# Calculate radian constant
radian = 180.0 / math.pi
# Check rotation order
if type(rotationOrder) == str:
rotationOrder = rotationOrder.lower()
rotateOrder = {'xyz': 0, 'yzx': 1, 'zxy': 2, 'xzy': 3, 'yxz': 4, 'zyx': 5}
if rotationOrder not in rotateOrder:
raise Exception('Invalid rotation order supplied!')
rotationOrder = rotateOrder[rotationOrder]
else:
rotationOrder = int(rotationOrder)
# Get transformation matrix
transformMatrix = OpenMaya.MTransformationMatrix(matrix)
# Get Euler rotation from matrix
eulerRot = transformMatrix.eulerRotation()
# Reorder rotation
eulerRot.reorderIt(rotationOrder)
# Return XYZ rotation values
return (eulerRot.x * radian, eulerRot.y * radian, eulerRot.z * radian)
def buildRotation(aimVector, upVector=(0, 1, 0), aimAxis='x', upAxis='y'):
'''
Build rotation matrix from the specified inputs
@param aimVector: Aim vector for construction of rotation matrix (worldSpace)
@type aimVector: tuple or list
@param upVector: Up vector for construction of rotation matrix (worldSpace)
@type upVector: tuple or list
@param aimAxis: Aim vector for construction of rotation matrix
@type aimAxis: str
@param upAxis: Up vector for construction of rotation matrix
@type upAxis: str
'''
# Check negative axis
negAim = False
negUp = False
if aimAxis[0] == '-':
aimAxis = aimAxis[1]
negAim = True
if upAxis[0] == '-':
upAxis = upAxis[1]
negUp = True
# Check valid axis
axisList = ['x', 'y', 'z']
if not axisList.count(aimAxis): raise Exception('Aim axis is not valid!')
if not axisList.count(upAxis): raise Exception('Up axis is not valid!')
if aimAxis == upAxis: raise Exception('Aim and Up axis must be unique!')
# Determine cross axis
axisList.remove(aimAxis)
axisList.remove(upAxis)
crossAxis = axisList[0]
# Normaize aimVector
aimVector = mathUtils.normalizeVector(aimVector)
if negAim: aimVector = (-aimVector[0], -aimVector[1], -aimVector[2])
# Normaize upVector
upVector = mathUtils.normalizeVector(upVector)
if negUp: upVector = (-upVector[0], -upVector[1], -upVector[2])
# Get cross product vector
crossVector = (0, 0, 0)
if (aimAxis == 'x' and upAxis == 'z') or (aimAxis == 'z' and upAxis == 'y'):
crossVector = mathUtils.crossProduct(upVector, aimVector)
else:
crossVector = mathUtils.crossProduct(aimVector, upVector)
# Recalculate upVector (orthogonalize)
if (aimAxis == 'x' and upAxis == 'z') or (aimAxis == 'z' and upAxis == 'y'):
upVector = mathUtils.crossProduct(aimVector, crossVector)
else:
upVector = mathUtils.crossProduct(crossVector, aimVector)
# Build axis dictionary
axisDict = {aimAxis: aimVector, upAxis: upVector, crossAxis: crossVector}
# Build rotation matrix
mat = buildMatrix(xAxis=axisDict['x'], yAxis=axisDict['y'], zAxis=axisDict['z'])
# Return rotation matrix
return mat
def inverseTransform(source, destination, translate=True, rotate=True, scale=True):
'''
Apply the inverse of a specified transform to another target transform.
@param source: The source transform that will supply the transformation
@type source: str
@param destination: The destination transform that will receive the inverse transformation
@type destination: str
@param translate: Apply inverse translate to destination transform
@type translate: bool
@param rotate: Apply inverse rotation to destination transform
@type rotate: bool
@param scale: Apply inverse scale to destination transform
@type scale: bool
'''
# ==========
# - Checks -
# ==========
if not mc.objExists(source): raise Exception('Transform "' + source + '" does not exist!!')
if not mc.objExists(destination): raise Exception('Transform "' + destination + '" does not exist!!')
# Load decomposeMatrix plugin
if not mc.pluginInfo('decomposeMatrix', q=True, l=True):
try:
mc.loadPlugin('decomposeMatrix')
except:
raise MissingPluginError('Unable to load "decomposeMatrix" plugin!!')
# =================================
# - Apply Inverse Transformations -
# =================================
# Create and name decomposeMatrix node
dcm = mc.createNode('decomposeMatrix', n=source + '_decomposeMatrix')
# Make connections
mc.connectAttr(source + '.inverseMatrix', dcm + '.inputMatrix', f=True)
if translate: mc.connectAttr(dcm + '.outputTranslate', destination + '.translate', f=True)
if rotate: mc.connectAttr(dcm + '.outputRotate', destination + '.rotate', f=True)
if scale: mc.connectAttr(dcm + '.outputScale', destination + '.scale', f=True)
# =================
# - Return Result -
# =================
return dcm
def fromList(valueList):
'''
Create matrix from value list.
@param valueList: List of matrix values
@type valueList: list
'''
# Check Value List
if len(valueList) != 16:
raise Exception('Invalid value list! Expecting 16 element, found ' + str(len(valueList)))
# Create transformation matrix from input vaules
matrix = OpenMaya.MMatrix()
OpenMaya.MScriptUtil.createMatrixFromList(valueList, matrix)
# OpenMaya.MScriptUtil.setDoubleArray(matrix[0], 0, valueList[0])
# OpenMaya.MScriptUtil.setDoubleArray(matrix[0], 1, valueList[1])
# OpenMaya.MScriptUtil.setDoubleArray(matrix[0], 2, valueList[2])
# OpenMaya.MScriptUtil.setDoubleArray(matrix[0], 3, valueList[3])
# OpenMaya.MScriptUtil.setDoubleArray(matrix[1], 0, valueList[4])
# OpenMaya.MScriptUtil.setDoubleArray(matrix[1], 1, valueList[5])
# OpenMaya.MScriptUtil.setDoubleArray(matrix[1], 2, valueList[6])
# OpenMaya.MScriptUtil.setDoubleArray(matrix[1], 3, valueList[7])
# OpenMaya.MScriptUtil.setDoubleArray(matrix[2], 0, valueList[8])
# OpenMaya.MScriptUtil.setDoubleArray(matrix[2], 1, valueList[9])
# OpenMaya.MScriptUtil.setDoubleArray(matrix[2], 2, valueList[10])
# OpenMaya.MScriptUtil.setDoubleArray(matrix[2], 3, valueList[11])
# OpenMaya.MScriptUtil.setDoubleArray(matrix[3], 0, valueList[12])
# OpenMaya.MScriptUtil.setDoubleArray(matrix[3], 1, valueList[13])
# OpenMaya.MScriptUtil.setDoubleArray(matrix[3], 2, valueList[14])
# OpenMaya.MScriptUtil.setDoubleArray(matrix[3], 3, valueList[15])
# Return Result
return matrix
def asList(matrix):
'''
Return the specified matrix as a list
@param matrix: Matrix to return list for
@type matrix: maya.OpenMaya.MMatrix
'''
return [matrix(0, 0), matrix(0, 1), matrix(0, 2), matrix(0, 3),
matrix(1, 0), matrix(1, 1), matrix(1, 2), matrix(1, 3),
matrix(2, 0), matrix(2, 1), matrix(2, 2), matrix(2, 3),
matrix(3, 0), matrix(3, 1), matrix(3, 2), matrix(3, 3), ]
def printMatrix(matrix):
'''
Print the specified matrix values to the script editor
@param matrix: Matrix to print
@type matrix: maya.OpenMaya.MMatrix
'''
print(('%.3f' % matrix(0, 0)) + ', ' + ('%.3f' % matrix(0, 1)) + ', ' + ('%.3f' % matrix(0, 2)) + ', ' + (
'%.3f' % matrix(0, 3)))
print(('%.3f' % matrix(1, 0)) + ', ' + ('%.3f' % matrix(1, 1)) + ', ' + ('%.3f' % matrix(1, 2)) + ', ' + (
'%.3f' % matrix(1, 3)))
print(('%.3f' % matrix(2, 0)) + ', ' + ('%.3f' % matrix(2, 1)) + ', ' + ('%.3f' % matrix(2, 2)) + ', ' + (
'%.3f' % matrix(2, 3)))
print(('%.3f' % matrix(3, 0)) + ', ' + ('%.3f' % matrix(3, 1)) + ', ' + ('%.3f' % matrix(3, 2)) + ', ' + (
'%.3f' % matrix(3, 3)))