Project relative paths for external file references
If you work with multiple branches, you might be experiencing issues with Maya preference for resolving Absolut paths before Relative ones for external file references (textures, audio, other Maya files, etc).
If I create a Maya scene in “Branch_A”, integrate that into “Branch_B” and then open the file, Maya will resolve all external file references to their absolute path if possible. This means that all my external file references will point to files in “Branch_A”, even though I’m opening the file in “Branch_B”. Only if Maya can’t resolve the absolute paths, it will try to resolve relative to the current Maya project/workspace.
I wanted to find an easy way to make the file paths relative without:
• Creating custom tools for the creating of ecah external file reference type
• Adding callbacks to handle when each external file reference type was created
• Updating the file path’s with the Maya scene loaded (this would cause Maya to reload them)
Doing a text search and replace within the Maya file (.ma), post save/export, seemed like the simplest idea. I tried it out and it turned out to be easy to do and very fast performing. So here is some of the code involved:
Code that replaces path in the last saved scene:
import os.path
import maya.cmds as mc
import paths
def get_last_save(fileType="ma"):
"""
Get the last saved/exported file. If type is defined, it must match the extension given.
A hack for sure..
"""
if not fileType:
return
lastTempFile = mc.file(query=True, lastTempFile=True)
head, tail = os.path.splitext(lastTempFile)
extensionLength = len(fileType)+1
tail = tail[:extensionLength]
lastSave = ''.join([head, tail])
if fileType:
if tail.lower() != ''.join([".", fileType.lower()]):
return
return lastSave
def make_file_references_relative(*args):
"""
Make external file references project relative, in the last saved file
The Maya file has to be an ASCII file and the external file
references have to be within the current Maya project/workspace.
D:/P4/PRJ/dev/branch//Construction/texture.tga -> Construction/texture.tga
"""
lastSave = get_last_save()
if lastSave:
try:
f = open(lastSave, "r")
text = f.read()
finally:
f.close()
try:
projectPath = paths.project()
removeString = '//'.join((projectPath.replace("\\", "/"), ""))
text = text.replace(removeString, "")
f = open(lastSave, "w")
f.write(text)
finally:
f.close()
Adding callbacks, for this to happen automatically. I’m using the API, since I could not get scriptNode/Job to happen both on save and export:
import maya.OpenMaya as OpenMaya
import repath
userCallbacks = []
class _Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(_Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Callback:
__metaclass__ = _Singleton
def __init__(self):
self.idList = []
def add(self):
try:
if self not in userCallbacks:
userCallbacks.append(self)
except:
pass
def remove(self):
for _id in self.idList:
OpenMaya.MMessage.removeCallback(_id)
try:
userCallbacks.remove(self)
except:
pass
class Save_Relative_Callback(Callback):
def __init__(self):
Callback.__init__(self)
self.create_callbacks()
def create_callbacks(self):
try:
self.idList.append(OpenMaya.MSceneMessage.addCallback(OpenMaya.MSceneMessage.kAfterSave, repath.make_file_references_relative))
self.idList.append(OpenMaya.MSceneMessage.addCallback(OpenMaya.MSceneMessage.kAfterExport, repath.make_file_references_relative))
except:
pass
def add(callback):
callback.add()
Adding the callback in a Maya start up script:
import callback
callback.add(callback.Save_Relative_Callback())
I opted to just store the project relative part of the file path. I tried using a environment variable (E.G. %MY_CURRENT_PROJECT%something/somefile.dds). While this worked great, it does not play nice with 3dsMax or MotionBuilder (who both seem oblivious to the idea of using environment variables in paths), when scenes are FBX’ed across. Using the project relative bit works better.
Of course if your pipeline is setup so that your current project/branch is in a folder that you have mounted to a consistent drive letter (with something like SUBST), you might not have these issues in the first place.
Speed: Maya API vs. CMDS vs. PyMel
If you have to deal with attributes on a large set of objects, learning a little API or at least avoiding PyMel, might be worth a try. Here are some test results and the code run to acquire them:
Searching 44.000 transforms, to see it they have a specific custom attr (where every fourth node has it..)
With API:
Time Taken: 0.839416478551
With CMDS:
Time Taken: 14.0579282427
With PyMel:
Time Taken: 26.2123000353
import maya.OpenMaya as OpenMaya
import maya.cmds as mc
import pymel.core as pm
import time
customAttr = "MyTag"
class Timer():
def __init__(self):
self.start = None
def __enter__(self):
self.start = time.clock()
def __exit__(self, type, value, traceback):
print 'Time Taken: {0}'.format(time.clock() - self.start)
print "\nSearching 44.000 transforms, to see it they have a specific custom attr (where every third node has it..)"
print "\nWith API:"
with Timer():
dagIt = OpenMaya.MItDag(OpenMaya.MItDag.kDepthFirst, OpenMaya.MFn.kTransform)
nodesWithAttrAPI = list()
while not dagIt.isDone():
depNode = OpenMaya.MFnDagNode(dagIt.currentItem())
depNodeAttr = depNode.hasAttribute(customAttr)
if depNodeAttr:
path = OpenMaya.MDagPath()
depNode.getPath(path)
nodesWithAttrAPI.append(path.fullPathName())
dagIt.next()
print "\nWith CMDS:"
with Timer():
nodesWithAttrCMDS = list()
for transform in mc.ls(type="transform"):
if mc.attributeQuery(customAttr, node=transform, exists=True):
nodesWithAttrCMDS.append(transform)
print "\nWith PyMel:"
with Timer():
nodesWithAttrPyMel = list()
for transform in pm.ls(type="transform"):
if pm.attributeQuery(customAttr, node=transform, exists=True):
nodesWithAttrPyMel.append(transform)
Rigging System sandbox
Created a tiddlywiki to have a place to have some process about how to create a rigging system, very much from a code/system development perspective I think – but let’s see where it goes. It’s really just intended for myself and is not a professional display, so it will be unsensored and full of “late nights in the couch at the laptop” spelling errors and giberish. This blog and that little project might merge at some point though, time will tell..
UK Living
So I’ve made the Big Plunge and moved over to the UK. I’ve recently started work as a Senior Technical Character Artist at EA, the studio behind the Harry Potter games series. Very exciting stuff.
I have a pretty central position here that’s very character oriented, so that suits me just fine. At this point I’m quite looking forward to going full circle on a product, that is pretty sure to get to market, as I’ve my share of projects canceled at the end of pre-production. So all in all I’m a happy camper
I’m pretty busy and a bit overwhelmed, being in a new country and all, but hopyfully I will get a chance to post some odds and ends, regardless.
Cheers,
Sune
Code Snippet: Setting a matrix attribute with maya.cmds
Seems you just can’t do it.. So use mel,PyMel or maya.OpenMaya!
However if can’t or won’t do neither, you can use this tiny procedure that will do it for you (using maya.mel):
# The proc
import maya.cmds as mc
import maya.mel as mel
def setMatrixAttr(obj, attr, matrixList):
matrixString = ''
for element in matrixList:
matrixString = matrixString + str(element) + ''
mel.eval("setAttr -type \"matrix\" " + obj + "." + attr + matrixString)
# Example of usage
matrix = mc.getAttr(’LeftLeg.worldInverseMatrix’)
setMatrixAttr('skinCluster51', 'bindPreMatrix[103]', matrix)
New Showreel!
Hi Gang,
I’ve setup a presentations page with my new Showreel, resume and so on:
Do Check it out.. You know you want to!
Awesome book for the “Coding TD”
Just wanted to plug an excellent book I’m… Wait! Not even done reading?? That’s right, it’s that good – for me at least.
You know I often feel like I’m “hacking my way” thorugh some of the more computery, code and math related sides to being a character TD, wishing I could dedicate a whole decade to just getting to the bottom of some topic. And I see a lot of people around me “hacking their way” as well. Of course we all have different backgrounds and holes in them too. Alas, so little time so much to learn
While I have read my share of books on the topic of coding, MEL, Python, Object Oriented Design etc. and those books have taught me a lot, a “certified” coder from my last gig recommended “Code Complete 2″. It’s about the discipline of “Code Construction” and is language independent. This book is om some respects a real eye opener and tells basic stuff you know you really need to understand, but in a way that makes you wonder – “why you didn’t figure that out by yourself already”. Another thing is this if you have several people working on the same code base this book can serve as a common guide or at least common point of reference, to figure out how you want to work.
Of course it might not be your cup of tea.. or I might just have exposed myself as an insane coding noob
I have only read half of this book, but for me I feel wiser and more prepared! Check it out
Open for Business!
Last week the production company I worked for unfortunately folded.. As for the fate of the game we were working on, I’m not sure what is gonna happen. So once I find myself I the process of doing the reel -cv – looking for work thing.
So if anyone has any interesting offers or leads do let me know. I’m based in Denmark, but will definitely travel or relocate for the right gig. Freelance is welcome as well of course! I’ll again post once I got my reel together.
Hope everyone is having a nice summer,
Sune
Interstellar Marines!
Hi.
Today we (The Company I work for) launched our new website: Interstellarmarines.com
Here you can check out a lot of stuff about our game, marketing strategy and some developer/behind the scenes stuff. I will probably be posting most of my rigging related stuff in there, for the next period of time.
Take a look at our trailer – All in engine:
On the site there is the first part of a rigging tutorial about setting up arms and shoulder: Setting up the shoulders and arms of the Marine part 1
The tutorial is not the most advanced, but more geeky stuff should follow!
Oh and do show your support and sign up as a member – it’s free
