1027 lines
33 KiB
Python
1027 lines
33 KiB
Python
|
import maya.cmds as cmds
|
||
|
import maya.mel as mel
|
||
|
import maya.api.OpenMaya as om
|
||
|
from six.moves import range
|
||
|
from collections import Counter, OrderedDict
|
||
|
from functools import partial
|
||
|
from webbrowser import open_new_tab
|
||
|
import six, math
|
||
|
|
||
|
|
||
|
def GetSelection(*args, **kwargs):
|
||
|
type = kwargs["type"] if "type" in kwargs else "None"
|
||
|
highlight = kwargs["highlight"] if "highlight" in kwargs else False
|
||
|
flatten = kwargs["flatten"] if "flatten" in kwargs else False
|
||
|
allParents = kwargs["allParents"] if "allParents" in kwargs else False
|
||
|
|
||
|
# Check if there is any args
|
||
|
if len(args) > 0:
|
||
|
selection, objects = [], []
|
||
|
# Get selection & objects from args
|
||
|
for arg in args:
|
||
|
selection.extend(arg)
|
||
|
objects.extend(arg)
|
||
|
else:
|
||
|
# Get selection
|
||
|
if flatten:
|
||
|
selection = cmds.ls(sl=True, l=True, fl=True)
|
||
|
else:
|
||
|
selection = cmds.ls(sl=True, l=True)
|
||
|
|
||
|
objects = list(selection)
|
||
|
|
||
|
# Get highlighted objects
|
||
|
if highlight:
|
||
|
objects.extend(cmds.ls(hl=True, l=True))
|
||
|
|
||
|
# Get shapes
|
||
|
if type == "mesh":
|
||
|
shapes = cmds.ls(objects, l=True, dag=True, ni=True, o=True, typ="mesh")
|
||
|
elif type == "geometry" or type == "geo":
|
||
|
shapes = cmds.ls(objects, l=True, dag=True, ni=True, o=True, g=True)
|
||
|
elif type == "nurbsCurve" or type == "curve":
|
||
|
shapes = cmds.ls(objects, l=True, dag=True, ni=True, typ="nurbsCurve")
|
||
|
elif type == "transform":
|
||
|
shapes = cmds.ls(objects, l=True, dag=True, ni=True, o=True, typ="transform")
|
||
|
else:
|
||
|
shapes = cmds.ls(objects, l=True, dag=True, ni=True, o=True)
|
||
|
|
||
|
# Get objects
|
||
|
if allParents:
|
||
|
objects = cmds.listRelatives(shapes, f=True, ap=True, ni=True, typ="transform")
|
||
|
else:
|
||
|
objects = cmds.listRelatives(shapes, f=True, p=True, ni=True, typ="transform")
|
||
|
|
||
|
# Remove intermediate objects
|
||
|
objects = cmds.ls(objects, l=True, ni=True)
|
||
|
|
||
|
# Remove duplicates objects
|
||
|
if objects is not None:
|
||
|
objects = list(OrderedDict.fromkeys(objects))
|
||
|
|
||
|
return selection, shapes, objects
|
||
|
|
||
|
def GetComponentType(*args, **kwargs):
|
||
|
# Create default args
|
||
|
selection = None
|
||
|
|
||
|
# Load arguments (override default args)
|
||
|
for i, arg in enumerate(args):
|
||
|
if i == 0:
|
||
|
selection = arg
|
||
|
|
||
|
# Load keyworded arguments (override *args)
|
||
|
for key, value in six.iteritems(kwargs):
|
||
|
if key == "selection" or key == "sel":
|
||
|
selection = value
|
||
|
|
||
|
selList = om.MSelectionList()
|
||
|
|
||
|
if selection is not None:
|
||
|
for each in selection:
|
||
|
try:
|
||
|
selList.add(each)
|
||
|
except:
|
||
|
pass
|
||
|
else:
|
||
|
selList = om.MGlobal.getActiveSelectionList()
|
||
|
|
||
|
filterDict = OrderedDict([("v", om.MFn.kMeshVertComponent), ("eg", om.MFn.kMeshEdgeComponent), ("fc", om.MFn.kMeshPolygonComponent), ("puv", om.MFn.kMeshMapComponent), ("pvf", om.MFn.kMeshVtxFaceComponent), ("cv", om.MFn.kCurveCVComponent)])
|
||
|
|
||
|
for key, filter in six.iteritems(filterDict):
|
||
|
iter = om.MItSelectionList(selList, filter)
|
||
|
try:
|
||
|
if iter.hasComponents() is True:
|
||
|
return key
|
||
|
except:
|
||
|
pass
|
||
|
|
||
|
return None
|
||
|
|
||
|
def Eval(msg, mode='PRINT', deferred=False):
|
||
|
if deferred is False:
|
||
|
if mode == 'PRINT':
|
||
|
from sys import stdout; stdout.write("{}\n".format(msg))
|
||
|
elif mode == 'INFO':
|
||
|
om.MGlobal.displayInfo(msg)
|
||
|
elif mode == 'WARNING':
|
||
|
om.MGlobal.displayWarning(msg)
|
||
|
elif mode == 'ERROR':
|
||
|
om.MGlobal.displayError(msg)
|
||
|
else:
|
||
|
if mode == 'PRINT':
|
||
|
cmds.evalDeferred(r'from sys import stdout; stdout.write("{}\n")'.format(msg))
|
||
|
elif mode == 'INFO':
|
||
|
cmds.evalDeferred(r'import maya.api.OpenMaya as om; om.MGlobal.displayInfo("'+msg+'")')
|
||
|
elif mode == 'WARNING':
|
||
|
cmds.evalDeferred(r'import maya.api.OpenMaya as om; om.MGlobal.displayWarning("'+msg+'")')
|
||
|
elif mode == 'ERROR':
|
||
|
cmds.evalDeferred(r'import maya.api.OpenMaya as om; om.MGlobal.displayError("'+msg+'")')
|
||
|
|
||
|
def Print(object, mode='PRINT', deferred=False):
|
||
|
if type(object) is not list:
|
||
|
Eval(object, mode, deferred)
|
||
|
else:
|
||
|
for obj in object:
|
||
|
Eval(obj, mode, deferred)
|
||
|
|
||
|
def IsInstanced(object):
|
||
|
isInstanced = False
|
||
|
shapes = cmds.listRelatives(object, f=True, s=True, ni=True)
|
||
|
if shapes:
|
||
|
parents = cmds.listRelatives(shapes, f=True, ap=True) or []
|
||
|
if len(parents) > 1:
|
||
|
isInstanced = True
|
||
|
return isInstanced
|
||
|
|
||
|
def getOutlinerList(object=None):
|
||
|
# If object has a parent, get a list of the childrens
|
||
|
if object:
|
||
|
parent = cmds.listRelatives(object, parent=True, fullPath=True)
|
||
|
if parent:
|
||
|
return cmds.listRelatives(parent, children=True, type="transform", fullPath=True)
|
||
|
# Otherwise, get list of assemblies in the scene
|
||
|
return cmds.ls(long=True, assemblies=True)
|
||
|
|
||
|
def getOutlinerPosition(obj):
|
||
|
# Check if objects exists
|
||
|
if cmds.objExists(obj):
|
||
|
# Make sure it's long names
|
||
|
obj = cmds.ls(obj, long=True)[0]
|
||
|
# Get a list of the outliner
|
||
|
outlinerList = getOutlinerList(obj)
|
||
|
# Get the position of the object in the outliner
|
||
|
sourceObjPosition = outlinerList.index(obj)+1
|
||
|
# Get the position of the object from the bottom of the outliner
|
||
|
return sourceObjPosition - len(outlinerList)
|
||
|
|
||
|
def crossProduct(v1, v2):
|
||
|
vector = om.MVector(*v1) ^ om.MVector(*v2)
|
||
|
return [vector.x, vector.y, vector.z]
|
||
|
|
||
|
def normalizeVector(v1=[1, 0, 0]):
|
||
|
if isinstance(v1, (list, tuple)) is True and len(v1) >= 3:
|
||
|
v1 = om.MVector(v1[0], v1[1], v1[2])
|
||
|
v1.normalize()
|
||
|
v1 = [v1.x, v1.y, v1.z]
|
||
|
return v1
|
||
|
|
||
|
def vectorBetweenPoints(point1, point2):
|
||
|
return normalizeVector([point2[i] - point1[i] for i in range(len(point1))])
|
||
|
|
||
|
def vectorAvg(vectors):
|
||
|
sum = om.MVector()
|
||
|
|
||
|
for vector in vectors:
|
||
|
sum += vector
|
||
|
|
||
|
return sum / len(vectors)
|
||
|
|
||
|
def cubicRoot(number):
|
||
|
return number ** (1 / 3)
|
||
|
|
||
|
def GetVertexPosition(vertex):
|
||
|
id = int(vertex.split("[")[-1][:-1])
|
||
|
|
||
|
vtxList = om.MSelectionList().add(vertex)
|
||
|
dagPath = vtxList.getDagPath(0)
|
||
|
|
||
|
vtx_iter = om.MItMeshVertex(dagPath)
|
||
|
vtx_iter.setIndex(id)
|
||
|
|
||
|
# Get vertex position
|
||
|
position = vtx_iter.position(space=om.MSpace.kWorld)
|
||
|
|
||
|
return om.MVector(position)
|
||
|
|
||
|
def GetEdgePosition(edge):
|
||
|
id = int(edge.split("[")[-1][:-1])
|
||
|
|
||
|
edgeList = om.MSelectionList().add(edge)
|
||
|
dagPath = edgeList.getDagPath(0)
|
||
|
|
||
|
edge_iter = om.MItMeshEdge(dagPath)
|
||
|
edge_iter.setIndex(id)
|
||
|
|
||
|
# Get edge position
|
||
|
position = edge_iter.center(space=om.MSpace.kWorld)
|
||
|
|
||
|
return om.MVector(position)
|
||
|
|
||
|
def GetFacePosition(face):
|
||
|
id = int(face.split("[")[-1][:-1])
|
||
|
|
||
|
faceList = om.MSelectionList().add(face)
|
||
|
dagPath = faceList.getDagPath(0)
|
||
|
|
||
|
face_iter = om.MItMeshPolygon(dagPath)
|
||
|
face_iter.setIndex(id)
|
||
|
|
||
|
# Get edge position
|
||
|
position = face_iter.center(space=om.MSpace.kWorld)
|
||
|
|
||
|
return om.MVector(position)
|
||
|
|
||
|
def GetVertexVectors(vertex):
|
||
|
space = om.MSpace.kWorld
|
||
|
id = int(vertex.split("[")[-1][:-1])
|
||
|
|
||
|
vtxList = om.MSelectionList().add(vertex)
|
||
|
dagPath = vtxList.getDagPath(0)
|
||
|
|
||
|
vtx_iter = om.MItMeshVertex(dagPath)
|
||
|
vtx_iter.setIndex(id)
|
||
|
|
||
|
# Get vertex normal & position
|
||
|
normal = vtx_iter.getNormal(space=space)
|
||
|
position = vtx_iter.position(space=space)
|
||
|
|
||
|
# Get all connected vertices
|
||
|
cvertices = list(vtx_iter.getConnectedVertices())
|
||
|
vertices_dict = {}
|
||
|
|
||
|
cvtx_iter = om.MItMeshVertex(dagPath)
|
||
|
while len(cvertices):
|
||
|
if cvertices[0] not in vertices_dict:
|
||
|
cvtx_iter.setIndex(cvertices[0])
|
||
|
cvtx_position = cvtx_iter.position(space=space)
|
||
|
edge_v = vectorBetweenPoints(list(position), list(cvtx_position))
|
||
|
vertices_dict[cvertices[0]] = tuple([round(v, 3) for v in edge_v])
|
||
|
|
||
|
del cvertices[0]
|
||
|
|
||
|
# Get the most common vector
|
||
|
tangent, vector_count = Counter(vertices_dict.values()).most_common(1)[0]
|
||
|
|
||
|
# If no common vector is found, check for parallel vectors
|
||
|
if vector_count < 2:
|
||
|
all_vectors = list(vertices_dict.values())
|
||
|
parallel_vectors = {k: 1 for k in all_vectors}
|
||
|
while len(all_vectors) > 0:
|
||
|
omV = om.MVector(all_vectors[0])
|
||
|
for ov in all_vectors:
|
||
|
if ov == all_vectors[0]:
|
||
|
continue
|
||
|
if omV.isParallel(om.MVector(ov)):
|
||
|
parallel_vectors[all_vectors[0]] += 1
|
||
|
del parallel_vectors[ov]
|
||
|
del all_vectors[0]
|
||
|
v = max(parallel_vectors, key=parallel_vectors.get)
|
||
|
if parallel_vectors[v] > 1:
|
||
|
tangent, vector_count = v, parallel_vectors[v]
|
||
|
|
||
|
# If no parallel vector is found, use first two points
|
||
|
if vector_count < 2:
|
||
|
vtx_id = list(vertices_dict.keys())[0]
|
||
|
else:
|
||
|
vtx_id = list(vertices_dict.keys())[list(vertices_dict.values()).index(tangent)]
|
||
|
|
||
|
# Calculate tangent
|
||
|
cvtx_iter.setIndex(vtx_id)
|
||
|
cvtx_position = cvtx_iter.position(space=space)
|
||
|
tangent = vectorBetweenPoints(list(position), list(cvtx_position))
|
||
|
|
||
|
return list(normal), tangent
|
||
|
|
||
|
def GetEdgeVectors(edge):
|
||
|
space = om.MSpace.kWorld
|
||
|
|
||
|
# Calculate normal from face vertices
|
||
|
vtxFaces = cmds.polyListComponentConversion(edge, fe=True, tvf=True)
|
||
|
vtxFaceList = om.MSelectionList()
|
||
|
for vtxFace in vtxFaces:
|
||
|
vtxFaceList.add(vtxFace)
|
||
|
|
||
|
normal = om.MVector()
|
||
|
count = 0
|
||
|
|
||
|
dagPath, component = vtxFaceList.getComponent(0)
|
||
|
fnMesh = om.MFnMesh(dagPath)
|
||
|
vtxFace_itr = om.MItMeshFaceVertex(dagPath, component)
|
||
|
while not vtxFace_itr.isDone():
|
||
|
faceId = vtxFace_itr.faceId()
|
||
|
vertexId = vtxFace_itr.vertexId()
|
||
|
|
||
|
normal += fnMesh.getFaceVertexNormal(faceId, vertexId, space=space)
|
||
|
count += 1
|
||
|
|
||
|
vtxFace_itr.next()
|
||
|
|
||
|
normal = normal / count
|
||
|
|
||
|
# Get tangent
|
||
|
id = int(edge.split("[")[-1][:-1])
|
||
|
edgeList = om.MSelectionList().add(edge)
|
||
|
dagPath = edgeList.getDagPath(0)
|
||
|
|
||
|
edge_iter = om.MItMeshEdge(dagPath)
|
||
|
edge_iter.setIndex(id)
|
||
|
|
||
|
position = om.MPoint()
|
||
|
|
||
|
vertices = [edge_iter.vertexId(0), edge_iter.vertexId(1)]
|
||
|
vtx_iter = om.MItMeshVertex(dagPath)
|
||
|
for vtx in vertices:
|
||
|
vtx_iter.setIndex(vtx)
|
||
|
position += vtx_iter.position(space=space)
|
||
|
|
||
|
avgPos = position / len(vertices)
|
||
|
tangent = vectorBetweenPoints(list(avgPos), list(edge_iter.point(1, space)))
|
||
|
|
||
|
return list(normal), list(tangent)
|
||
|
|
||
|
def GetFaceVectors(face):
|
||
|
space = om.MSpace.kWorld
|
||
|
id = int(face.split("[")[-1][:-1])
|
||
|
|
||
|
faceList = om.MSelectionList().add(face)
|
||
|
dagPath = faceList.getDagPath(0)
|
||
|
|
||
|
face_iter = om.MItMeshPolygon(dagPath)
|
||
|
face_iter.setIndex(id)
|
||
|
|
||
|
# Get face normal
|
||
|
normal = face_iter.getNormal(space=space)
|
||
|
|
||
|
# Get all connected faces that have similar normal
|
||
|
cfaces = list(face_iter.getConnectedFaces())
|
||
|
faces_dict = {id: True}
|
||
|
|
||
|
cface_iter = om.MItMeshPolygon(dagPath)
|
||
|
while len(cfaces):
|
||
|
if cfaces[0] not in faces_dict:
|
||
|
cface_iter.setIndex(cfaces[0])
|
||
|
cface_normal = cface_iter.getNormal(space=space)
|
||
|
if normal.isEquivalent(cface_normal, 0.01):
|
||
|
faces_dict[cfaces[0]] = True
|
||
|
for f in cface_iter.getConnectedFaces():
|
||
|
if f not in faces_dict:
|
||
|
cfaces.append(f)
|
||
|
else:
|
||
|
faces_dict[cfaces[0]] = False
|
||
|
|
||
|
del cfaces[0]
|
||
|
|
||
|
# Get edge vectors from connected faces
|
||
|
cfaces = [f for f, value in six.iteritems(faces_dict) if value is True]
|
||
|
edges_dict = {}
|
||
|
|
||
|
cedge_iter = om.MItMeshEdge(dagPath)
|
||
|
for f in cfaces:
|
||
|
cface_iter.setIndex(f)
|
||
|
cedges = list(cface_iter.getEdges())
|
||
|
|
||
|
for edge in cedges:
|
||
|
if edge not in edges_dict:
|
||
|
cedge_iter.setIndex(edge)
|
||
|
edge_v = vectorBetweenPoints(list(cedge_iter.point(0, space)), list(cedge_iter.point(1, space)))
|
||
|
edges_dict[edge] = tuple([round(v, 3) for v in edge_v])
|
||
|
|
||
|
# Get the most common vector
|
||
|
tangent, vector_count = Counter(edges_dict.values()).most_common(1)[0]
|
||
|
|
||
|
# if no common vector is found, check for parallel vectors
|
||
|
if vector_count < 2:
|
||
|
all_vectors = list(edges_dict.values())
|
||
|
parallel_vectors = {k: 1 for k in all_vectors}
|
||
|
while len(all_vectors) > 0:
|
||
|
omV = om.MVector(all_vectors[0])
|
||
|
for ov in all_vectors:
|
||
|
if ov == all_vectors[0]:
|
||
|
continue
|
||
|
if omV.isParallel(om.MVector(ov)):
|
||
|
parallel_vectors[all_vectors[0]] += 1
|
||
|
del parallel_vectors[ov]
|
||
|
del all_vectors[0]
|
||
|
v = max(parallel_vectors, key=parallel_vectors.get)
|
||
|
if parallel_vectors[v] > 1:
|
||
|
tangent, vector_count = v, parallel_vectors[v]
|
||
|
|
||
|
# if no parallel vector is found, use first two points
|
||
|
if vector_count < 2:
|
||
|
# get face-relative vertices positions
|
||
|
vertices_position = face_iter.getPoints(space=space)
|
||
|
vertices_dict = {}
|
||
|
# convert face-relative indices to object-relative indices
|
||
|
for i in range(face_iter.polygonVertexCount()):
|
||
|
vertices_dict[int(face_iter.vertexIndex(i))] = vertices_position[i]
|
||
|
vertices_dict = OrderedDict(sorted(vertices_dict.items()))
|
||
|
vertices_position = []
|
||
|
for pos in six.itervalues(vertices_dict):
|
||
|
vertices_position.append(pos)
|
||
|
if len(vertices_position) == 2:
|
||
|
break
|
||
|
tangent = vectorBetweenPoints(list(vertices_position[0]), list(vertices_position[1]))
|
||
|
else:
|
||
|
# Get back the original vector since we needed to round the values for comparing the vectors
|
||
|
edge_id = list(edges_dict.keys())[list(edges_dict.values()).index(tangent)]
|
||
|
cedge_iter.setIndex(edge_id)
|
||
|
tangent = vectorBetweenPoints(list(cedge_iter.point(0, space)), list(cedge_iter.point(1, space)))
|
||
|
|
||
|
return list(normal), tangent
|
||
|
|
||
|
def GetOrientationFromVectors(normal, tangent):
|
||
|
binormal = normalizeVector(crossProduct(normal, tangent))
|
||
|
|
||
|
position = [0, 0, 0]
|
||
|
|
||
|
tMatrix = normal + [0] + tangent + [0] + binormal + [0] + position + [1]
|
||
|
mMatrix = om.MMatrix(tMatrix)
|
||
|
tmMatrix = om.MTransformationMatrix(mMatrix)
|
||
|
rotation = tmMatrix.rotation(False).reorder(om.MEulerRotation.kXYZ)
|
||
|
rotation = [math.degrees(x + 0) for x in list(rotation)[:3]]
|
||
|
|
||
|
return rotation
|
||
|
|
||
|
def SignedVolumeOfTriangle(p1, p2, p3):
|
||
|
volume = (p1 * (p2 ^ p3)) / 6
|
||
|
return volume
|
||
|
|
||
|
def GetObjectVolume(object):
|
||
|
# Create face list
|
||
|
faces = object + ".f[*]"
|
||
|
faceList = om.MSelectionList().add(faces)
|
||
|
dagPath, component = faceList.getComponent(0)
|
||
|
|
||
|
# Get ids list
|
||
|
compFn = om.MFnSingleIndexedComponent(component)
|
||
|
ids = compFn.getElements()
|
||
|
|
||
|
# Get all triangle volumes
|
||
|
volumes = []
|
||
|
border = False
|
||
|
|
||
|
# Looping through each face
|
||
|
face_iter = om.MItMeshPolygon(dagPath, component)
|
||
|
for id in ids:
|
||
|
face_iter.setIndex(id)
|
||
|
numTriangles = face_iter.numTriangles()
|
||
|
# Loop each face triangle
|
||
|
for num in range(numTriangles):
|
||
|
triangle = face_iter.getTriangle(num, space=om.MSpace.kWorld)[0]
|
||
|
volume = SignedVolumeOfTriangle(om.MVector(triangle[0]), om.MVector(triangle[1]), om.MVector(triangle[2]))
|
||
|
volumes.append(volume)
|
||
|
|
||
|
# Check if face is on open border
|
||
|
if border is False:
|
||
|
border = face_iter.onBoundary()
|
||
|
|
||
|
# Calcule sum of every triangle volumes
|
||
|
volume = abs(sum(volumes))
|
||
|
|
||
|
# Print warning if object has open borders
|
||
|
if border is True:
|
||
|
Print.Print("{} has open borders, which could result in unexpected scale values.".format(object), mode='WARNING', deferred=True)
|
||
|
|
||
|
# Return volume cubic root
|
||
|
return cubicRoot(volume)
|
||
|
|
||
|
def GetEdgeScale(edge):
|
||
|
id = int(edge.split("[")[-1][:-1])
|
||
|
|
||
|
edgeList = om.MSelectionList().add(edge)
|
||
|
dagPath = edgeList.getDagPath(0)
|
||
|
|
||
|
edge_iter = om.MItMeshEdge(dagPath)
|
||
|
edge_iter.setIndex(id)
|
||
|
|
||
|
# Get edge position
|
||
|
scale = edge_iter.length(space=om.MSpace.kWorld)
|
||
|
|
||
|
return scale
|
||
|
|
||
|
def GetFaceScale(face):
|
||
|
id = int(face.split("[")[-1][:-1])
|
||
|
|
||
|
faceList = om.MSelectionList().add(face)
|
||
|
dagPath = faceList.getDagPath(0)
|
||
|
|
||
|
face_iter = om.MItMeshPolygon(dagPath)
|
||
|
face_iter.setIndex(id)
|
||
|
|
||
|
# Get edge position
|
||
|
scale = face_iter.getArea(space=om.MSpace.kWorld)
|
||
|
|
||
|
return math.sqrt(scale)
|
||
|
|
||
|
# Create empty MEL function for proper undo/redo operations
|
||
|
mel.eval('proc BakeTransformations(){}')
|
||
|
|
||
|
# Main function
|
||
|
def PerformBakeTransformations(bakeMode=1, setObjSpc=1, clearSel=1, bakePos=1, bakeRot=1, bakeScale=1):
|
||
|
# Open undo chunk
|
||
|
cmds.undoInfo(ock=True, cn="BakeTransformations")
|
||
|
|
||
|
# Call empty MEL function for proper undo/redo operations
|
||
|
mel.eval('BakeTransformations')
|
||
|
|
||
|
# Get selection
|
||
|
selection = GetSelection(highlight=False, flatten=True)[0]
|
||
|
|
||
|
# Check that something is selected
|
||
|
if not len(selection):
|
||
|
Print("Nothing selected!", mode='ERROR')
|
||
|
cmds.undoInfo(cck=True)
|
||
|
|
||
|
# Get object from selection
|
||
|
component = selection[-1]
|
||
|
selectType = GetComponentType([component])
|
||
|
object = GetSelection([component], type="mesh")[2][-1] if selectType else component
|
||
|
|
||
|
# Check that a component is selected
|
||
|
if bakeMode == 1 and not selectType:
|
||
|
Print("No component selected!", mode='ERROR')
|
||
|
cmds.undoInfo(cck=True)
|
||
|
return
|
||
|
|
||
|
# Check that object is not an instance
|
||
|
if IsInstanced(object):
|
||
|
Print("Selected object is an instance and cannot be baked.", mode='ERROR')
|
||
|
cmds.undoInfo(cck=True)
|
||
|
return
|
||
|
|
||
|
# Get object parent and outliner position
|
||
|
parent = cmds.listRelatives(object, f=True, p=True)
|
||
|
currentPosition = getOutlinerPosition(object)
|
||
|
|
||
|
# Get pivot manipulator context and mode
|
||
|
if bakeMode == 2:
|
||
|
currentCtx = cmds.currentCtx()
|
||
|
if currentCtx == "moveSuperContext":
|
||
|
manipMode = cmds.manipMoveContext("Move", q=True, m=True)
|
||
|
elif currentCtx == "RotateSuperContext":
|
||
|
manipMode = cmds.manipRotateContext("Rotate", q=True, m=True)
|
||
|
if manipMode == 1:
|
||
|
manipMode = 2
|
||
|
elif manipMode == 2:
|
||
|
manipMode = 0
|
||
|
elif manipMode == 3:
|
||
|
manipMode = 6
|
||
|
elif currentCtx == "scaleSuperContext":
|
||
|
manipMode = cmds.manipScaleContext("Scale", q=True, m=True)
|
||
|
|
||
|
# Store current units and temporarily change for centimeters
|
||
|
units = cmds.currentUnit(q=True, l=True)
|
||
|
cmds.currentUnit(l="cm")
|
||
|
|
||
|
# Get translation
|
||
|
if bakePos or not clearSel:
|
||
|
# From Component
|
||
|
if bakeMode == 1:
|
||
|
if selectType == "v":
|
||
|
# Get vertex position
|
||
|
position = GetVertexPosition(component)
|
||
|
if selectType == "eg":
|
||
|
# Get edge position
|
||
|
position = GetEdgePosition(component)
|
||
|
if selectType == "fc":
|
||
|
# Get face position
|
||
|
position = GetFacePosition(component)
|
||
|
# From Pivot
|
||
|
elif bakeMode == 2:
|
||
|
# Case 1: Get move tool position
|
||
|
if currentCtx == "moveSuperContext" and cmds.manipMoveContext("Move", q=True, vis=True):
|
||
|
position = cmds.manipMoveContext("Move", q=True, p=True)
|
||
|
elif currentCtx == "moveSuperContext" and cmds.manipMoveContext("Move", q=True, epm=True):
|
||
|
position = cmds.manipMoveContext("Move", q=True, epp=True)
|
||
|
# Case 2: Get rotate tool position
|
||
|
elif currentCtx == "RotateSuperContext" and cmds.manipRotateContext("Rotate", q=True, vis=True):
|
||
|
position = cmds.manipRotateContext("Rotate", q=True, p=True)
|
||
|
elif currentCtx == "RotateSuperContext" and cmds.manipRotateContext("Rotate", q=True, epm=True):
|
||
|
position = cmds.manipRotateContext("Rotate", q=True, epp=True)
|
||
|
# Case 3: Get scale tool position
|
||
|
elif currentCtx == "scaleSuperContext" and cmds.manipScaleContext("Scale", q=True, vis=True):
|
||
|
position = cmds.manipScaleContext("Scale", q=True, p=True)
|
||
|
elif currentCtx == "scaleSuperContext" and cmds.manipScaleContext("Scale", q=True, epm=True):
|
||
|
position = cmds.manipScaleContext("Scale", q=True, epp=True)
|
||
|
# Case 4: Get object pivot position
|
||
|
else:
|
||
|
rotatePivot = om.MVector(cmds.xform(object, q=True, a=True, ws=True, rp=True))
|
||
|
scalePivot = om.MVector(cmds.xform(object, q=True, a=True, ws=True, sp=True))
|
||
|
position = vectorAvg([rotatePivot, scalePivot])
|
||
|
|
||
|
# Get rotation
|
||
|
if bakeRot or not clearSel:
|
||
|
# From Component
|
||
|
if bakeMode == 1:
|
||
|
if selectType == "v":
|
||
|
# Get vertex normal and tangent
|
||
|
normal, tangent = GetVertexVectors(component)
|
||
|
elif selectType == "eg":
|
||
|
# Get edge normal and tangent
|
||
|
normal, tangent = GetEdgeVectors(component)
|
||
|
elif selectType == "fc":
|
||
|
# Get face normal and tangent
|
||
|
normal, tangent = GetFaceVectors(component)
|
||
|
|
||
|
# Get rotation from the component normal and corresponding edge vector
|
||
|
rotation = GetOrientationFromVectors(normal, tangent)
|
||
|
# From Pivot
|
||
|
elif bakeMode == 2:
|
||
|
rotation = cmds.manipPivot(q=True, o=True)[0]
|
||
|
|
||
|
if any([currentCtx == "moveSuperContext", currentCtx == "RotateSuperContext", currentCtx == "scaleSuperContext"]):
|
||
|
if any([manipMode == 0, manipMode == 4, manipMode == 10]):
|
||
|
rotation = cmds.xform(object, q=True, a=True, eu=True, ro=True)
|
||
|
elif manipMode == 1:
|
||
|
if parent is not None:
|
||
|
rotation = cmds.xform(parent[0], q=True, a=True, eu=True, ro=True)
|
||
|
elif manipMode == 5:
|
||
|
live = cmds.ls(l=True, lv=True)
|
||
|
if len(live):
|
||
|
live = cmds.listRelatives(live, f=True, p=True, ni=True, typ="transform")[0]
|
||
|
rotation = cmds.xform(live, q=True, a=True, eu=True, ro=True)
|
||
|
|
||
|
# Get scale
|
||
|
if bakeScale:
|
||
|
# From Component
|
||
|
if bakeMode == 1:
|
||
|
if selectType == "v":
|
||
|
# Get vertex scale
|
||
|
scale = GetObjectVolume(object)
|
||
|
elif selectType == "eg":
|
||
|
# Get edge scale
|
||
|
scale = GetEdgeScale(component)
|
||
|
elif selectType == "fc":
|
||
|
# Get face scale
|
||
|
scale = GetFaceScale(component)
|
||
|
# From Pivot
|
||
|
elif bakeMode == 2:
|
||
|
# Get pivot scale
|
||
|
scale = GetObjectVolume(object)
|
||
|
|
||
|
# Store components selection
|
||
|
cmds.selectMode(co=True)
|
||
|
cmds.selectType(pv=True)
|
||
|
vertices = cmds.ls(sl=True, l=True)
|
||
|
cmds.selectType(pe=True)
|
||
|
edges = cmds.ls(sl=True, l=True)
|
||
|
cmds.selectType(pf=True)
|
||
|
faces = cmds.ls(sl=True, l=True)
|
||
|
|
||
|
# Create null and apply transformations
|
||
|
null = cmds.ls(cmds.group(em=True), l=True)[0]
|
||
|
cmds.matchTransform(null, object)
|
||
|
|
||
|
# Set translation
|
||
|
if bakePos:
|
||
|
# Move null
|
||
|
cmds.xform(null, a=True, ws=True, t=position)
|
||
|
# Move pivot
|
||
|
cmds.xform(object, a=True, ws=True, piv=position)
|
||
|
|
||
|
# Set rotation
|
||
|
if bakeRot:
|
||
|
# Rotate null
|
||
|
cmds.xform(null, a=True, eu=True, roo="xyz", ro=rotation)
|
||
|
|
||
|
# Set scale
|
||
|
if bakeScale:
|
||
|
# Scale null
|
||
|
cmds.xform(null, a=True, ws=True, s=[scale, scale, scale])
|
||
|
|
||
|
# Freeze null transformations
|
||
|
cmds.makeIdentity(null, a=True, t=1-bakePos, r=1-bakeRot, s=1-bakeScale, n=False, pn=True)
|
||
|
|
||
|
# Parent object to null
|
||
|
if parent is not None:
|
||
|
null = cmds.ls(cmds.parent(null, parent), l=True)[0]
|
||
|
|
||
|
object = cmds.ls(cmds.parent(object, null), l=True)[0]
|
||
|
|
||
|
# Freeze object transformations
|
||
|
cmds.makeIdentity(object, a=True, t=bakePos, r=bakeRot, s=bakeScale, n=False, pn=True)
|
||
|
|
||
|
# Unparent object from null
|
||
|
if parent is not None:
|
||
|
object = cmds.ls(cmds.parent(object, parent), l=True)[0]
|
||
|
else:
|
||
|
object = cmds.ls(cmds.parent(object, w=True), l=True)[0]
|
||
|
|
||
|
# Delete null
|
||
|
cmds.delete(null)
|
||
|
|
||
|
# Restore outliner position
|
||
|
cmds.reorder(object, relative=currentPosition)
|
||
|
|
||
|
# Restore components selection
|
||
|
cmds.selectMode(co=True)
|
||
|
cmds.selectType(pv=True)
|
||
|
cmds.select(vertices, r=True)
|
||
|
cmds.selectType(pe=True)
|
||
|
cmds.select(edges, r=True)
|
||
|
cmds.selectType(pf=True)
|
||
|
cmds.select(faces, r=True)
|
||
|
|
||
|
# Select object
|
||
|
if clearSel:
|
||
|
cmds.selectMode(o=True)
|
||
|
cmds.select(object, r=True)
|
||
|
elif selectType is not None:
|
||
|
mel.eval("selectType -"+selectType+" 1;")
|
||
|
cmds.select(selection, r=True)
|
||
|
|
||
|
# Set tools axis to object space
|
||
|
if setObjSpc:
|
||
|
cmds.manipMoveContext("Move", e=True, m=0)
|
||
|
cmds.manipRotateContext("Rotate", e=True, m=0)
|
||
|
cmds.manipScaleContext("Scale", e=True, m=0)
|
||
|
elif bakeMode == 2:
|
||
|
cmds.manipPivot(p=position, o=rotation)
|
||
|
|
||
|
# Recover units
|
||
|
cmds.currentUnit(l=units)
|
||
|
|
||
|
# Close undo chunk
|
||
|
cmds.undoInfo(cck=True)
|
||
|
|
||
|
# Create a new partial class to print the correct command name when undoing
|
||
|
class rpartial(partial):
|
||
|
def __repr__(self):
|
||
|
return __name__.split(".")[-1]
|
||
|
|
||
|
# Create window
|
||
|
class BakeTransformations(object):
|
||
|
def __init__(self, optionBox=False, *args, **kwargs):
|
||
|
# Create default variables
|
||
|
self.pfx = "BT_"
|
||
|
self.windowName = self.pfx + "Window"
|
||
|
self.windowSizeMenuItem = self.pfx + "SaveWindowSize_menuItem"
|
||
|
|
||
|
self.windowTitle = "Bake Transformations"
|
||
|
self.runLabel = "Bake"
|
||
|
self.windowSize = [546, 350]
|
||
|
|
||
|
# Create option variables
|
||
|
self.saveWindowSize = self.pfx + "SaveWindowSize"
|
||
|
self.bakeMode = self.pfx + "BakeMode"
|
||
|
self.setObjSpc = self.pfx + "SetObjSpc"
|
||
|
self.clearSel = self.pfx + "ClearSel"
|
||
|
self.bakePos = self.pfx + "BakePos"
|
||
|
self.bakeRot = self.pfx + "BakeRot"
|
||
|
self.bakeScale = self.pfx + "BakeScale"
|
||
|
|
||
|
# Create window or run command
|
||
|
if optionBox is True:
|
||
|
self.createWindow()
|
||
|
else:
|
||
|
self.runCmd(closeWindow=False, **kwargs)
|
||
|
|
||
|
# Help command
|
||
|
def helpCmd(self, *args):
|
||
|
open_new_tab("https://gabrielnadeau.com/pages/gn-baketransformations")
|
||
|
|
||
|
# Run command
|
||
|
def runCmd(self, closeWindow, **kwargs):
|
||
|
# Get option variables
|
||
|
self.defaultSettings(reset=False)
|
||
|
|
||
|
if "bakeMode" in kwargs:
|
||
|
bakeMode = kwargs["bakeMode"]
|
||
|
else:
|
||
|
bakeMode = cmds.optionVar(q=self.bakeMode)
|
||
|
|
||
|
if "setObjSpc" in kwargs:
|
||
|
setObjSpc = kwargs["setObjSpc"]
|
||
|
else:
|
||
|
setObjSpc = cmds.optionVar(q=self.setObjSpc)
|
||
|
|
||
|
if "clearSel" in kwargs:
|
||
|
clearSel = kwargs["clearSel"]
|
||
|
else:
|
||
|
clearSel = cmds.optionVar(q=self.clearSel)
|
||
|
|
||
|
if "bakePos" in kwargs:
|
||
|
bakePos = kwargs["bakePos"]
|
||
|
else:
|
||
|
bakePos = cmds.optionVar(q=self.bakePos)
|
||
|
|
||
|
if "bakeRot" in kwargs:
|
||
|
bakeRot = kwargs["bakeRot"]
|
||
|
else:
|
||
|
bakeRot = cmds.optionVar(q=self.bakeRot)
|
||
|
|
||
|
if "bakeScale" in kwargs:
|
||
|
bakeScale = kwargs["bakeScale"]
|
||
|
else:
|
||
|
bakeScale = cmds.optionVar(q=self.bakeScale)
|
||
|
|
||
|
# Bake Transformations
|
||
|
PerformBakeTransformations(bakeMode, setObjSpc, clearSel, bakePos, bakeRot, bakeScale)
|
||
|
|
||
|
# Close window if specified
|
||
|
if closeWindow is True:
|
||
|
self.closeWindow()
|
||
|
|
||
|
# Close window
|
||
|
def closeWindow(self):
|
||
|
if cmds.window(self.windowName, ex=True) is True:
|
||
|
cmds.evalDeferred('import maya.cmds as cmds; cmds.deleteUI("'+self.windowName+'", wnd=True)')
|
||
|
|
||
|
# Window size
|
||
|
def resizeWindow(self):
|
||
|
if cmds.optionVar(q=self.saveWindowSize) == 0:
|
||
|
cmds.window(self.windowName, e=True, wh=self.windowSize)
|
||
|
|
||
|
# Default settings
|
||
|
def defaultSettings(self, reset=False):
|
||
|
if cmds.optionVar(ex=self.saveWindowSize) == 0:
|
||
|
cmds.optionVar(iv=(self.saveWindowSize, 1))
|
||
|
if reset is True or cmds.optionVar(ex=self.bakeMode) == 0:
|
||
|
cmds.optionVar(iv=(self.bakeMode, 1))
|
||
|
if reset is True or cmds.optionVar(ex=self.setObjSpc) == 0:
|
||
|
cmds.optionVar(iv=(self.setObjSpc, 1))
|
||
|
if reset is True or cmds.optionVar(ex=self.clearSel) == 0:
|
||
|
cmds.optionVar(iv=(self.clearSel, 1))
|
||
|
if reset is True or cmds.optionVar(ex=self.bakePos) == 0:
|
||
|
cmds.optionVar(iv=(self.bakePos, 1))
|
||
|
if reset is True or cmds.optionVar(ex=self.bakeRot) == 0:
|
||
|
cmds.optionVar(iv=(self.bakeRot, 1))
|
||
|
if reset is True or cmds.optionVar(ex=self.bakeScale) == 0:
|
||
|
cmds.optionVar(iv=(self.bakeScale, 1))
|
||
|
|
||
|
# Reset settings
|
||
|
def resetSettings(self, *args):
|
||
|
self.defaultSettings(reset=True)
|
||
|
self.windowSetup()
|
||
|
|
||
|
# Save settings
|
||
|
def saveSettings(self, *args):
|
||
|
cmds.optionVar(iv=(self.saveWindowSize, cmds.menuItem(self.windowSizeMenuItem, q=True, cb=True)))
|
||
|
cmds.optionVar(iv=(self.bakeMode, cmds.radioButtonGrp(self.bakeMode, q=True, sl=True)))
|
||
|
cmds.optionVar(iv=(self.setObjSpc, cmds.checkBoxGrp(self.setObjSpc, q=True, v1=True)))
|
||
|
cmds.optionVar(iv=(self.clearSel, cmds.checkBoxGrp(self.clearSel, q=True, v1=True)))
|
||
|
cmds.optionVar(iv=(self.bakePos, cmds.checkBoxGrp(self.bakePos, q=True, v1=True)))
|
||
|
cmds.optionVar(iv=(self.bakeRot, cmds.checkBoxGrp(self.bakeRot, q=True, v1=True)))
|
||
|
cmds.optionVar(iv=(self.bakeScale, cmds.checkBoxGrp(self.bakeScale, q=True, v1=True)))
|
||
|
|
||
|
# Setup window
|
||
|
def windowSetup(self):
|
||
|
cmds.menuItem(self.windowSizeMenuItem, e=True, cb=cmds.optionVar(q=self.saveWindowSize))
|
||
|
cmds.radioButtonGrp(self.bakeMode, e=True, sl=cmds.optionVar(q=self.bakeMode))
|
||
|
cmds.checkBoxGrp(self.setObjSpc, e=True, v1=cmds.optionVar(q=self.setObjSpc))
|
||
|
cmds.checkBoxGrp(self.clearSel, e=True, v1=cmds.optionVar(q=self.clearSel))
|
||
|
cmds.checkBoxGrp(self.bakePos, e=True, v1=cmds.optionVar(q=self.bakePos))
|
||
|
cmds.checkBoxGrp(self.bakeRot, e=True, v1=cmds.optionVar(q=self.bakeRot))
|
||
|
cmds.checkBoxGrp(self.bakeScale, e=True, v1=cmds.optionVar(q=self.bakeScale))
|
||
|
self.saveSettings()
|
||
|
|
||
|
def initializeWindow(self):
|
||
|
cmds.showWindow(self.windowName)
|
||
|
self.resizeWindow()
|
||
|
cmds.setFocus(self.windowName)
|
||
|
|
||
|
# Create window
|
||
|
def createWindow(self):
|
||
|
# If window already opened, set focus on it
|
||
|
if cmds.window(self.windowName, ex=True) is True:
|
||
|
self.initializeWindow()
|
||
|
return
|
||
|
|
||
|
# Window
|
||
|
cmds.window(self.windowName, t=self.windowTitle, mb=True, wh=self.windowSize)
|
||
|
|
||
|
# Edit Menu
|
||
|
cmds.menu(l="Edit")
|
||
|
cmds.menuItem(l="Save Settings", c=partial(self.saveSettings), ecr=False)
|
||
|
cmds.menuItem(l="Reset Settings", c=partial(self.resetSettings), ecr=False)
|
||
|
cmds.menuItem(d=True)
|
||
|
cmds.menuItem(self.windowSizeMenuItem, l="Save Window Size", c=partial(self.saveSettings), cb=False, ecr=False)
|
||
|
cmds.setParent("..")
|
||
|
|
||
|
# Help Menu
|
||
|
cmds.menu(l="Help", helpMenu=True)
|
||
|
cmds.menuItem(l="Help on "+self.windowTitle, i="help.png", c=partial(self.helpCmd), ecr=False)
|
||
|
cmds.setParent("..")
|
||
|
|
||
|
# Window Form (START)
|
||
|
cmds.formLayout(self.pfx+"windowForm")
|
||
|
|
||
|
# Tab Layout (START)
|
||
|
cmds.tabLayout(self.pfx+"tabLayout", tv=False)
|
||
|
cmds.formLayout(self.pfx+"tabForm")
|
||
|
|
||
|
# Scroll Layout (START)
|
||
|
cmds.scrollLayout(self.pfx+"scrollLayout", cr=True)
|
||
|
cmds.formLayout(self.pfx+"scrollForm")
|
||
|
|
||
|
# Description Frame (START)
|
||
|
cmds.frameLayout(self.pfx+"Description_frameLayout", cll=True, l="Description", li=5, bgs=True, mh=4, mw=0)
|
||
|
|
||
|
# Description Column (START)
|
||
|
cmds.columnLayout(cat=("left", 20), adj=1)
|
||
|
|
||
|
# Description
|
||
|
cmds.text(l="Bakes selected component or current tool pivot transformations on object.", al="left")
|
||
|
cmds.setParent("..")
|
||
|
|
||
|
# Description Column (END)
|
||
|
cmds.setParent("..")
|
||
|
|
||
|
# Settings Frame (START)
|
||
|
cmds.frameLayout(self.pfx+"Settings_frameLayout", cll=True, l="Settings", li=5, bgs=True, mh=4, mw=0)
|
||
|
|
||
|
# Settings Column (START)
|
||
|
cmds.columnLayout(cat=("left", 0), adj=1)
|
||
|
|
||
|
# Space
|
||
|
cmds.checkBoxGrp(self.setObjSpc, l1="Set tools axis to object space", cat=(1, "left", 143), cc=partial(self.saveSettings))
|
||
|
|
||
|
# Clear
|
||
|
cmds.checkBoxGrp(self.clearSel, l1="Set selection type to object", cat=(1, "left", 143), cc=partial(self.saveSettings))
|
||
|
|
||
|
# Separation
|
||
|
cmds.rowLayout(h=3)
|
||
|
cmds.setParent("..")
|
||
|
cmds.rowLayout(h=2, bgc=[0.266, 0.266, 0.266])
|
||
|
cmds.setParent("..")
|
||
|
cmds.rowLayout(h=3)
|
||
|
cmds.setParent("..")
|
||
|
|
||
|
# Bake
|
||
|
cmds.rowLayout(nc=2, cw=(1, 134), cat=(1, "right", 0), ct2=("left", "left"))
|
||
|
cmds.text(l="Bake:")
|
||
|
cmds.radioButtonGrp(self.bakeMode, nrb=2, l="", la2=("Component", "Pivot"), cw3=(4, 110, 110), cc=partial(self.saveSettings))
|
||
|
cmds.setParent("..")
|
||
|
|
||
|
# Transformations
|
||
|
cmds.rowLayout(nc=2, cw=(1, 134), cat=(1, "right", 0), ct2=("left", "left"))
|
||
|
cmds.text(l="Transformations:")
|
||
|
cmds.checkBoxGrp(self.bakePos, l1="Translation", cat=(1, "left", 6), cc=partial(self.saveSettings))
|
||
|
cmds.setParent("..")
|
||
|
|
||
|
cmds.checkBoxGrp(self.bakeRot, l1="Rotation", cat=(1, "left", 143), cc=partial(self.saveSettings))
|
||
|
cmds.checkBoxGrp(self.bakeScale, l1="Scale", cat=(1, "left", 143), cc=partial(self.saveSettings))
|
||
|
|
||
|
# Settings Column (END)
|
||
|
cmds.setParent("..")
|
||
|
|
||
|
# Settings Frame (END)
|
||
|
cmds.setParent("..")
|
||
|
|
||
|
# Scroll Layout (END)
|
||
|
cmds.setParent("..")
|
||
|
cmds.setParent("..")
|
||
|
|
||
|
# Tab Layout (END)
|
||
|
cmds.setParent("..")
|
||
|
cmds.setParent("..")
|
||
|
|
||
|
# Buttons
|
||
|
cmds.formLayout(self.pfx+"Buttons_formLayout", nd=150)
|
||
|
if int(cmds.about(mjv=True)) < 2020:
|
||
|
cmds.iconTextButton(self.pfx+"ApplyAndClose_button", st="textOnly", l=self.runLabel, c=rpartial(self.runCmd, closeWindow=True), fla=False, h=26, rpt=True)
|
||
|
cmds.iconTextButton(self.pfx+"Apply_button", st="textOnly", l="Apply", c=rpartial(self.runCmd, closeWindow=False), fla=False, h=26, rpt=True)
|
||
|
else:
|
||
|
cmds.iconTextButton(self.pfx+"ApplyAndClose_button", st="textOnly", l=self.runLabel, c=partial(self.runCmd, closeWindow=True), fla=False, h=26, rpt=True)
|
||
|
cmds.iconTextButton(self.pfx+"Apply_button", st="textOnly", l="Apply", c=partial(self.runCmd, closeWindow=False), fla=False, h=26, rpt=True)
|
||
|
cmds.iconTextButton(self.pfx+"Close_button", st="textOnly", l="Close", c=partial(self.closeWindow), fla=False, h=26, rpt=True)
|
||
|
cmds.setParent("..")
|
||
|
|
||
|
# Window Form (END)
|
||
|
cmds.setParent("..")
|
||
|
|
||
|
# Window Form Layout
|
||
|
cmds.formLayout(self.pfx+"windowForm", e=True,
|
||
|
af=[(self.pfx+"tabLayout", "top", 0), (self.pfx+"tabLayout", "left", 0), (self.pfx+"tabLayout", "right", 0), (self.pfx+"tabLayout", "bottom", 36)])
|
||
|
|
||
|
cmds.formLayout(self.pfx+"windowForm", e=True,
|
||
|
ac=(self.pfx+"Buttons_formLayout", "top", 5, self.pfx+"tabLayout"),
|
||
|
af=[(self.pfx+"Buttons_formLayout", "left", 5), (self.pfx+"Buttons_formLayout", "right", 5)],
|
||
|
an=(self.pfx+"Buttons_formLayout", "bottom"))
|
||
|
|
||
|
# Tabs Form Layout
|
||
|
cmds.formLayout(self.pfx+"tabForm", e=True,
|
||
|
af=[(self.pfx+"scrollLayout", "top", 2), (self.pfx+"scrollLayout", "left", 2), (self.pfx+"scrollLayout", "right", 2), (self.pfx+"scrollLayout", "bottom", 2)])
|
||
|
|
||
|
# Scroll Form Layout
|
||
|
cmds.formLayout(self.pfx+"scrollForm", e=True,
|
||
|
af=[(self.pfx+"Description_frameLayout", "top", 0), (self.pfx+"Description_frameLayout", "left", 0), (self.pfx+"Description_frameLayout", "right", 0)],
|
||
|
an=(self.pfx+"Description_frameLayout", "bottom"))
|
||
|
|
||
|
cmds.formLayout(self.pfx+"scrollForm", e=True,
|
||
|
ac=(self.pfx+"Settings_frameLayout", "top", 0, self.pfx+"Description_frameLayout"),
|
||
|
af=[(self.pfx+"Settings_frameLayout", "left", 0), (self.pfx+"Settings_frameLayout", "right", 0)],
|
||
|
an=(self.pfx+"Settings_frameLayout", "bottom"))
|
||
|
|
||
|
# Buttons Form Layout
|
||
|
cmds.formLayout(self.pfx+"Buttons_formLayout", e=True,
|
||
|
af=[(self.pfx+"ApplyAndClose_button", "top", 0), (self.pfx+"ApplyAndClose_button", "left", 0)],
|
||
|
ap=(self.pfx+"ApplyAndClose_button", "right", 2, 50),
|
||
|
an=(self.pfx+"ApplyAndClose_button", "bottom"))
|
||
|
|
||
|
cmds.formLayout(self.pfx+"Buttons_formLayout", e=True,
|
||
|
af=(self.pfx+"Apply_button", "top", 0),
|
||
|
ap=[(self.pfx+"Apply_button", "left", 2, 50), (self.pfx+"Apply_button", "right", 2, 100)],
|
||
|
an=(self.pfx+"Apply_button", "bottom"))
|
||
|
|
||
|
cmds.formLayout(self.pfx+"Buttons_formLayout", e=True,
|
||
|
af=[(self.pfx+"Close_button", "top", 0), (self.pfx+"Close_button", "right", 0)],
|
||
|
ap=(self.pfx+"Close_button", "left", 2, 100),
|
||
|
an=(self.pfx+"Close_button", "bottom"))
|
||
|
|
||
|
# Window Setup
|
||
|
self.defaultSettings(reset=False)
|
||
|
self.windowSetup()
|
||
|
self.initializeWindow()
|