Category Archives: workflow

Fat Bat and the power of doodling

I’ve been doing a lot more Photoshop drawing in recent weeks, some bad, some not so bad. It’s a nice break from the technical world or python and rigging. It’s nice to just throw down shapes and colour and just start seeing what happens, there’s a great freedom in doing so and a lot of fun on the way to discovering new concepts and ideas for stories and characters. Here are some results, with brief overview of my thought process.

1. I call this one ‘Hipster with a rocket!’

I had no idea what was going to happen here, all I knew was that I wanted to create something with a rocket in it, so I started with the ground, threw in the sky and the rocket…..then I thought, it needs something else, so I roughly drew out some shapes to represent the astronaut, I kept really simple and voila, an image I was moderately happy with. Well, inside I was really happy with it, uncomplicated shapes, warm colours, and all with minimal effort.

shitPlanetAnyway

2. Bat etching.

I wanted to draw bats, To loosen me up one morning, I just painted out some random shapes with a big white brush on black, I then went in with an eraser and just etched in silhouettes, a really nice way to find some unexpected shapes. I wasn’t thinking detail, just bats,  the one on the bottom left, was already in mind and is developed on below, but all the rest, they just popped out of the initial painted shapes.

bat-sillhoettes

3. The Fat Bat comes to life….

A few days of doodling and this model popped up, not much to say here, but I knew the bat on the bottom left(from above) had an appeal about its posture and shape, and this was the character I most warmed too, so after an initial doodle for some colour and concepting,  I moved onto the model, and here he is, nameless but otherwise a fat bat, that has evolved through a really fun creative processes.

fatBat_01

batLookDev_01

All he needs now is a story…. and an animator willing to bring him to life….okay, I’ll get around to doing it soon, I promise!

Joint Based face Rig Demo

I Just dug this out of the archives.  It’s a demo of a rig I built while doing a CG society course early this year, it uses a LOT of joints, all driven by set driven keys.  It’s the first time I’ve digressed from using Blendshapes in a rig setup and it does work very nicely.

A lot of credit must go to Judd Simantov who ran the course, and produced a wonderfully appealing model for the students to work with.

The video is 3 minutes long and is mostly just me doodling and making faces for fun, so I give you a Ace Frehley as it’s soundtrack!

I’m back, and here’s nk_ribbonSpine.py

So After a few months of trying to get my site back online due to some problematic bugs, and a busy work schedule, I’m finally able to post again…. and Here in all it’s glory is my ribbon creator script.

I’ve never liked doing anything more than once, so as a 3D artist, I decided it to take the time to script my own tools while rigging. I’ve used Mel for a few years, but for the past 6 months I’ve been learning python and it’s been highly refreshing. Here’s a tool I’ve just completed that creates 2 types of ribbon spines, a Basic ribbon and an Offset ribbon as seen in Aaron Holly’s DVD’s on creature rigging.

Many thanks also to Suchan Bajracharya of Puppeteer Lounge, who created the Sinka Rig. It makes use of both these types, which I myself am implementing into my own rig setups now.  I’ve also just started a workshop with PL, so I hope to really push my rigging skillset to a new level over the coming months.

Just a note, this version currently only works fully in Maya 2014, since, if I’m not mistaken the skinCluster functionality has evolved from previous versions of Maya.

I know, the GUI is a little ugly and raw, but this is part of my learning curve; I’m currently just getting used to building UI’s in Maya. With all knowledge I’ve saturated in recent years, I’m hoping I can start to share that knowledge with the world of animation TD’s and those learning like me.

I’ll try and do an update soon on how this might be used in A rig, so please keep you’re eyes peeled.


import maya.cmds as mc 

