Friday, April 4, 2014

Setting the correct Pixel Aspect in Maya

0 comments
I just recently ran into the issue of setting the pixelAspectRatio of the defaultResolution to a value that wasn't what maya was setting based on the width and height. I couldn't really find any answers on the net so I figure i'd put my answer up.

 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
import maya.cmds as cmds


def setResolution(width=1920, height=1080, pixelAspect=1.0):
    '''
    Sets render resolution properly.

    @param width- The width of the resolution.
    @param height- The width of the resolution.
    @param pixelAspect- The pixel aspect to set the defaultResolution to.

    Returns None
    '''
    #Calculates the device aspect since pixel aspect isn't an actual attribute.
    device_aspect = float(width * pixelAspect)/float(height)

    #Set the Lock Device Aspect Ratio. IMPORTANT!
    #If you don't do this it won't work.
    cmds.setAttr("defaultResolution.lockDeviceAspectRatio", 1)

    #Set width, height, and aspect ratio.
    cmds.setAttr("defaultResolution.width", width)
    cmds.setAttr("defaultResolution.height", height)
    cmds.setAttr("defaultResolution.deviceAspectRatio", device_aspect)

if __name__ == "__main__":
    setResolution(width=3168, height=2376, pixelAspect=2.0)

Hope this saves someone the time it took me to figure this out!

-Chris

Monday, May 20, 2013

cdSnap: PyQt style

0 comments

So I learned some pyqt and voila, here's cdSnap. It should handle most of your ikfk snapping/space switching/rotation order snapping needs. I really like how it can bake keys in multiple ways depending on your needs. Let me know if it works or doesn't work for you!

You'll first want to install pyqt, I recommend Nathan Horne's site to download his installers for windows.

Second, either run it the script in the python script editor or type after installing it your maya scripts directory:
import cdSnapUI
reload(cdSnapUI)
cdSnap = cdSnapUI.cdSnapUI()
cdSnap.show()






Download it!

Wednesday, April 10, 2013

Getting dat Matrix: Maya Python API 2.0

3 comments
So I've been delving in the Maya Python API lately and having lots of fun with matrices. I couldn't find a lot of info for using API 2.0 with matrices.

In this script example, there are two functions, one that gets a worldMatrix of an object and one that decomposes a matrix into translation, rotation, and scale. I think I've annotated it pretty well, but a big thing to note is that if you freeze translation on an object, it won't return the correct world values for the object you input.

Just change the nodeName to your object name and run the script.

import maya.cmds as cmds
import maya.api.OpenMaya as OpenMaya
import math
import sys

def getMatrix(node):
 '''
 Gets the world matrix of an object based on name.
 '''
 #Selection list object and MObject for our matrix
 selection = OpenMaya.MSelectionList()
 matrixObject = OpenMaya.MObject()
 
 #Adding object
 selection.add(node)
 
 #New api is nice since it will just return an MObject instead of taking two arguments.
 MObjectA = selection.getDependNode(0)
 
 #Dependency node so we can get the worldMatrix attribute
 fnThisNode = OpenMaya.MFnDependencyNode(MObjectA)
 
 #Get it's world matrix plug
 worldMatrixAttr = fnThisNode.attribute( "worldMatrix" )
 
 #Getting mPlug by plugging in our MObject and attribute
 matrixPlug = OpenMaya.MPlug( MObjectA, worldMatrixAttr )
 matrixPlug = matrixPlug.elementByLogicalIndex( 0 )
 
 #Get matrix plug as MObject so we can get it's data.
 matrixObject = matrixPlug.asMObject(  )
 
 #Finally get the data
 worldMatrixData = OpenMaya.MFnMatrixData( matrixObject )
 worldMatrix = worldMatrixData.matrix( )
 
 return worldMatrix

def decompMatrix(node,matrix):
 '''
 Decomposes a MMatrix in new api. Returns an list of translation,rotation,scale in world space.
 '''
 #Rotate order of object
 rotOrder = cmds.getAttr('%s.rotateOrder'%node)
 
 #Puts matrix into transformation matrix
 mTransformMtx = OpenMaya.MTransformationMatrix(matrix)
 
 #Translation Values
 trans = mTransformMtx.translation(OpenMaya.MSpace.kWorld)
 
 #Euler rotation value in radians
 eulerRot = mTransformMtx.rotation()
 
 #Reorder rotation order based on ctrl.
 eulerRot.reorderIt(rotOrder)
 
 #Find degrees
 angles = [math.degrees(angle) for angle in (eulerRot.x, eulerRot.y, eulerRot.z)]
 
 #Find world scale of our object.
 scale = mTransformMtx.scale(OpenMaya.MSpace.kWorld)

 #Return Values
 return [trans.x,trans.y,trans.z],angles,scale

