Search Maya Zest



Friday, August 7, 2015

Change the length of key tangents in the graph editor in Maya

For some reason Maya by default tangents in the graph editor are locked up tighter than a beer cap without a bottle opener unless you do these steps.




1. Open the graph editor

2. Select all your keys in the graph editor (or juts the ones you want to effect)

3. Go to curves menu in the graph editor and choose "weighted tangents"

4. Then with all of them still selected goto tangents menu and choose "free tangents"

Now they should unlock and give you ALOT mroe flexibility in your graph editor.

Monday, July 27, 2015

How to turn instanced nparticles models into geometry

If you need your instanced nparticles to become actual geometry with keyframes that you can work with and modify here is the way to go about it.

This is an amazing little tool here is more info about it by it's creator.
http://www.sigillarium.com/blog/726/


Save this script to a .py file

Place the file in your maya scripts folder

maya>2016>scripts


from sag_instancerToGeometry import *
sag_instancerToGeometry()


#-----------------------------------------------------------------------------------------------maya-
# file: sag_instancerToGeometry.py
# version: 1.4
# date: 2012.05.05
# author: Arkadiy Demchenko (sagroth@sigillarium.com)
#----------------------------------------------------------------------------------------------------
# Converts instancer into keyframed objects:
# Put the file into maya scripts dir and run:
#
# from sag_instancerToGeometry import *
# sag_instancerToGeometry()
#----------------------------------------------------------------------------------------------------
# 2012.05.05 (v1.4) - corrected GUI for older maya versions
# 2012.04.06 (v1.3) - doesn't set visibility to off prior to the starting frame of conversion
#                   - doesn't pay attention to 'start from current frame' if custom range is defined
#
# 2011.06.19 (v1.2) - reworked GUI
# - uses long names correctly (no problems with objects of the same name anymore)
# - doesn't freeze source objects' rotations or error if channels have keyframes
# - keeps input connections for instances also
# - works with different rotation orders of source objects and instancer itself
# - each baked object is inside it's own group which actually gets all keyframes
# - works with any linear units of the scene (switches to cm and back, actually)
#
# 2010.06.11 (v1.1) - duplicates now maintain original input connections
# - only translate, rotate, scale and visibility are keyframed now
#
# 2009.11.14 (v1.0) - main release
#----------------------------------------------------------------------------------------------------

from maya.cmds import *

# GUI
def sag_instancerToGeometry():
if window( 'sag_instancerToGeometry_win', exists = True ):
deleteUI( 'sag_instancerToGeometry_win' )

window( 'sag_instancerToGeometry_win', title = 'Instancer to Geo', sizeable = False )

columnLayout( adj = True )

radioButtonGrp( 'sag_instancerToGeometry_win__dupOrInst_RBG',
labelArray2 = ['Make Duplicates', 'Make Instances'],
numberOfRadioButtons = 2,
select = 2 )

separator( style = 'in' )

checkBox( 'sag_instancerToGeometry_win__fromCurFrame_ChB',
align = 'left',
label = 'Start from Current Frame',
value = 1 )

radioButtonGrp( 'sag_instancerToGeometry_win__range_RBG',
labelArray2 = ['Playback Range', 'Custom Range'],
numberOfRadioButtons = 2,
select = 1,
onCommand1 = 'intFieldGrp( "sag_instancerToGeometry_win__range_IFG", edit = True, enable1 = False, enable2 = False )',
onCommand2 = 'intFieldGrp( "sag_instancerToGeometry_win__range_IFG", edit = True, enable1 = True, enable2 = True )' )

intFieldGrp( 'sag_instancerToGeometry_win__range_IFG',
label = '',
numberOfFields = 2,
columnWidth = (1, 24),
value1 = playbackOptions( q = True, min = True ),
value2 = playbackOptions( q = True, max = True ),
enable1 = False,
enable2 = False )

sep2 = separator( style = 'in' )

