Autodesk just recently released Maya 2017. Which means another round of updates for my two available plugins; sePushPullConstraint and seUVBlendShape. The big change this time around was the update to Qt version 5. Though the conversion from version 4 to 5 is not that difficult, it does make it incompatible between the two versions. Thankfully, someone has already wrote a nice Python module to make the code work in both. So for those tools that are using PyQt and want to make their user interfaces compatible, take a look at this handy code.
That’s all the updates for now! Enjoy!
If you have used dock widgets in Qt, you may have docked with with tabs for easy stacking of other dock widgets. One handy feature of the tabs is when you click on the active tab, it will collapse the dock area and clicking a tab will expand it again. One thing however that is missing in Qt is a way to trigger this behavior yourself. If you simply hide the dock widget, the tab will disappear so that is no use. There is no slot or function to control the action. After lots of investigating I came to the conclusion that there is some custom Qt event handling specifically for mouse button clicks on a dock widget tab. Triggering this event causes some way to hide the dock but keep the tabs using some other special method. The Qt source code doesn’t expose this either so there is no way to find what is happening and recreate it yourself.
But I didn’t give up, I wanted my tabbed dock widgets to be collapsed upon opening the UI to keep tools that are not needing to be seen from distracting the user. So how can I trigger this behavior programmatically? Well, I simulate a mouse button click event on the tab so I trick Qt on thinking the user did click on the tab! By creating my own QMouseEvent, I send the event to the tab bar with the position of where the “click” happened and let the tab bar handle what it does, which is collapse/expand the dock widget. Simple!
Below is the code snippet I created to reproduce a mouse button press event over the tab that has the same text. Simply pass it a QMainWindow instance and the text on the tab you want to “click” on. The return will be True if the tab was found and event was sent otherwise False. Now you can too programmatically trigger this feature which should have been included in the first place. By the way, this is for Qt 4.8, maybe future versions will support this.
def simulateDockTabClick(window, tabText):
Simulates a left mouse click event on a dock widget tab with the given
text. A possible use for this function is to recreate the effect of
collapsing a tabbed dock area as Qt doesn't expose a method to get this
:param window: The QMainWindow widget to use
:type window: QtGui.QMainWindow
:param tabText: the text in the tab to "click" on
:type tabText: str
:returns: True if dock tab was found and event was sent, else False if
no tab was found with the text.
assert isinstance(window, QtGui.QMainWindow), \
'Widget is not a QMainWindow instance'
for child in window.children():
if isinstance(child, QtGui.QTabBar):
for i in range(child.count()):
if child.tabText(i) == tabText:
tabPosition = child.tabRect(i).center()
event = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonPress,
I needed a way to get the geometry index on a deformer based on the deforming shape name. Rather than trying to trace the connections in the dependency graph, Maya’s API has a much easier and faster method. This is also better than using the deformer command for the information since the command does not support returning full path names for comparison. So I thought I would share it to anyone who may want to add it to their own collection of tools.
import maya.OpenMaya as OM
import maya.OpenMayaAnim as OMA
import maya.cmds as cmds
def getDeformerGeometryIndex(deformer, geometry):
Return the geometry index for the deformer for the given geometry.
If multiple shapes exist in the base geometry, the first one is used.
if not cmds.objectType(geometry, isa='shape'):
shapes = cmds.listRelatives(geometry, ni=True, s=True, f=True)
if not shapes:
raise TypeError("Geometry '%s' does not have a shape" % geometry)
# get the first shape and use it
geometry = shapes
selList = OM.MSelectionList()
oDeformer = OM.MObject()
oGeo = OM.MObject()
fnDeformer = OMA.MFnGeometryFilter(oDeformer)
A friend and former co-worker Chad Vernon does it again with his awesome skills. This time Chad has released a free tool to generate front of chain corrective shapes on an already deformed mesh.
Meaning, if you are trying to find an easy way to sculpt a corrective shape on a posed mesh, this will create a mesh that can be used in a blend shape at the beginning of your deformation chain which you can drive that shape when the other deformations put it in that pose. It makes doing corrective shapes so much easier than trying to guess or having a custom additive blend shape deformer.
What really makes Chad a nice guy is he provided the code in all python for you to look and see. Thanks Chad, I’ll be sure to use this soon! So go over there and get it now!
Ok, so I had this MEL script sitting around a long time and wanted to share before it gets too out of date. This is the shape taper script that is in my demo reel that splits symmetrical set driven keys into left and right asymmetrical shapes on joints.
What this script is for is you have a single attribute that drives a symmetrical shape on your bone based facial rig. But when you want create left and right tapered shapes, it becomes very difficult to do this. So that is where this tool comes in. Once you have the symmetrical shape created, you can split it very easily with great control so you have perfect left and right shapes, which when combined will look just like the symmetrical one.
I made this script a few years ago, so some of my bad coding still exists in there so forgive me. But it’s free to use and recently fixed to work with 2011 of Maya. To see an example watch my demo reel about 2/3 way through and you will see what it can do.