-
Notifications
You must be signed in to change notification settings - Fork 2
/
bakeCam.py
182 lines (141 loc) · 6.2 KB
/
bakeCam.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
# Author : HYUK KO | [email protected] | github.com/kohyuk91
"""
import bakeCam
try:
bc.close()
bc.deleteLater()
except:
pass
bc = bakeCam.BakeCam()
bc.show()
"""
import maya.cmds as mc
import maya.mel as mm
import maya.OpenMayaUI as omui
try:
from PySide import QtGui, QtCore
import PySide.QtGui as QtWidgets
import shiboken
except ImportError:
from PySide2 import QtGui, QtCore, QtWidgets
import shiboken2 as shiboken
import os
import re
from functools import wraps
# Decorator for undo support.
def openCloseChunk(func):
@wraps(func)
def wrapper(*args, **kargs):
action = None
try:
mc.undoInfo(openChunk=True)
action = func(*args, **kargs)
except:
print(traceback.format_exc())
pass
finally:
mc.undoInfo(closeChunk=True)
return action
return wrapper
class BakeCam(QtWidgets.QDialog):
@classmethod
def maya_main_window(cls):
main_window_ptr = omui.MQtUtil.mainWindow()
return shiboken.wrapInstance(long(main_window_ptr), QtWidgets.QWidget)
def __init__(self):
super(BakeCam, self).__init__(self.maya_main_window())
self.setWindowTitle("Bake Cam")
self.setWindowFlags(self.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint)
self.create_widgets()
self.create_layouts()
self.create_connections()
self.loadSettings()
def create_widgets(self):
self.options_resetScale_cb = QtWidgets.QCheckBox("Reset Scale")
self.options_resetScale_cb.setChecked(True)
self.bake_reparentToWorld_btn = QtWidgets.QPushButton("BAKE CAMERA")
self.bake_reparentToWorld_btn.setStyleSheet("QPushButton {background-color: #EC5f67;}")
def create_layouts(self):
options_groupbox = QtWidgets.QGroupBox("Options")
options_layout = QtWidgets.QGridLayout()
options_layout.addWidget(self.options_resetScale_cb, 0, 0)
options_groupbox.setLayout(options_layout)
bake_groupbox = QtWidgets.QGroupBox()
bake_layout = QtWidgets.QGridLayout()
bake_layout.addWidget(self.bake_reparentToWorld_btn, 0, 0)
bake_groupbox.setLayout(bake_layout)
main_layout = QtWidgets.QVBoxLayout(self)
main_layout.addWidget(options_groupbox)
main_layout.addWidget(bake_groupbox)
def create_connections(self):
#self.bake_duplicate_btn.clicked.connect(lambda: self.bake("duplicate"))
self.bake_reparentToWorld_btn.clicked.connect(lambda: self.bake("reparentToWorld"))
def getObjectType(self, sel):
selShape = mc.listRelatives(sel, fullPath=True, shapes=True) # Get selected object's shape node.
objectType = mc.objectType(selShape) # Get object type.
return objectType
def saveSettings(self):
mc.optionVar(intValue=("bakeCam_options_resetScale_cb", self.options_resetScale_cb.isChecked()))
def loadSettings(self):
if mc.optionVar(exists="bakeCam_options_resetScale_cb"):
self.options_resetScale_cb.setChecked(True) if mc.optionVar(q="bakeCam_options_resetScale_cb") else self.options_resetScale_cb.setChecked(False)
@openCloseChunk
def bake(self, method):
"""
Bake Method
Duplicate:
Reparent to World: If the camera you want to bake has custom attributes or connections you do not want to break, click this.
"""
sel = mc.ls(selection=True, long=True)
if len(sel) != 1: # Check if only one object is selected.
mc.warning("You must select a single camera.")
return
if self.getObjectType(sel) != "camera": # Check if selected object's type is camera.
mc.warning("You must select a single camera.")
return
if mc.listRelatives(sel, parent=True) == None: # Check if selected camera's parent is 'world'.
mc.warning("Selected camera is already a child of the parent, 'world'.")
return
selCamTrans = sel[0]
selCamShape = mc.listRelatives(selCamTrans, shapes=True, fullPath=True)[0]
minTime = mc.playbackOptions(q=True, minTime=True)
maxTime = mc.playbackOptions(q=True, maxTime=True)
#if method == "duplicate":
# dupCamTrans, dupCamShape = mc.camera(name=selCamTrans)
# print "WIP"
if method == "reparentToWorld":
worldLoc = mc.spaceLocator(name="worldLoc")[0]
selCamRotateOrder = mc.getAttr(selCamTrans+".rotateOrder")
mc.setAttr(worldLoc+".rotateOrder", selCamRotateOrder)
pc = mc.parentConstraint(selCamTrans, worldLoc, maintainOffset=False)
mc.ogs(pause=True)
mc.bakeResults(worldLoc, simulation=True, attribute=["tx","ty","tz","rx","ry","rz"], time=(minTime, maxTime))
mc.ogs(pause=True)
mc.delete(pc) # Delete parent constraint.
# Delete selected camera's translation and rotation attributes.
mm.eval('cutKey -time ":" -hierarchy none -at "tx" -at "ty" -at "tz" -at "rx" -at "ry" -at "rz" {cam};'.format(cam=selCamTrans))
# Unparent selected camera to world
unparentedSelCamTrans = mc.parent(selCamTrans, world=True)[0]
# Cut worldLoc transform keys.
mm.eval('cutKey -time ":" -hierarchy none -at "tx" -at "ty" -at "tz" -at "rx" -at "ry" -at "rz" {loc};'.format(loc=worldLoc))
# Paste worldLoc transform keys to unparentedSelCamTrans
mm.eval('pasteKey -option replaceCompletely -copies 1 -connect 0 -timeOffset 0 -floatOffset 0 -valueOffset 0 "{cam}";'.format(cam=unparentedSelCamTrans))
mc.delete(worldLoc)
# If Reset Scale is checked, set unparentedSelCamTrans scaleXYZ value to 1.
if self.options_resetScale_cb.isChecked():
mc.setAttr(unparentedSelCamTrans+".sx", 1)
mc.setAttr(unparentedSelCamTrans+".sy", 1)
mc.setAttr(unparentedSelCamTrans+".sz", 1)
# Close window
self.close()
self.deleteLater()
# Save checkbox toggle state
self.saveSettings()
if __name__ == "__main__":
try:
bc.close()
bc.deleteLater()
except:
pass
bc = BakeCam()
bc.show()