Deepen your understanding while checking the contents of your own tools one by one, and use them for future tool development. Thoroughly understand that I've been through because I've been working with copy and paste until now. I'm writing a script in the same way and it works somehow, so I hope it helps people who end up with.
Slows the camera movement speed in Maya and allows fine adjustment of the camera. Maya cameras can be subtly fast, which can be a bit annoying for delicate camera work. Normally, it is adjusted with Tool Settings, but it is difficult to use because there are settings for each camera tool, so I unified it. Turn the dial to the left to slow down the speed, and turn it to the right to speed up, and you can switch between camera tools.
** Operating environment: Maya2019.3, Maya2020.1 ** Since I am using Pyside2, it will not work before 2016.
cameraSpeedEditor.py
# -*- coding: utf-8 -*-
from maya.app.general.mayaMixin import MayaQWidgetBaseMixin
from PySide2 import QtWidgets
from PySide2.QtCore import Qt
from maya import cmds
class Widget(QtWidgets.QWidget):
def __init__(self):
#Call parent method
super(Widget, self).__init__()
#Place grid layout
layout = QtWidgets.QGridLayout(self)
#Description label
labelWidget = QtWidgets.QLabel(u'Adjust the speed of the camera\n\n ← slow camera speed adjustment speed →')
labelWidget.setAlignment(Qt.AlignCenter)
layout.addWidget(labelWidget,0,0,1,-1)
#Dial widget
self.camDial = QtWidgets.QDial()
self.camDial.setRange(0, 100)
self.camDial.setValue(50)
self.camDial.setNotchesVisible(True)
self.camDial.sliderReleased.connect(self.setCamSpeed)
layout.addWidget(self.camDial,1,0,1,-1)
#Check super slow mode
self.checkWidget = QtWidgets.QCheckBox(u'Super slow')
self.checkWidget.setChecked(False)
self.checkWidget.stateChanged.connect(self.setCamSpeed)
layout.addWidget(self.checkWidget,2,0)
#Camera tool combo box
setCamLabel = QtWidgets.QLabel('set Camera tool:')
setCamLabel.setAlignment(Qt.AlignRight)
layout.addWidget(setCamLabel,3,0)
selCamItem = QtWidgets.QComboBox(self)
selCamItem.addItem('tumble')
selCamItem.addItem('track')
selCamItem.addItem('dolly')
selCamItem.addItem('boxZoomSuper')
selCamItem.addItem('roll')
selCamItem.addItem('yawPitch')
selCamItem.activated[str].connect(self.setTool)
layout.addWidget(selCamItem,3,1)
#Reset button
resetButton = QtWidgets.QPushButton(u'reset')
resetButton.clicked.connect(self.resetCamSpeed)
layout.addWidget(resetButton,4,0,1,-1)
#Camera speed set
def setCamSpeed(self):
#Calculate speed numbers
value = float(self.camDial.value()) **3*0.0000072+0.1
if self.checkWidget.isChecked():
value = value /10
#Set the calculated value
cmds.tumbleCtx( 'tumbleContext' ,e=True ,ts=value)
cmds.trackCtx( 'trackContext' ,e=True ,ts=value)
cmds.dollyCtx( 'dollyContext' ,e=True ,s =value)
cmds.boxZoomCtx('boxZoomContext' ,e=True ,zs=value)
cmds.rollCtx( 'rollContext' ,e=True ,rs=value)
cmds.orbitCtx( 'azimuthElevationContext' ,e=True ,orbitScale=value)
cmds.orbitCtx( 'yawPitchContext' ,e=True ,orbitScale=value)
#Show what you have set
print ( '# Camera speed is '+str(value)+' !\n'),
#Camera toolset
def setTool(self, selectTool):
cmds.setToolTo('%sContext' %(selectTool))
print ( 'Set %s Tool !\n' %(selectTool)),
#Camera speed reset
def resetCamSpeed(self):
#Reset the value of each camera to the default
cmds.tumbleCtx( 'tumbleContext' ,e=True ,ts=1)
cmds.trackCtx( 'trackContext' ,e=True ,ts=1)
cmds.dollyCtx( 'dollyContext' ,e=True ,s =1)
cmds.boxZoomCtx('boxZoomContext' ,e=True ,zs=1)
cmds.rollCtx( 'rollContext' ,e=True ,rs=1)
cmds.orbitCtx( 'azimuthElevationContext' ,e=True ,orbitScale=1)
cmds.orbitCtx( 'yawPitchContext' ,e=True ,orbitScale=1)
self.camDial.setValue(50)
self.checkWidget.setChecked(False)
print ( '# Camera speed is Default !\n'),
class MainWindow(MayaQWidgetBaseMixin, QtWidgets.QMainWindow):
def __init__(self):
#Call parent method
super(MainWindow, self).__init__()
#Specify the name and size of the window
self.setWindowTitle('Camera Speed editor')
self.resize(200, 250)
#Instance Widget and place it in window
widget = Widget()
self.setCentralWidget(widget)
def closeEvent(self, event):
#Perform camera speed reset when window is closed
widget = Widget()
widget.resetCamSpeed()
def main():
#Window display
window = MainWindow()
window.show()
#Processing when called in main
if __name__ == "__main__":
main()
From here, I would like to explain how each code works, starting from the beginning, while understanding for myself.
# -*- coding: utf-8 -*-
If you use Japanese in the code, you should put it in. See here for details. It seems rather deprecated in Python3. Maya is still 2.7, so I'll add it just in case.
from maya.app.general.mayaMixin import MayaQWidgetBaseMixin
from PySide2 import QtWidgets
from PySide2.QtCore import Qt
from maya import cmds
Import each library to use. Python has a lot of libraries, so you can do various things by using it. I think it's one of the advantages of using Python instead of MEL.
from 〇〇 import △△
means to bring △△ in 〇〇.
Functions of each library.
** MayaQWidgetBaseMixin **: Used to set the parent-child relationship of the window
** QtWidgets, Qt **: PySide, UI related functions
** cmds **: maya command
The 4th line from maya import cmds
is a reference of maya,
It is described as ʻimport maya.cmds as cmds`.
I'm doing this because it's more beautiful to have them all from. What you are doing is probably the same.
class Widget(QtWidgets.QWidget):
def __init__(self):
#Call parent method
super(Widget, self).__init__()
...
class。 The explanation of class is broken here. It's complicated, so please understand it in a book. The place where I stumbled the most when I was doing Python. I wonder if I should get used to it while using it.
I also thought that I was studying myself, It is recommended that you read a book because there is a limit to using only online articles. Personally, [Introduction to O'Reilly Japan Python3](https://www.amazon.co.jp/%E5%85%A5%E9%96%80-Python-3-Bill-Lubanovic/dp/4873117380/ref = sr_1_1? __ mk_ja_JP =% E3% 82% AB% E3% 82% BF% E3% 82% AB% E3% 83% 8A & dchild = 1 & keywords =% E5% 85% A5% E9% 96% 80python3 & qid = 1598490946 & sr = 8-1 ) Is very easy to understand. I'm still reading. I think it is for beginners to intermediates.
[Introduction to O'Reilly Japan Python3](https://www.amazon.co.jp/%E5%85%A5%E9%96%80-Python-3-Bill-Lubanovic/dp/4873117380/ref=sr_1_1? __mk_ja_JP =% E3% 82% AB% E3% 82% BF% E3% 82% AB% E3% 83% 8A & dchild = 1 & keywords =% E5% 85% A5% E9% 96% 80python3 & qid = 1598490946 & sr = 8-1) [Illustration] What is object-oriented? (Meaning of class method instance)
class Widget(QtWidgets.QWidget):
Inherit ** QtWidgets.QWidget ** imported from the library to ** Widget **. It's like preparing to customize the base of PySide2 for yourself.
def __init__(self):
__init__
Special method. Initialize the part that is called first when the instance is created.
You'll see it most often when you look at the class code.
self
First argument.
It works for other than self, but by convention ** self ** is always used.
These rules are summarized in the document *** PEP 8 ***, so please refer to it.
Perhaps if you are self-taught on the net, you will not be able to reach these rules and you will be able to create your own rules (self-discipline)
Understanding Python self and init What is Python self? Explanation of usage and precautions Understanding [Python Coding Standards] PEP8
#Call parent method
super(Widget, self).__init__()
Another confusing description. I didn't understand it at first, but it's nothing if I understand it.
Inherit ** QtWidgets.QWidget ** to ** Widget ** and
If you create an initialization method with __init__
, the initialization method of the parent (QtWidgets.QWidget) will not be called.
So, put this description and call the parent initialization method.
By the way, this description was necessary in python2 series, but in 3 series, super () .__ init__ ()
is good. simple.
I'm wondering when Maya will switch to 3 series. ..
[Python] class inheritance (super) How to use Python's super () function
To better understand what the class is doing, let's illustrate what's going on. 2.From ~ imports PySide2.QtWidgets 7. Inherit the imported QtWidgets QWidget with the name Widget 8. Create initialization method in Widget class 10. Call the initialization method of the imported QtWidgets.QWidget 13 or later Create UI layout and functions
There are still many letters, so I made a simple illustration.
In this way, you can make an instance copy of the original blueprint (familiar with Maya) and override (overwrite) the arms, legs, and colors to get the shape you want.
So, if you overwrite it with __init__
, the original __init__
will not be called, so you need super
.
Well, the explanation of class has become long, but I will finally create the UI from now on.
#Place grid layout
layout = QtWidgets.QGridLayout(self)
Create QGridLayout. Buttons and labels will be placed in this grid layout.
#Description label
labelWidget = QtWidgets.QLabel(u'Adjust the speed of the camera\n\n ← slow camera speed adjustment speed →')
Added labels to grid layout.
When using Japanese such as ʻu'character', prefix it with ** u **. You can start a new line with
\ n`.
labelWidget.setAlignment(Qt.AlignCenter)
Place the created label widget in the center.
layout.addWidget(labelWidget,0,0,1,-1)
Label widget grid layout 0th row, 0th column, 1st row length, **-1 column length ** If you want to use it from the specified location to the end, use ** -1 **.
In this way, you can specify from which position in the row or column how long it is.
#Dial widget
self.camDial = QtWidgets.QDial()
self.camDial.setRange(0, 100)
self.camDial.setValue(50)
self.camDial.setNotchesVisible(True)
self.camDial.sliderReleased.connect(self.setCamSpeed)
layout.addWidget(self.camDial,1,0,1,-1)
Create a dial widget.
This time, self.camDial
and self are added because I want to pull the numerical value from another place.
Specify the range from 0 to 100. Changed the default value to 50. Add scale with setNotchesVisible
.
With self.camDial.sliderReleased.connect (self.setCamSpeed)
,
Set self.setCamSpeed
to be executed when the mouse button is released.
#Check super slow mode
self.checkWidget = QtWidgets.QCheckBox(u'Super slow')
self.checkWidget.setChecked(False)
self.checkWidget.stateChanged.connect(self.setCamSpeed)
layout.addWidget(self.checkWidget,2,0)
Create a check widget.
Specify that the default is unchecked and that self.setCamSpeed
is executed when the checked state is changed.
The layout is arranged in the 2nd row and 0th column. If both lengths are 1, you can leave it blank.
#Camera tool combo box
setCamLabel = QtWidgets.QLabel('set Camera tool:')
setCamLabel.setAlignment(Qt.AlignRight)
layout.addWidget(setCamLabel,3,0)
selCamItem = QtWidgets.QComboBox(self)
selCamItem.addItem('tumble')
selCamItem.addItem('track')
selCamItem.addItem('dolly')
selCamItem.addItem('boxZoomSuper')
selCamItem.addItem('roll')
selCamItem.addItem('yawPitch')
selCamItem.activated[str].connect(self.setTool)
layout.addWidget(selCamItem,3,1)
selCamItem = QtWidgets.QComboBox (self)
Create a combo box.
Add multiple camera tool items with ʻaddItem. I want to use the name as it is, so it conforms to the description of Maya's camera tool.
selCamItem.activated [str] .connect (self.setTool)When the activity changes Execute by passing ** string ** of addItem to
self.setTool`.
#Reset button
resetButton = QtWidgets.QPushButton(u'reset')
resetButton.clicked.connect(self.resetCamSpeed)
layout.addWidget(resetButton,4,0,1,-1)
Creating a reset button. Set the operation settings and layout in the same way as others.
This completes the UI creation.
Create the operation contents of ** ~ .connect ** that appeared when creating the UI.
#Camera speed set
def setCamSpeed(self):
#Calculate speed numbers
value = float(self.camDial.value()) **3*0.0000072+0.1
if self.checkWidget.isChecked():
value = value /10
#Set the calculated value
cmds.tumbleCtx( 'tumbleContext' ,e=True ,ts=value)
cmds.trackCtx( 'trackContext' ,e=True ,ts=value)
cmds.dollyCtx( 'dollyContext' ,e=True ,s =value)
cmds.boxZoomCtx('boxZoomContext' ,e=True ,zs=value)
cmds.rollCtx( 'rollContext' ,e=True ,rs=value)
cmds.orbitCtx( 'azimuthElevationContext' ,e=True ,orbitScale=value)
cmds.orbitCtx( 'yawPitchContext' ,e=True ,orbitScale=value)
#Show what you have set
print ( '# Camera speed is '+str(value)+' !\n'),
Get the status of dials and checkboxes, Reflect the calculated value in each camera tool.
value = float (self.camDial.value ()) ** 3 * 0.0000072 + 0.1
Convert from dial value to camera speed value.
Why is it such a strange calculation formula, but when I adjusted it to move just right, it became like this.
ʻIf ~` reduces ** value ** to 1/10 if super slow mode is checked.
# Set the calculated value below
Reflect the calculated value in the value of each camera tool
The reason why there are many wasted margins is to align the rows and make them easier to see.
It seems that PEP8 is not recommended, but I dare to ignore it. How is it actually?
print ('hogehoge'),
The last **, (comma) ** are added for display on the Maya command line.
Because warnings are colored and a little overwhelming.
For now, it's a mystery why it can be displayed on the command line with a comma. I wonder if it's a Maya specification.
#Camera toolset
def setTool(self, selectTool):
cmds.setToolTo('%sContext' %(selectTool))
print ( 'Set %s Tool !\n' %(selectTool)),
** [str] ** received from selCamItem.activated [str] .connect (self.setTool)
,
cmds.setToolTo ('% sContext'% (selectTool))
Switch with this command.
% s replaces% (Honyara)
Example:
'%sContext' %('tumble')
→ 'tumbleContext'
#Camera speed reset
def resetCamSpeed(self):
#Reset the value of each camera to the default
cmds.tumbleCtx( 'tumbleContext' ,e=True ,ts=1)
cmds.trackCtx( 'trackContext' ,e=True ,ts=1)
cmds.dollyCtx( 'dollyContext' ,e=True ,s =1)
cmds.boxZoomCtx('boxZoomContext' ,e=True ,zs=1)
cmds.rollCtx( 'rollContext' ,e=True ,rs=1)
cmds.orbitCtx( 'azimuthElevationContext' ,e=True ,orbitScale=1)
cmds.orbitCtx( 'yawPitchContext' ,e=True ,orbitScale=1)
self.camDial.setValue(50)
self.checkWidget.setChecked(False)
print ( '# Camera speed is Default !\n'),
Restore camera settings and UI to defaults.
With the above, the operation when operating the widget has been created.
class MainWindow(MayaQWidgetBaseMixin, QtWidgets.QMainWindow):
def __init__(self):
#Call parent method
super(MainWindow, self).__init__()
#Specify the name and size of the window
self.setWindowTitle('Camera Speed editor')
self.resize(200, 250)
#Instance Widget and place it in window
widget = Widget()
self.setCentralWidget(widget)
Inheriting ** MayaQWidgetBaseMixin ** and ** QtWidgets.QMainWindow ** ** MayaQWidgetBaseMixin ** is a feature that prevents windows from going under the main Maya window. I used to use shiboken etc., but it feels good to be much simpler.
New! Parent-child relationship in Maya windows MayaQWidgetBaseMixin!
Specify the window title and window size. Place the way jet you made earlier in the center of the window.
def closeEvent(self, event):
#Perform camera speed reset when window is closed
widget = Widget()
widget.resetCamSpeed()
Reset the camera speed when the window is closed.
You can use def closeEvent (self, event):
to add additional behavior when the window is closed.
Now you have created the UI and main functions.
def main():
#Window display
window = MainWindow()
window.show()
If you hit main () and the command, a window will be displayed and you can execute the program.
#Processing when called in main
if __name__ == "__main__":
main()
This is also like magic. Do not run the program when importing. If you copy and paste the entire code into a script editor and execute it, the program will start.
At first I thought it was just a memo, but it has become quite long. If I add something I don't understand while writing in places, it's like this.
It would be good for me to leave an article like this every time I write a tool. After all, I think that studying is something that you can learn by teaching → trying → teaching.
There may be many places that cannot be reached, but please forgive me. I would appreciate it if you could tell me if there are any mistakes.
Below is the site link that I used as a reference.
The name of the character code "Are" written at the beginning of the sentence in Python (something like UTF-8) Introduction to Python Modules and Imports from [Illustration] What is object-oriented? (Meaning of class method instance) Understanding Python self and init What is Python self? Explanation of usage and precautions Understanding [Python Coding Standards] PEP8 [Python] Class Inheritance (super) How to use Python's super () function new! Parent-child relationship in Maya windows MayaQWidgetBaseMixin! [Python] if name == What is'main':?
Recommended Posts