rowLayout( numberOfColumns = 2, columnWidth2 = [ 172, 40 ], columnAlign2 = [ 'center', 'center' ] )

button( label = 'Convert',
width = 172,
command = 'sag_instancerToGeometry_cmd()' )

button( label = 'Help',
width = 48,
command = 'showHelp( "http://www.sigillarium.com/blog/726/", absolute = True )' )

showWindow( 'sag_instancerToGeometry_win' )


# RUN MAIN PROCEDURE WITH SETTINGS FROM GUI
def sag_instancerToGeometry_cmd():
dupOrInst = radioButtonGrp( 'sag_instancerToGeometry_win__dupOrInst_RBG', q = True, select = True ) - 1
fromCurFrame = checkBox( 'sag_instancerToGeometry_win__fromCurFrame_ChB', q = True, value = True )
rangeSpecified = radioButtonGrp( 'sag_instancerToGeometry_win__range_RBG', q = True, select = True ) - 1
start = intFieldGrp( 'sag_instancerToGeometry_win__range_IFG', q = True, value1 = True )
end = intFieldGrp( 'sag_instancerToGeometry_win__range_IFG', q = True, value2 = True )

sag_instancerToGeometry_do( dupOrInst, fromCurFrame, rangeSpecified, start, end )


# MAIN PROCEDURE
def sag_instancerToGeometry_do( dupOrInst, fromCurFrame, rangeSpecified, start, end ):

# RANGE OPTIONS
currentFrame = currentTime( q = True )
startFrame = playbackOptions( q = True, min = True )
endFrame = playbackOptions( q = True, max = True )

if rangeSpecified > 0:
startFrame = start
endFrame = end
elif fromCurFrame > 0:
startFrame = currentFrame

# MAKE A LIST OF ALL SELECTED INSTANCERS
instList = []

selList = ls( selection = True )

for each in selList:
if objectType( each ) == 'instancer':
instList.append( each )

if instList == []:
print 'No instancers selected!'
return

# FIND GEOMETRY, PARTICLE OBJECTS AND MAPPED ATTRIBUTES FOR INSTANCERS
geoList = []
ptList = []
iamList = []

blankInsts = []
for each in instList:
# MAKE A LIST OF INPUT OBJECTS
instGeo = listConnections( each + '.inputHierarchy', source = True, destination = False, connections = False, plugs = False )

if instGeo == None:
print 'No geometry connected to instancer ' + each + '!'
blankInsts.append( each )

else:
# MAKE A LIST OF PARTICLE OBJECTS AND THEIR INSTANCER MAPPED ATTRIBUTES
conn = listConnections( each + '.inputPoints', source = True, destination = False, connections = False, plugs = True )

if conn == None:
print 'No particles connected to instancer ' + each + '!'
blankInsts.append( each )
else:
geoList.append( instGeo )
ptList.append( conn[0][:conn[0].find( '.' )] )
iamList.append( getAttr( conn[0][:conn[0].rfind( '.' )] + '.instanceAttributeMapping' ) )

# REMOVE INSTANCERS WITH NO GEOMETRY OR PARTICLES ATTACHED FROM THE LIST
for each in blankInsts:
instList.remove( each )

# QUIT IF NO REASONABLE INSTANCERS LEFT
if instList == []:
return

# SET UNITS TO CM (SINCE THAT'S WHAT PARTICLE VALUES USING NO MATTER WHAT)
origUnits = currentUnit( query = True, linear = True )
currentUnit( linear = 'cm' )

# LISTS FOR STORING CONVERTED IDS AND CREATED DUPLICATES
pids = []
dups = []
for inst in instList:
pids.append( [] )
dups.append( [] )

# MAIN CONVERSION LOOP
for t in xrange( int( startFrame ), int( endFrame ) + 1 ):
currentTime( t, update = True )

for inst in instList:
instInd = instList.index( inst )
instGeo = geoList[instInd]
instPt = ptList[instInd]
instIam = iamList[instInd]