#If we're in the main namespace run our stuffs!
if __name__ == '__main__':
 #Defining object name.
 nodeName = 'yourName'
 
 #Get Matrix
 mat = getMatrix(nodeName)
 
 #Decompose matrix
 matDecomp = decompMatrix(nodeName,mat)
 
 #Print our values
 sys.stdout.write('\n---------------------------%s---------------------------\n'%nodeName)
 sys.stdout.write('\nTranslation : %s' %matDecomp[0])
 sys.stdout.write('\nRotation    : %s' %matDecomp[1])
 sys.stdout.write('\nScale       : %s\n' %matDecomp[2])

You could very easily get an MMatrix using maya.cmds by just doing:

mat = OpenMaya.MMatrix(cmds.getAttr('YourNode.worldMatrix'))

But this will only work with the new API, not the old.

Monday, March 4, 2013

cdScaleAnimCurves

0 comments
      So upon request, I wrote a script that scales selected curves relative to it's selection. Either copy this to the python script editor and run it or put it in your scripts directory and import it and run:

import cdScaleAnimCurves as cdAnim
cd.createUI()

cdScaleAnimCurves


Let me know how it works!
-Chris

Monday, January 21, 2013

cdRenderCompsWithSelected

0 comments
So I wrote an after effects script. I've never written in java, but always fun learning something new.
  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
/*
This script takes the selected footage in an after effects project 
and makes a composition for each footage with the selected layers.
It then adds it to the render queue with the inputed after effects
template and the user specified path.

Input:
 Selected Footage and Layer with an active composition

Returns:
 None

Functions:
 cdGetItems();
 cdRenderCompsWithSelected(comp, layers, footage, outputPathName, endTime, templateName);
*/


function cdGetItems()
{
 var mySelectedItems = [];

 for (var i = 1; i <= app.project.numItems; i++)
     {
         if (app.project.item(i).selected)
             {
                 mySelectedItems[mySelectedItems.length] = app.project.item(i);
             }
     }

 if(mySelectedItems.length < 1)
  {
   alert("You have no footage selected");
   return;
  }
  
 if(app.project.activeItem == undefined || app.project.activeItem == null || app.project.activeItem.selectedLayers == undefined || app.project.activeItem.selectedLayers == undefined || app.project.activeItem.selectedLayers == null || app.project.activeItem.selectedLayers.length == 0)
  {
   alert("You have no adjustment layer selected");
   return;
  }

 else
  {
   var currentComp = app.project.activeItem;
            var selectedLayer = app.project.activeItem.selectedLayers[0];
            var endTime = app.project.activeItem.workAreaDuration;

      var myOutputPath= Folder.selectDialog("Select output path!");      
      if (myOutputPath == undefined)
       {
        return;
       }

      var outputPathName = myOutputPath.fsName + "/";

   var name = prompt("What is your render queue template name?", "Spiderman");
      
      if (name == undefined)
       {
        return;
       }

   cdRenderCompsWithSelected(currentComp, selectedLayer, mySelectedItems, outputPathName, endTime, name)
  }
}

function cdRenderCompsWithSelected(comp, layers, footage, outputPathName, endTime, templateName)
{
    app.beginUndoGroup("Run the Function.");
    var g = 0;
    
    for (var i = 0; i < footage.length; i++)
        {
            var currentFootage = footage[i];
            var myComp = app.project.items.addComp(currentFootage.name, 1280, 720, 1, currentFootage.duration, 24);                           
            var myLayer = myComp.layers.add(currentFootage);
            newLayer = layers.copyToComp(myComp);
            myComp.layers[1].outPoint = currentFootage.duration;
            var theRender = app.project.renderQueue.items.add(myComp);
            var newFile = new File(outputPathName + currentFootage.name);
            theRender.outputModules[1].file = newFile;     

            try
             {
              theRender.outputModules[1].applyTemplate(templateName);
             }
             
         catch(err)
          {
     if (g == 0)
     {
      g = 1;
      alert("You didn't specify an existing template name!");                            
     }
     continue;
          }
        }
    app.endUndoGroup();
}

cdGetItems();

Monday, October 15, 2012

Selected Curve to Python Command

1 comments
In the process of making a control maker for python, I found it super annoying to manually figure out the command for a curve. This script will take the selected curve and return the command in python. SO MUCH EASIER.

Just run the script and type makePythonCommand("New Curve Name"). It should print out the commands for all curve types as well as transforms selected with multiple shapes under it.
 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
import maya.cmds as mc

