What a beautifully concise and articulated article on the logic/maths behind a physics joint chain. Will be very useful for learning about this and re-creating this in your own tools:
https://shirzadbahrami.com/physics-based-animation-undulation/
What a beautifully concise and articulated article on the logic/maths behind a physics joint chain. Will be very useful for learning about this and re-creating this in your own tools:
https://shirzadbahrami.com/physics-based-animation-undulation/
Add this to a file to generate a useful debug.log file!
Useful if you're unable to access a console for printing but still need to know why a file is failing to execute!
Hate Perforce's default Diff window, with lack of syntax highlighting and interactive merge clicking...?
The Problem:
For a while it haunted me that my custom repos/packages weren't auto-completing, not ctrl+mouse hover to see what a function did.
The Fix:
F1 > Preferences: Open Workspace Settings (JSON)
Ensure you have "settings", if not, add it.
Ensure you have "python.analysis.extraPaths" : ["your paths here"], if not, add it.
I came across a pretty cool new zealander who is hosting a lot of his tools on his own personal website. Thought it was worth a link :)
'foo' is 'foo'
True
'foo' == 'foo'
True
'foo' is 'foo2'[:-1]
False
'foo' == 'foo2'[:-1]
True
'foo' is 'Foo'.lower()
False
'foo' == 'Foo'.lower()
True
0 == 0.0
True
0 is 0.0
False
0 is False
False
0 == False
True
not 0
True
Thanks to Joe Hornsby for providing these excellent examples.
The Issue:
// Error: line 1: The undo queue is turned off.
:(
The Fix:
In script editor, on a python tab, run:
cmds.undoInfo(state=True)
:)
Want to know a secret?
"*"*100 takes me about 1 second to type.
Why not wrap it in a print?
print("*"*100)
print("var_a:", var_a)
print("var_b:", var_b)
print("var_c:", var_c)
Result:
//****************************************************************************************************
// var_a: pineapple
// var_b: 64
// var_c: <__main__.Dog object at 0x00000248A53D7748> #
//************************************************************************************************
Isn't that easier to read?
Python generators were something that alluded me for quite a while. A spooky concept that didn't seem necessary. However after using Coroutines in C#, it sort of became a little more clear.
Then, recently I stumbled across an excellent blog post explaining what generators do, how and when to use them:
Check it out!
Here's a useful function for debugging a tools performance.
It's handy to know how long each section of your code is taking without having to sprinkle lots of time.time() functions around. Therefore, wouldn't it be nice to add a decorator to any function that you would like to print the execution time of?
import time
import functools
def record_time(f):
"""Print execution time of wrapped function."""
@functools.wraps(f)
def wrapper(*args, **kwargs):
start = time.time()
try:
return f(*args, **kwargs)
finally:
print(f.__name__, "time taken:", time.time()-start)
return wrapperNow you can just add @record_time to line directly above any function definition, and when the function is called, the time will be printed like so;
@record_time
def jelly():
for i in range(0,10000):
print i
jelly()
# ('jelly', 'time taken:', 2.1070001125335693)
Happy debugging!
Here's an age-old bug:
The Problem:
"My joint recieves a transform in the skeleton hierarchy, and I can't remove it!"
The Fix:
cmds.parent(problem_jnt, new_parent, relative=True)
I came across a useful python debugging library the other day that allows you to print where a function is being called from:
from inspect import stack
def foo():
print(stack()[1][1:4])
def bar():
foo()
What this will do now is whenever foo() is called, it will also now spit out a message:Today I forgot how to get the current frame from a node, something which I wanted to access in order to create a 'turbine' auto-rig component. I tried going into the node editor and created a new 'time' node, but the 'outTime' attribute didn't seem to update with the timeline when I scrubbed through it.
However, it seems that every Maya scene has a persistant 'time' node called time1.
This is the correct node to query when wanting to access the current frame from a node, and as it is persistant in every Maya scene, it's fine to hardcode this name.
I had an issue today where I couldn't save my Maya file as a .mb, and faced the following error:
The Problem:
"File contains unknown nodes or data. To preserve this information, the current file type cannot be changed. //"
This can be caused by having unknown nodes in the scene, usually from an external plugin that you no longer have.
The Fix:
unknown_nodes = cmds.ls(type="unknown")
# Before you delete, check you want to delete these unknown nodes!
cmds.delete(unknown_nodes)
After running this code, you should be able to save as .mb again!
Hello hello,
I just found a really cool bit of code to temporarily disable the Maya viewport whilst running code. Very useful for potentially 'heavy' stuff like caching, baking etc:
cmds.refresh(suspend=True)
doYourFunc()
cmds.refresh(suspend=False)
I feel it's about time to share my custom Maya hotkeys because I've been using them everyday for the past 4+ years in every job I've been in, and they were gifted to me by a friend who gave them to me on my first day, on my first job.
They'll save you hours days of your life! Days i tell you.
# Show geo only (alt+1)
import maya.cmds as mc
currentPanel = mc.getPanel(withFocus = True)
getStatus = mc.modelEditor(currentPanel, q=True, cameras=True)
if getStatus == True:
mc.modelEditor(currentPanel, e=True, allObjects=False)
mc.modelEditor(currentPanel, e=True, polymeshes=True)
else:
mc.modelEditor(currentPanel, e=True, allObjects=True)# Show joints only (alt+2)
import maya.cmds as mc
currentPanel = mc.getPanel(withFocus = True)
getStatus = mc.modelEditor(currentPanel, q=True, cameras=True)
if getStatus == True:
mc.modelEditor(currentPanel, e=True, allObjects=False)
mc.modelEditor(currentPanel, e=True, joints=True)
mc.modelEditor(currentPanel, e=True, handles=True)
else:
mc.modelEditor(currentPanel, e=True, allObjects=True)#Show joints and geo only (alt+3)
import maya.cmds as mc
currentPanel = mc.getPanel(withFocus = True)
getStatus = mc.modelEditor(currentPanel, q=True, cameras=True)
if getStatus == True:
mc.modelEditor(currentPanel, e=True, allObjects=False)
mc.modelEditor(currentPanel, e=True, joints=True)
mc.modelEditor(currentPanel, e=True, polymeshes=True)
else:
mc.modelEditor(currentPanel, e=True, allObjects=True)#Show curves and geo only (alt+4)
import maya.cmds as mc
currentPanel = mc.getPanel(withFocus = True)
getStatus = mc.modelEditor(currentPanel, q=True, cameras=True)
if getStatus == True:
mc.modelEditor(currentPanel, e=True, allObjects=False)
mc.modelEditor(currentPanel, e=True, nurbsCurves=True)
mc.modelEditor(currentPanel, e=True, polymeshes=True)
mc.modelEditor(currentPanel, e=True, cv=True)
mc.modelEditor(currentPanel, e=True, nurbsSurfaces=True)
else:
mc.modelEditor(currentPanel, e=True, allObjects=True)# Show curves only (alt+5)
import maya.cmds as mc
currentPanel = mc.getPanel(withFocus = True)
getStatus = mc.modelEditor(currentPanel, q=True, cameras=True)
if getStatus == True:
mc.modelEditor(currentPanel, e=True, allObjects=False)
mc.modelEditor(currentPanel, e=True, nurbsCurves=True)
mc.modelEditor(currentPanel, e=True, cv=True)
mc.modelEditor(currentPanel, e=True, nurbsSurfaces=True)
mc.modelEditor(currentPanel, e=True, locators=True)
else:
mc.modelEditor(currentPanel, e=True, allObjects=True)
def lerp(input1, input2, step):
""" Linearly interpolation between input1 and input2 given
a value between 0.0 and 1.0.
Args:
input1 (int): starting integer to lerp from.
input2 (int): destination integer to lerp towards.
step (float): float value between 0.0 and 1.0
"""
return (1 - step) * input1 + step * input2
import pymel.tools.mel2py as mel2py
print mel2py.mel2pyStr("""spaceLocator -p 0 0 0;""")
spaceLocator(p=(0, 0, 0))