# GET INSTANCER ROTATION ORDER AND CONVERT IT INTO GEOMETRY ROTATION ORDER
instRodOrig = getAttr( inst + '.rotationOrder' )
instRodConv = { 0:0, 1:3, 2:4, 3:1, 4:2, 5:5 }
instRod = instRodConv[ instRodOrig ]

deadPids = pids[instList.index(inst)][:]
instNum = getAttr( inst + '.instanceCount' )
for i in xrange( 0, instNum ):
# GET GENERAL OPTIONS VALUES
pid = int(particle( instPt, q = True, at = 'particleId', order = i )[0])
pos = particle( instPt, q = True, at = 'worldPosition', order = i )
scl = (1,1,1)
shr = (0,0,0)
vis = 1.0
idx = 0.0
if 'scale' in instIam:
scl = particle( instPt, q = True, at = instIam[instIam.index( 'scale' )+1], order = i )
if 'shear' in instIam:
shr = particle( instPt, q = True, at = instIam[instIam.index( 'shear' )+1], order = i )
if 'visibility' in instIam:
vis = particle( instPt, q = True, at = instIam[instIam.index( 'visibility' )+1], order = i )[0]
if 'objectIndex' in instIam:
idx = particle( instPt, q = True, at = instIam[instIam.index( 'objectIndex' )+1], order = i )[0]

# IF OBJECT INDEX IS HIGHER OR LOWER THAN AVAILABLE NUMBER OF INSTANCE OBJECTS - CLAMP TO THE CLOSEST POSSIBLE VALUE
if idx > (len( instGeo ) - 1):
idx = (len( instGeo ) - 1)
elif idx < 0:
idx = 0

# IF SCALE ATTRIBUTE IS FLOAT INSTEAD OF VECTOR - FORCE VECTOR
if len( scl ) < 3:
scl = [scl[0], scl[0], scl[0]]

# GET ROTATION OPTIONS VALUES
rot = (0,0,0)
if 'rotation' in instIam:
rot = particle( instPt, q = True, at = instIam[instIam.index( 'rotation' )+1], order = i )

# IF THE PARTICLE IS NEWBORN MAKE A DUPLICATE
newBorn = 0

dupName = inst.replace( '|', '_' ) + '_' + instGeo[int(idx)].replace( '|', '_' ) + '_id_' + str(pid)

if pid not in pids[instList.index(inst)]:
pids[instList.index(inst)].append( pid )

# IF OBJECT WITH THE SAME NAME ALREADY EXISTS, ADD _# SUFFIX
if objExists( dupName ):
z = 1
dupName += '_' + str( z )
while objExists( dupName ):
z += 1
dupName = dupName[:dupName.rfind( '_' )+1] + str( z )

if dupOrInst > 0:
dup = instance( instGeo[int(idx)], name = dupName )[0]
trsConns = listConnections( instGeo[int(idx)], s = True, d = False, c = True, p = True )
if trsConns != None:
for y in xrange( 0, len( trsConns ), 2 ):
if not isConnected( trsConns[y+1], dup + trsConns[y][trsConns[y].rfind( '.' ):] ):
connectAttr( trsConns[y+1], dup + trsConns[y][trsConns[y].rfind( '.' ):] )
else:
dup = duplicate( instGeo[int(idx)], name = dupName, inputConnections = True )[0]

# CREATE A GROUP FOR A DUPLICATE
dupGrp = group( em = True, name = dup + '_grp' )
parent( dupGrp, dup )
setAttr( dupGrp + '.translate', 0, 0, 0, type = 'double3' )
parent( dupGrp, world = True )
parent( dup, dupGrp )

dup = dupGrp

dups[instList.index(inst)].append( dup )

if t != int( startFrame ):
newBorn = 1
else:
# IF OBJECT WITH THE SAME NAME EXISTS FROM PREVIOUS BAKE, FIND THE SUFFIXED NAME FROM THIS BAKE
if not dupName + '_grp' in dups[instList.index(inst)]:
z = 1
dupName += '_' + str( z )
while not dupName + '_grp' in dups[instList.index(inst)]:
z += 1
dupName = dupName[:dupName.rfind( '_' )+1] + str( z )