def makePythonCommand(name):
    try:
        curve = mc.ls(selection = True)[0]
        curveShapes = mc.listRelatives(curve, children = True, path= True, type = 'nurbsCurve')
    except:
        raise RuntimeError('Select a curve Please')    
    
    if name == '':
        name = 'What'
            
    for curveShape in curveShapes:
        #curveInfo    
        infoNode = mc.createNode('curveInfo')
        mc.connectAttr("%s.worldSpace[0]" %curveShape, "%s.inputCurve" %infoNode, force = True)
        
        #Find the knot values and get the numSpans,degree,form, and CVs
        knots = list(mc.getAttr('%s.knots' %infoNode)[0])
        numSpans = mc.getAttr('%s.spans' %curveShape)
        degree = mc.getAttr('%s.degree' %curveShape)
        form = mc.getAttr('%s.form' %curveShape)
        numCVs = numSpans + degree
        mc.delete(infoNode)
        
        if form == 2:
            numCVs -= degree
        
        cVs = mc.ls('%s.cv[0:%d]' %(curveShape, (numCVs-1)), flatten = True)        
        
        #For each cv get it's world position
        cvArray = [mc.xform(cv, q = True, ws = True, translation = True) for cv in cVs]
        
        if form == 2:
            cvArray.append(cvArray[0])
            cvArray.append(cvArray[1])
            cvArray.append(cvArray[2])
           
            pyCmd = 'mc.curve(name = "%s", per = True, d= %s,p= %s, k = %s)' %(name, degree, cvArray, knots)
            
        if degree == 1 and form !=2:
            pyCmd = 'mc.curve(name = "%s", d= 1,p= %s)' %(name, cvArray)
                            
        if degree >=2 and form !=2:     
            pyCmd = 'mc.curve(name = "%s", d= %s,p= %s, k = %s)' %(name, degree, cvArray, knots)
    
        print '\n%s' %pyCmd

Monday, September 10, 2012

cdReorderAttributes

0 comments
I wrote this script today just because maya has never implemented the feature of moving your user defined attributes. Basically you can do this by hand by deleting an attribute and undoing it. Do make sure you have undo's enabled and have the object selected/have an object with user defined attributes. Just run the script in the python script editor and move attributes in the list in the order you want.


 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
import maya.cmds as mc

def cdReorderAttributes():
    if mc.window('cdReOrderAttributes', exists = True):
     mc.deleteUI('cdReOrderAttributes')
    
    #Get the selected nurbs surface and joints, otherwise print an error. 
    try:
     obj = mc.ls(selection= True)[0]
    except:
     raise RuntimeError('Please select an object to load attributes.')         
    
    attrs = mc.listAttr(obj, userDefined = True)
    
    if attrs:
        if len(attrs) < 2:
            raise RuntimeError('Not enough attributes to reorder.')   
    
    else:
        raise RuntimeError('Not enough attributes to reorder.')   
         
    win = mc.window('cdReOrderAttributes', title= 'cdReOrderAttributes', sizeable = True)
    
    mc.columnLayout('attrLayout', adjustableColumn = True, rowSpacing = 5)
    mc.rowColumnLayout('attrRowLayout', numberOfColumns = 2, columnWidth = [(1, 120), (2,50)])
    
    mc.columnLayout('attrLayout', adjustableColumn = True, rowSpacing = 5)
    mc.textScrollList('attrScroll', allowMultiSelection=True, append = attrs, selectItem= attrs[0])    
    mc.setParent('..')    
    
    mc.columnLayout('buttonLayout', adjustableColumn = True, rowSpacing = 5)
    mc.symbolButton(image = 'trackUp.png',  height =  90, command = 'moveAttrUp()')
    mc.symbolButton(image =  'trackDown.png', height =  90, command = 'moveAttrDown()')
    mc.setParent('..')    
    mc.setParent('..')    
    
    mc.columnLayout('buttonLayout', adjustableColumn = True, rowSpacing = 5)
    mc.button('Reorder Attributes', command = 'reorderAttr("%s")' %obj, backgroundColor = (0,.2,.2))
    mc.setParent('..')    
    
    mc.window(win, edit= True, width = 100, height = 200)
    mc.showWindow(win)


def moveAttrUp():
    attrs = mc.textScrollList( 'attrScroll', query = True, ai = True)
    attrSel = mc.textScrollList( 'attrScroll', query = True, selectItem = True)[0]
    
    a = attrs.index(attrSel)
    attrs[a-1], attrs[a] = attrs[a], attrs[a-1]
            
    mc.textScrollList('attrScroll', e = True, ra = True)
    mc.textScrollList('attrScroll', e = True, append = attrs, selectItem = attrSel)
            
def moveAttrDown():
    
    attrs = mc.textScrollList( 'attrScroll', query = True, ai = True)
    attrSel = mc.textScrollList( 'attrScroll', query = True, selectItem = True)[0]
    
    a = attrs.index(attrSel)
    
    if a == (len(attrs) - 1):
        attrs[0], attrs[a] = attrs[a], attrs[0]    
        
    else:        
        attrs[a+1], attrs[a] = attrs[a], attrs[a+1]
            
    mc.textScrollList('attrScroll', e = True, ra = True)
    mc.textScrollList('attrScroll', e = True, append = attrs, selectItem = attrSel)    

def reorderAttr(obj):
    attrs = mc.textScrollList( 'attrScroll', query = True, ai = True)
    for attr in attrs:
        mc.undo(mc.deleteAttr(obj, attribute = attr))
 
       
cdReorderAttributes()