def nk_ribbonSpine():
    
	'''
	Version
	-----------------------
	v02
	* Switched the prefix so that the prefix specified of this is an offset ribbon, or a basic
	* Fixed double transforms on the nurbsPlane and the the follicles
	
	About
	-----------------------
	Creates a ribbon spine based on the Aaron Holly's method. 
	
	Returns
	-----------------------
	None
	
	Requires
	-----------------------
	None
	
	Example
	-----------------------
	Source the code, then run the following line to bring up the nk_ribbonSpine UI:
	nk_ribbonSpine()
	
	None
	
	TODO
	-----------------------
	* Add an option to switch the direction of the spine so it can be created facing in x or y
	'''
	

	# GUI FOR RIBBON SPLINE

	# delete the ui if it exists
	if (mc.window('nk_ribbonSpineGui', exists=True)):
	    mc.deleteUI('nk_ribbonSpineGui')

 	# Create the Gui 
 	mc.window('nk_ribbonSpineGui', title='nk_ribbonSpine', h=125, w=150)
 	
 	#Create main Col
 	mc.columnLayout('mainCol')
 	
 	# FrameLayot - Prefix
 	mc.frameLayout('prefixFL', label='prefix')
	mc.textFieldGrp('prefix', label='PREFIX', text='CHAR_SIDE_LIMB')
	mc.setParent('mainCol')
	
	# FrameLayout - Ribbon Type
	mc.frameLayout('ribbonTypeFL', label='Ribbon Type')
	mc.button('basicRbnBTN', l='BASIC', c='basicRibbon()')
	mc.button('offsetRbnBTN', l='OFFSET', c='offsetRibbon()' )
	mc.setParent('mainCol')
	
	
	mc.window('nk_ribbonSpineGui', e=True, h=125, w=150)
    
 	mc.showWindow('nk_ribbonSpineGui')

 
####RIBBON SPINE FUNCTION BELOW HERE###################