dup = dupName + '_grp'
if pid in deadPids:
deadPids.remove( pid )

# TRANSFORM THE DUPLICATE
setAttr( dup + '.translate', pos[0], pos[1], pos[2], type = 'double3' )
setAttr( dup + '.scale', scl[0], scl[1], scl[2], type = 'double3' )
setAttr( dup + '.visibility', vis )

setAttr( dup + '.rotateOrder', instRod )
setAttr( dup + '.rotate', rot[0], rot[1], rot[2], type = 'double3' )

# SET KEYFRAMES
setKeyframe( dup, inTangentType = 'linear', outTangentType = 'linear', attribute = ( 'translate', 'rotate', 'scale', 'visibility' ) )
if newBorn > 0:
setKeyframe( dup + '.visibility', time = currentTime( q = True ) - 1, value = 0 )

# MAKE DEAD INSTANCES INVISIBLE
for dead in deadPids:
setKeyframe( dups[instList.index(inst)][pids[instList.index(inst)].index(dead)] + '.visibility', value = 0 )

# GROUP DUPLICATES, DELETE STATIC CHANNELS AND APPLY EULER FILTER
for inst in instList:
group( dups[instList.index(inst)], name = inst + '_geo_grp', world = True )
for obj in dups[instList.index(inst)]:
delete( obj, staticChannels = True, unitlessAnimationCurves = False, hierarchy = 'none', controlPoints = False, shape = False )
animCurves = listConnections( obj, source = True, destination = False, connections = False, plugs = False )
filterCurve( animCurves )

# RESTORING ORIGINAL UNITS
currentUnit( linear = origUnits )





Tuesday, May 12, 2015

Using Backburner with Maya Render Layers

So if you have found your way here chances are you are trying to accomplish this illusive phenomena known as getting render layers to work in Back Burner with maya. If you just start a scene rendering with "send to backburner" in maya you will ONLY get the masterLayer

I spent a lot of time researching this and found a script someone wrote to submit multiple jobs, one per render layer to Backburner. IT IS PURE GENIUS.

I'm posting the script here because it is so amazing I don't want to see it disappearing from the web. But I will link to the great guy that created it as well and if you are the guy who created it and want me to take it down from here i'm glad too.

Here is his blog.
http://www.marianoantico.blogspot.com/

Here is the Python script

Creative crash link if you'd prefer to get it there.
http://www.creativecrash.com/maya/script/to-backburner

Just create a new shelf icon in maya and paste the code from this script into the command section for the shelf icon. No need to "install" it anywhere.

The only thing you will need to tweak is to open the script in notepad change and update the maya path on line 251 and 602 to reflect your version of maya. Search for 2011 and replace it with your version in my case 2015.

If you don't do this BB will throw a create Cmdjob Process error: 2 and not give you any other information as to why it isn't working. But it's this path that is the problem.

Otherwise the script is pretty self explanitory, it sends a BB job for each render layer and your good to go!

See his mini tutorial here.
https://vimeo.com/35570376

Thanks Mariano!!

ADDITIONAL TIP
You can also change the path your files are going to render to by adding this command to the "additional options" field on this script to each job before submitting.

If you don't ALL images even from different render layers will go into the same folder. Example.

-rd "//VFX_NAS/Maya_Project/images/Shot_1"

ANOTHER TIP
You can install backburner Monitor on multiple machines to be able to watch the jobs. but only one of them can control the jobs, add render nodes etc. To change which system controls the render que simple open Monitor on the system you want to control it from. Connect to the manager IP and hit ctrl-Q


Wednesday, October 22, 2014

Change default save from binary to ASCII (maya)

Simple tip but if you can't find where to change this can be frustrating.

Just go to file menu in the top of maya. Then click the little square next to "save scene as" Now in the popup you can select maya ASCII as the default save type.