Thursday, December 10, 2015

Delete Floating or "winged" Vertex in maya.

Often in maya when modeling you can end up with floating "or winged vertex. Simply object select the mesh you need to clean up











type polyDelVertex in the MEL box at the bottom of maya and hit enter. This should clean up any floating vertexes and leave the good ones.

Tuesday, November 17, 2015

Creating dynamic clouds in fumefx and vray for maya

So you want to create some slick clouds in FumeFX for MAYA?



Basic steps of the tutorial:

1. Generate polygon cloud geometry using displaced noise on a group of combined spheres to get a nice broken up cloud shape.

2. Convert the displacement to polygons via modify>convert displacement to polygons.

3. Reduce the resulting polygon mesh to something manageable (100k polys or less)

4. Use the resulting object as a fume fx emitter.



1.First make a a collection of spheres either manually or using this cloud creation plugin. Basically we just want a cluster of spheres that is roughly the shape of our cloud. Make sure there are both large and small spheres sprinkled about for good variation.


(If you use the spheres plugin it will generate nurbs and you will have to convert them to polys and then reduce it's poly count before use. )

UPDATE: Another cool way I just discovered to get your base cloud starting shape is to use maya fluids with a texture from my maya fluid clouds tutorial. on how to create maya fluid clouds. This actually works amazingly well!!! Then once you have a cloud shape you like simply go to modify>convert fluid to polygons).  If you do this SKIP TO STEP 4.

2. Once you have a combined shape that is a single object of spheres apply a lambert material (reason for this is we are going to convert the displacement to polys and you can't do this if it's a vray material)

3. In your hyper shade create a displacement node. default click and drag a noise node onto your lambert material and Select displacement. Then create a noise node and middle drag it to the displacement node. (REMEMBER MAYA DISPLACEMENT IS BASED ON OBJECT SCALE. if you have a large object you may not see your displacement. To remedy this select your displacement file node. Color balance and turn up the alpha gain setting till you see the displacement. Then you can refine the displacement smoothness and resolution by selecting the object you are displacing There should now be a Displacement Map drop down in the attributes for it. The vray displacement settings will NOT work anymore.)

If you try and use a fractal to drag onto the displacement node by default it will attach the alpha channel out and you won't get any effect. You can fix this by middle mouse clicking and disconnecting the alpha and attaching just one channel of R,G or B to the displacement node.

3. Now set your renderer to IPR so we can see real time updates of the displacement changes (make sure to turn on displacement in the Vray RT renderer) and start tweaking the noise parameters and UV mapping settings on your object. What we want is a big lump shape with small details and large billow details at the same time. you don't want ONLY either of those you want both.

This is going to effect the look of your clouds quite alot. If you have to many large smooth areas they will show up, if you have to small of details they will disappear into them ass and not be visible.




4. Once you have a shape you like. go to modify menu > convert displacement to polygons.

It may take a few minutes. The resulting object will probably be really polygon heavy. Go to mesh menu>reduce> settings square. Set it to 50% (or higher if you wish and reduce the obejct a couple times. Something below 100k polys or less should be good.

5. Now make your fume FX container select it then shift select your object and turn it into a object emmiter with the fume fx icon.

Now for the golden mojo cloud mix.
I don't have it perfect but after some experimentation I've come up with a decent recipi. use these fume


6. On your object emitter source attributes to source type volume. and turn the smoke amount up to 10.




On your emmiter source also change turbulence to these values:
Velocity
Object - 1 (doesn't matter)
Extra - .001 (for very slight cloud expansion over time, if this is set to 0 you will have a perfectly static cloud.)



Turbulence
Amount .5
Scale 10
Frames 3



7. Then use these settings in your fume FX container. I'm only mentioning the ones. Turn off fuel.


GENERAL PARAMETERS:
Spacing .3 (work it down to .2 later)

Set your container size toe contain your object and set it to adaptive.

SIMULATION:GENERAL
leave as default

SIMULATION:SYSTEM
Gravity .1
Vorticity .5
Velocity Damping 0
X turb .9
Y turb .1
Z turb .5

SIMULATION: TURBULENCE NOISE
Scale 2
Frames 10
Detail 2

SIMULTION:SMOKE
Simulate Smoke : ON
Smoke Boyancy .2
Dissipation Min Dens 10
Dissipation strength .1
Diffusion 0

Additional smoke rendering settings.




Lastly in  illumination> illumination map set multiplier to 4. (this is from the fume fx vray maya documentation.)



If all goes well you should get a render that looks something like this.




Turn on do Multiple scattering under Multiple Scattering. leave settings as is. Add a single directional light.


These are both rendered at .3 spacing and took 55 seconds on a 40 core dual xeon @ 960x540

45 seconds

1.5 minutes



Hope you enjoyed this tutorial. If it helps you drop me a line in the comments please!




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