def nk_createRibbonSpine(prefix='CHAR_SIDE_LIMB', type='offset'):

	##+++++++++++++++++++++++++++++++++##
	##+++++++nk_createRibbonSpine++++++##
	##+++++++++++++++++++++++++++++++++##

	
	#Check the type of ribbon
	if type == 'basic':
		suffix = 'rbnBasic'

	if type =='offset':
		suffix = 'rbnOffset'
	
	
	#create group for ribbon rig
	ribbonRigGrp = mc.group(em=True, n=(prefix + '_' + suffix + '_rig_grp'))
	# ribbonRigGrp = mc.group(em=True, n=(prefix))

	# Create nurbs plane
	ribbonPlane = mc.nurbsPlane (n=(prefix + '_' + suffix + 'Plane'), p=[0, 0, 0], ax= [0, 0 ,1], w=1 ,lr=5 ,d=3, u=1, v=5, ch=0)
	ribbonPlaneShape = mc.listRelatives(ribbonPlane, c=True, s=True) #get shape node
	
    # CLEANUP: Parent plane to rigGrp and turn off inheritsTransforms
	mc.parent(ribbonPlane[0], ribbonRigGrp)
	mc.setAttr('{ribbonPlane}.inheritsTransform'.format(ribbonPlane=ribbonPlane[0]),0, lock=True)
	#mc.setAttr('{ribbonPlane}.inheritsTransform'.format(ribbonPlane=ribbonPlane[0]), lock=True)
	

	## rebuildSurface
	mc.rebuildSurface(ribbonPlane[0], rpo=1, rt=0, end=1, kr=0, kcp=0, kc=0, su=1, du=1, sv=0, dv=3, tol=0.01, dir=0)
	
	# Create follicles * 5
	
	##Create an empty group for the follicles
	folGroup = mc.group(em=True, n=(prefix + '_' + suffix + '_follicleGrp'))
		
    # CLEANUP: Parent follicleGrp to rigGrp
	mc.parent(folGroup, ribbonRigGrp)
	
	##Create a list for the follicles
	folList = []

    ##Create the follicles and ribbon joints
	for f in range(5):
		follicle = mc.createNode('follicle', n=('{prefix}_{suffix}_FollicleShape_{number}'.format(prefix=prefix, suffix=suffix ,number=(f+1))))
		print follicle
		follicleTransform = mc.listRelatives(follicle,  p=True) #get transform node

		ribbonJnt = mc.joint(n='{prefix}_{suffix}_jnt_{f}'.format(prefix=prefix,suffix=suffix,f=f+1))#create joint
		grp=mc.group(n=(ribbonJnt+'_offsetGrp'))#grp joint

		## connect folliclesShapes to the plane
		mc.connectAttr(('{ribbonPlaneShape}.local'.format(ribbonPlaneShape=ribbonPlaneShape[0])) ,('{follicle}.inputSurface'.format(follicle=follicle)))
		mc.connectAttr(('{ribbonPlaneShape}.worldMatrix[0]'.format(ribbonPlaneShape=ribbonPlaneShape[0])) ,('{follicle}.inputWorldMatrix'.format(follicle=follicle)))
		## connect follicleShapes to follicleTransform
		mc.connectAttr((follicle+'.outTranslate'), (follicleTransform[0]+'.translate') )
		mc.connectAttr((follicle+'.outRotate'), (follicleTransform[0]+'.rotate') )

		##position the follicles along the plane
		mc.setAttr((follicle+'.parameterU'), 0.5)
		vSpanHeight = ((f+1.0)/5.0) - .1
		mc.setAttr((follicle+'.parameterV'), vSpanHeight)
		
		#Turn off inherit transforms on the follicles
		mc.setAttr('{follicleTransform}.inheritsTransform'.format(follicleTransform=follicleTransform[0]),0, lock=True)
		
		##parent the follicle to the group and add to lists
		mc.parent(follicleTransform[0], folGroup)
		folList.append(follicle)
		
	# Create ribbon bind joints and setup aim constraints
	mc.select(cl=True)

	bindBaseJnt = mc.joint(p=(0,-2.5,0), o=(0,0,90), rad=2, n=(prefix+'_'+suffix+'_base_bind_01'))
	mc.joint(p=(0,-2,0), n=(prefix+'_ribbon_base_bind_02'))

	mc.select(cl=True)

	bindTipJnt = mc.joint(p=(0,2.5,0), o=(0,0,-90), rad=2, n=(prefix+'_'+suffix+'_tip_bind_01'))
	mc.joint(p=(0,2,0), n=(prefix+'_ribbon_tip_bind_02'))

	mc.select(cl=True)


	bindMidJnt = mc.joint(p=(0,0,0), o=(0,0,0), rad=2, n=(prefix+'_'+suffix+'_mid_bind_01'))
	mc.select(cl=True)

    # create control Locators and parent bindJoint to aimLocator
	##baseLocators
	basePosLoc = mc.spaceLocator(n=(prefix+'_'+suffix+'_base_pos_loc'))
	baseUpLoc = mc.spaceLocator(n=(prefix+'_'+suffix+'_base_up_loc'))
	baseAimLoc = mc.spaceLocator(n=(prefix+'_'+suffix+'_base_aim_loc'))

	mc.parent(baseUpLoc,baseAimLoc,basePosLoc )#parent locators
	mc.xform(basePosLoc, t=(0,-2.5,0))#move locator to base position
	mc.xform(baseUpLoc, ws=True, t=(0,-2.5,2))# offset Up locator in Z
	mc.parent(bindBaseJnt,baseAimLoc)#parent jnt to aim locator
	
	
	#CLEANUP: startPosLoc to rigGrp
	mc.parent(basePosLoc, ribbonRigGrp)
	
	##midLocators
	midPosLoc = mc.spaceLocator(n=(prefix+'_'+suffix+'_mid_pos_loc'))
	midUpLoc = mc.spaceLocator(n=(prefix+'_'+suffix+'_mid_up_loc'))
	midAimLoc = mc.spaceLocator(n=(prefix+'_'+suffix+'_mid_aim_loc'))

	mc.parent(midUpLoc,midAimLoc,midPosLoc )#parent locators
	mc.xform(midUpLoc, ws=True, t=(0,0,2))# offset Up locator in Z
	mc.parent(bindMidJnt,midAimLoc)#parent jnt to aim locator
	
	mc.parent(midPosLoc, ribbonRigGrp)
	
	##tipLocators
	tipPosLoc = mc.spaceLocator(n=(prefix+'_'+suffix+'_tip_pos_loc'))
	tipUpLoc = mc.spaceLocator(n=(prefix+'_'+suffix+'_tip_up_loc'))
	tipAimLoc = mc.spaceLocator(n=(prefix+'_'+suffix+'_tip_aim_loc'))

	mc.parent(tipUpLoc,tipAimLoc,tipPosLoc)#parent locators
	mc.xform(tipPosLoc, t=(0,2.5,0))#move locator to tip position
	mc.xform(tipUpLoc, ws=True, t=(0,2.5,2))# offset Up locator in Z
	mc.parent(bindTipJnt,tipAimLoc)#parent jnt to aim locator
	
	#CLEANUP: tipPosLoc to rigGrp 
	mc.parent(tipPosLoc, ribbonRigGrp)
	
	#setup aim relationsips
	##basic
	if type=='basic':
		##baseAimLoc > tipPos##
		mc.aimConstraint(tipPosLoc[0],baseAimLoc[0], aim=(0,1,0), u=(0,0,1), wut='object', wuo=baseUpLoc[0])
		##tipAimLoc > basePos##
		mc.aimConstraint(basePosLoc[0],tipAimLoc[0], aim=(0,-1,0), u=(0,0,1), wut='object', wuo=tipUpLoc[0])
		##midAimLoc > tipPos##
		mc.aimConstraint(tipPosLoc[0],midAimLoc[0], aim=(0,1,0), u=(0,0,1), wut='object', wuo=midUpLoc[0])
		
		# midPosLoc to follow both base and tip
		mc.pointConstraint(basePosLoc[0],tipPosLoc[0],midPosLoc[0], mo=False)
		# midPosAim to follow both base and tip Aim
		mc.pointConstraint(baseUpLoc[0],tipUpLoc[0],midUpLoc[0], mo=False)
		
	if type=='offset':
		
		##baseAimLoc > midBindJoint##
		mc.aimConstraint(bindMidJnt,baseAimLoc[0], aim=(0,1,0), u=(0,0,1), wut='object', wuo=baseUpLoc[0])
		#tipAimLoc > midBindJoint##
		mc.aimConstraint(bindMidJnt,tipAimLoc[0], aim=(0,-1,0), u=(0,0,1), wut='object', wuo=tipUpLoc[0])
		##midAimLoc > tipPos##
		mc.aimConstraint(tipPosLoc[0],midAimLoc[0], aim=(0,1,0), u=(0,0,1), wut='object', wuo=midUpLoc[0])
		
		# midPosLoc to follow both base and tip
		mc.pointConstraint(basePosLoc[0],tipPosLoc[0],midPosLoc[0], mo=False)
		# midPosAim to follow both base and tip Aim
		mc.pointConstraint(baseUpLoc[0],tipUpLoc[0],midUpLoc[0], mo=False)

	# Bind skin	
	mc.select(cl=True)
	print bindBaseJnt 
	print bindMidJnt 
	print bindTipJnt
	mc.skinCluster(bindBaseJnt,bindMidJnt,bindTipJnt,ribbonPlane, n=(prefix+'_'+suffix+'_skinCluster'), tsb=True, ih=True, bm=0, sm=0, nw=1, wd=0, mi=3, omi=False, dr=4)

def basicRibbon():
	prefix = mc.textFieldGrp('prefix', q=True, text=True)
	nk_createRibbonSpine(prefix, type='basic')

def offsetRibbon():
	prefix = mc.textFieldGrp('prefix', q=True, text=True)
	nk_createRibbonSpine(prefix, type='offset')




myFirstPythonScript…copyAttributes

I’ve won’t hail myself as the ultimate scripting wizard…I think I’m pretty average to be fair, but its always nice to make certain tasks a bit quicker.   Here’s a basic python script you can use to copy attributes between 2 selected objects.

 

”’import maya.cmds as mc”’

 

#COPY ATTRIBUTES

 

#get attributesfromfirst selected

cntrls = mc.ls (sl=1, tr=1)

print cntrls

cnt = len(cntrls)

print cnt

 

#check if two items are selected

if cnt != 2 :

mc.warning (“SELECT TWO OBJECT ONLY”)

 

if cnt == 2:

#get attributes from master item

attrList = mc.listAttr (cntrls[0], v=1, k=1)

print attrList

#add attributes to next selected item

for attr in attrList :

mc.addAttr (cntrls[1], k=True, at=”float”, ln=attr)