tag:blogger.com,1999:blog-89991471824964884612024-03-19T14:18:59.922-07:00The Art and Tech of KyleMROn occasion, Kyle has been known to post stuff here...Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.comBlogger32125tag:blogger.com,1999:blog-8999147182496488461.post-49034359308641219172019-03-26T03:25:00.000-07:002019-03-26T03:25:19.306-07:00I'm baaaaaaack... with cubes!It's certainly been a while since I've posted anything, so here's a neat project I spent a few days working on in Unity!<br />
<br />
<iframe src="https://c.simmer.io/static/unityFrame/index.html?url=https%3A%2F%2Fsimmercdn.com%2Funity%2FztY5UWv11PbW4Wxi9xnzIuddBJ63%2Fcontent%2Ff422a6ac-be20-4063-f002-23380e7b0881&imagePath=screens/0.png" style="border: 0; height: 360px; width: 580px;"></iframe>
<br />
<br />
Scramble the cube with [S]<br />
Reset the cube with [R]<br />
Click and drag with RMB to look around the cube<br />
Click and drag on pieces with LMB to turnAnonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-77850059919371934822013-04-07T18:24:00.000-07:002013-04-07T18:30:43.509-07:00PyQt Drag and drop: Outliner-like QTreeView in MayaOk, it's definitely been a while since I last posted. I promise I'm not dead, just very busy with work! Anyways, this was an issue that came up for me a while ago -- one of those things I had to spend a couple days puzzling over. The issue was implementing internal drag and drop in a PyQt hierarchical tree display using the model/view framework.</p>
Enabling drag and drop for any of PyQt's convenience view classes (QTreeWidget, QListWidget) is fairly straightforward (alright, it's downright easy). Since you have to pretty much implement it from scratch when you use QAbstractItemModel paired with QTreeView, there end up being a couple of 'gotchas'.</p>
If you aren't familiar with the model/view paradigm in PyQt, I'd like to point you towards Yasin Uludag's excellent video series <a href="http://www.yasinuludag.com/blog/?p=98">here</a> -- they should give you a pretty good introduction. If you've seen his videos before, the code in my examples should appear fairly familiar, as I've structured things pretty much the same.</p>
By the end of this post, you should be able to implement your own outliner-like window in Maya using PyQt, as well as understand a little about how to integrate the Qt window with objects in the Maya scene using PyMEL.</p>
Let's jump in:</p>
<pre class="brush: py">
from pymel.core import *
from PyQt4 import QtCore, QtGui
import cPickle
import maya.OpenMayaUI
import sip
def mayaMainWindow():
'''Returns the Maya window as a QMainWindow instance.'''
ptr = maya.OpenMayaUI.MQtUtil.mainWindow()
if ptr is not None:
return sip.wrapinstance( long(ptr), QtCore.QObject )
</pre>
We'll start out with some basic imports. PyMEL will be used for interacting with Maya (although you could also use maya.cmds if you absolutely had to), PyQt4 for drawing the GUI elements, cPickle or pickle for serializing data. The OpenMaya and sip imports are for the first function, the usual boilerplate Maya Main Window function that allows us to make the windows we create children of the Maya window.</p>
<pre class="brush: py; first-line: 14">
class TreeItem( object ):
'''Wraps a PyNode to provide an interface to the QAbstractItemModel'''
def __init__( self, node=None ):
'''
Instantiates a new tree item wrapping a PyNode DAG object.
'''
self.node = node
self.parent = None
self.children = []
@property
def displayName( self ):
'''Returns the wrapped PyNode's name.'''
return self.node.name()
@displayName.setter
def displayName( self, name ):
'''Renames the wrapped PyNode.'''
self.node.rename( str( name ) )
def addChild( self, child ):
'''Adds a given item as a child of this item.
Also handles parenting of the PyNode in the maya scene
'''
self.children.append( child )
child.parent = self
# If adding a child to the root, parent the node to the world
if self.node is None:
# In earlier versions of PyMEL, parenting an object
# to its current parent throws an error
if child.node.getParent() is not None:
child.node.setParent( world=True )
return
if child.node.getParent() != self.node:
child.node.setParent( self.node )
def numChildren( self ):
'''Returns the number of child items.'''
return len( self.children )
def removeChildAtRow( self, row ):
'''Removes an item at the given index from the list of children.'''
self.children.pop( row )
def childAtRow( self, row ):
'''Retrieves the item at the given index from the list of children.'''
return self.children[row]
def row( self ):
'''Get this item's index in its parent item's child list.'''
if self.parent:
return self.parent.children.index( self )
return 0
def log( self, level=-1 ):
'''Returns a textual representation of an item's hierarchy.'''
level += 1
output = ''
for i in range( level ):
output += '\t'
output += self.node.name() if self.node is not None else 'Root'
output += '\n'
for child in self.children:
output += child.log( level )
level -= 1
return output
</pre>
Here's the first class. Since we will use Qt's model/view interface to create the tree view, we need an interface to the Maya objects that will be represented in the outliner. This 'item' class can wrap a PyNode to provide a usable interface to the object, returning information regarding the object's name and hierarchy; it can also edit the PyNode, so that the outliner can affect changes in the Maya scene as well.</p>
For this example, the PyNodes in question will represent joints, since they have a handy visual representation of their hierarchy - it will be easy to see hierarchical relationships between joints as they change as a result of dragging and dropping items in the outliner.</p>
<pre class="brush: py; first-line: 90">
def gatherItems():
'''Return a scene hierarchy of top-level joints as TreeItems.
Creates and returns a root TreeItem with items for all joints that are
direct children of the world as children.
'''
# Create a null TreeItem to serve as the root
rootItem = TreeItem()
topLevelJoints = [jnt for jnt in ls( type='joint' ) if jnt.getParent() is None]
def recursiveCreateItems( node ):
# An inline function for recursively creating tree items and adding them to their parent
item = TreeItem( node )
for child in node.getChildren( type='joint' ):
childItem = recursiveCreateItems( child )
item.addChild( childItem )
return item
for jnt in topLevelJoints:
item = recursiveCreateItems( jnt )
rootItem.addChild( item )
return rootItem
</pre>
This function gathers the data from the scene and compiles the hierarchy of TreeItems. It recursively traverses through all the top-level joints in the scene (joints with no parent), wraps them in a TreeItem instance, and adds that item to the 'children' list of the appropriate parent. It then returns a null TreeItem that acts as a 'world' level item, with all those top-level joints as its children.</p>
<pre class="brush: py; first-line: 116">
class OutlinerModel( QtCore.QAbstractItemModel ):
'''A drag and drop enabled, editable, hierarchical item model.'''
def __init__( self, root ):
'''Instantiates the model with a root item.'''
super( OutlinerModel, self ).__init__()
self.root = root
def itemFromIndex( self, index ):
'''Returns the TreeItem instance from a QModelIndex.'''
return index.internalPointer() if index.isValid() else self.root
def rowCount( self, index ):
'''Returns the number of children for the given QModelIndex.'''
item = self.itemFromIndex( index )
return item.numChildren()
def columnCount( self, index ):
'''This model will have only one column.'''
return 1
def flags( self, index ):
'''Valid items are selectable, editable, and drag and drop enabled. Invalid indices (open space in the view)
are also drop enabled, so you can drop items onto the top level.
'''
if not index.isValid():
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsDropEnabled
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsDropEnabled | QtCore.Qt.ItemIsDragEnabled |\
QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable
def supportedDropActions( self ):
'''Items can be moved and copied (but we only provide an interface for moving items in this example.'''
return QtCore.Qt.MoveAction | QtCore.Qt.CopyAction
def headerData( self, section, orientation, role ):
'''Return the header title.'''
if section == 0 and orientation == QtCore.Qt.Horizontal:
if role == QtCore.Qt.DisplayRole:
return 'Joints'
return QtCore.QVariant()
def data( self, index, role ):
'''Return the display name of the PyNode from the item at the given index.'''
if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
item = self.itemFromIndex( index )
return item.displayName
def setData( self, index, value, role ):
'''Set the name of the PyNode from the item being edited.'''
item = self.itemFromIndex( index )
item.displayName = str( value.toString() )
self.dataChanged.emit( QtCore.QModelIndex(), QtCore.QModelIndex() )
return True
def index( self, row, column, parentIndex ):
'''Creates a QModelIndex for the given row, column, and parent.'''
if not self.hasIndex( row, column, parentIndex ):
return QtCore.QModelIndex()
parent = self.itemFromIndex( parentIndex )
return self.createIndex( row, column, parent.childAtRow( row ) )
def parent( self, index ):
'''Returns a QMoelIndex for the parent of the item at the given index.'''
item = self.itemFromIndex( index )
parent = item.parent
if parent == self.root:
return QtCore.QModelIndex()
return self.createIndex( parent.row(), 0, parent )
def insertRows( self, row, count, parentIndex ):
'''Add a number of rows to the model at the given row and parent.'''
self.beginInsertRows( parentIndex, row, row+count-1 )
self.endInsertRows()
return True
def removeRows( self, row, count, parentIndex ):
'''Remove a number of rows from the model at the given row and parent.'''
self.beginRemoveRows( parentIndex, row, row+count-1 )
parent = self.itemFromIndex( parentIndex )
for x in range( count ):
parent.removeChildAtRow( row )
self.endRemoveRows()
return True
def mimeTypes( self ):
'''The MimeType for the encoded data.'''
types = QtCore.QStringList( 'application/x-pynode-item-instance' )
return types
def mimeData( self, indices ):
'''Encode serialized data from the item at the given index into a QMimeData object.'''
data = ''
item = self.itemFromIndex( indices[0] )
try:
data += cPickle.dumps( item )
except:
pass
mimedata = QtCore.QMimeData()
mimedata.setData( 'application/x-pynode-item-instance', data )
return mimedata
def dropMimeData( self, mimedata, action, row, column, parentIndex ):
'''Handles the dropping of an item onto the model.
De-serializes the data into a TreeItem instance and inserts it into the model.
'''
if not mimedata.hasFormat( 'application/x-pynode-item-instance' ):
return False
item = cPickle.loads( str( mimedata.data( 'application/x-pynode-item-instance' ) ) )
dropParent = self.itemFromIndex( parentIndex )
dropParent.addChild( item )
self.insertRows( dropParent.numChildren()-1, 1, parentIndex )
self.dataChanged.emit( parentIndex, parentIndex )
return True
</pre>
Here is the data model that will effectively translate the collection of data (TreeItems) into a form that can be displayed in our outliner (a QTreeView). The model is responsible for acting as a middle man between the GUI object and the data.</p>
There are a few important things to note here. The 'flags' function (line 137) declares that items can not only be selected and edited, but also dragged and dropped. Line 173 in the 'index' function is also very important - sometimes the data model will request information about indices that don't exist, leading to 'list index out of range' errors. I had a hell of a time figuring this out, and I still don't fully understand why this happens. However, looking through the C++ Qt source code, I found that convenience classes like QStandardItemModel, which inherits QAbstractItemModel does in fact employ a similar logical check to avoid queries to invalid indices.</p>
Perhaps the most important bit to call attention to are the last three functions, 'mimeTypes', 'mimeData', and 'dropMimeData'. The first declares acceptable Mime types for the model. Since we aren't using any standard data type, what we put here is fairly arbitrary. Check out good old <a href="https://en.wikipedia.org/wiki/Internet_media_type">wikipedia </a>for more info on Mime types.</p>
<pre class="brush: py; first-line: 233">
class SkeletonOutliner( QtGui.QMainWindow ):
'''A window containing a tree view set up for drag and drop.'''
def __init__( self, parent=mayaMainWindow() ):
'''Instantiates the window as a child of the Maya main window, sets up the
QTreeView with an OutlinerModel, and enables the drag and drop operations.
'''
super( SkeletonOutliner, self ).__init__( parent )
self.tree = QtGui.QTreeView()
self.outlinerModel = OutlinerModel( gatherItems() )
self.tree.setModel( self.outlinerModel )
self.tree.setDragEnabled( True )
self.tree.setAcceptDrops( True )
self.tree.setDragDropMode( QtGui.QAbstractItemView.InternalMove )
self.selModel = self.tree.selectionModel()
self.selModel.currentChanged.connect( self.selectInScene )
self.tree.expandAll()
self.setCentralWidget( self.tree )
self.show()
def selectInScene( self, current, previous ):
'''Callback for selecting the PyNode in the maya scene when the outliner selection changes.'''
pynode = self.outlinerModel.itemFromIndex( current ).node
select( pynode, r=True )
</pre>
The last part of the code defines a Qt window, parented to Maya's main window with a tree view hooked up to our OutlinerModel. There's a callback hooked up to the tree view's selection model that will change the selection in the Maya scene to the item selected in the outliner. And that's really about it.</p>
Call the window like this:</p>
<pre class="brush: py">
outliner = SkeletonOutliner()
</pre>
To see it in action, create a new scene in Maya and create a few joint chains, then instantiate the SkeletonOutliner class. You should be able to select joints, drag and drop them to reparent, and double click the names to rename them.Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com3tag:blogger.com,1999:blog-8999147182496488461.post-54251908402861276492013-01-02T05:32:00.000-08:002013-04-07T18:25:50.346-07:00kyleMR Demo Reel<div style="text-align: left;">
EDIT: I'm making this sticky post for my most recent demo reel. The newest posts under this one are my most recent work, including new Python tools and rig development.<br />
<br />
I also have a new website up! Check it out at <a href="http://kylemistlinrude.wix.com/kylemr">www.kyleMR.com</a>.</div>
<br />
<div style="text-align: center;">
<iframe allowfullscreen="" frameborder="0" height="281" mozallowfullscreen="" src="http://player.vimeo.com/video/46612797?portrait=0" webkitallowfullscreen="" width="500"></iframe> </div>
<a href="http://vimeo.com/46612797">Kyle Mistlin-Rude July 2012 Demo Reel</a> from <a href="http://vimeo.com/kylemr">kyleMR</a> on <a href="http://vimeo.com/">Vimeo</a>.<br />
<br />
First up is the Lutin rig, featuring a roll joint solution for the FK/IK blending arms, an adjustable foot roll attribute, and space switching. It was skinned to a dedicated deformation joint hierarchy, using only two joint influences per vertex.<br />
<br />
The character utility tool was scripted in Python, and it handles FK/IK matching for the character's arms, seamless parent space switching on various rig controls, as well as animation baking and export. The tool uses information stored within metaNodes on the rig to get control positions and manipulate the rig. It also combines modular character geometry and copies skin weights from original character meshes to a consolidated mesh.<br />
<br />
The modular character auto rig was developed from a 3D Buzz learning DVD. I was responsible for coding the system in Python from reference code, as well as debugging, troubleshooting, and adapting the user interface to work in the QT interface scheme new to Maya 2011 and 2012. The system handles the placing of joints and building of animation control setups procedurally.<br />
<br />
The mr_motionTrail script is a motion trail utility scripted in pyMel. It expands the default functionality of Maya's motion trails and allows the user to quickly add, edit, and remove trails in the viewport. It has been featured on lesterbanks.com and is available as a free download on Creative Crash.Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-12737486763280385542012-08-27T01:00:00.002-07:002012-08-27T01:00:38.615-07:00New Python Tool: Mirroring and Copying SDKs<div style="text-align: center;">
<iframe allowfullscreen="allowfullscreen" frameborder="0" height="281" mozallowfullscreen="mozallowfullscreen" src="http://player.vimeo.com/video/48283237?portrait=0" webkitallowfullscreen="webkitallowfullscreen" width="500"></iframe> </div>
<div style="text-align: center;">
<a href="http://vimeo.com/48283237">Set Driven Key Mirroring and Copying: Python Tool for Maya</a> from <a href="http://vimeo.com/kylemr">kyleMR</a> on <a href="http://vimeo.com/">Vimeo</a>.</div>
Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-24245496269927526082012-08-08T21:22:00.000-07:002012-08-08T21:22:03.511-07:00The Mech Leg Problem: Rigging an Offset Ball JointAs part of a project I'm working on, I'm going to be rigging a cool frog-like mech. Originally, each joint in the mech's leg was going to be a sort of hinge, but in order for the character to be able to shift its weight and adduct or abduct its legs, we needed to replace the hinges at the hips and ankles with ball joints. However, for the hip joint, instead of simply swapping the hinge for a ball joint, and placing it at the top of the leg, we decided to attach the ball joint to the side of the existing hinge, since it moved the leg out away from the body and gave us a wider range of motion with less interpenetration of the geometry.<br />
<br />
That posed an interesting problem of how to rig an offset ball joint so that the leg behaved in a way that looked mechanically correct. Here is the setup I ended up piecing together:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidGL2akfBYM9XebjVe8FraLXgrMD8841DUkTSeUPhaO09c-EaRLyiHh77cq4WGhH0d9vw5FqwTPkM7uupj6cGaNZuU5POML0nlhXh58eNfLsDEA1u9jzB6mi_m1yORFpSdge-HfNx-OeLG/s1600/mechLeg01_geo_border.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="293" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidGL2akfBYM9XebjVe8FraLXgrMD8841DUkTSeUPhaO09c-EaRLyiHh77cq4WGhH0d9vw5FqwTPkM7uupj6cGaNZuU5POML0nlhXh58eNfLsDEA1u9jzB6mi_m1yORFpSdge-HfNx-OeLG/s320/mechLeg01_geo_border.jpg" width="320" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;">Here's an approximation of the geometry for the mech's leg.</span></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
As you can see from the picture, the mech's leg is much like a quadrupedal hind leg - it's a digitigrade limb. You can also see how the top of the leg (the hip's hinge) is attached to the side of the new ball joint. In this case, the ball joint is centered over the origin, with 0 values in X and Z translation.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK2uKmGlmBRu1q5dzAcBXra6wbgpKx_VtkdKwqoneC9f4Vesz0LZB0l96fnf0BWqSuLB8-9wlrDmLwfHAxhDx6wKZ7f580V5C43N1PnHNa-T56pusy56NirotcH_KVA1KlkO1Jpi5AZ-gj/s1600/mechLeg02_joints_border.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="293" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK2uKmGlmBRu1q5dzAcBXra6wbgpKx_VtkdKwqoneC9f4Vesz0LZB0l96fnf0BWqSuLB8-9wlrDmLwfHAxhDx6wKZ7f580V5C43N1PnHNa-T56pusy56NirotcH_KVA1KlkO1Jpi5AZ-gj/s320/mechLeg02_joints_border.jpg" width="320" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;"> The basic joint chain to control the leg.</span></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
To start the rig off, create the basic joint chain. I just eyeballed the placement of the joints from the side view, but for the final rig I would make sure the joints were centered at the pivot points for the hinges and ball joints. After placing the joints, I just translated them in X to make them line up with the geometry.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
I started with the entire chain in a single hierarchy, then I duplicated the foot/ankle joint (the second to last joint) and unparented it from the hierarchy to make a separate foot hierarchy. I then deleted the end joint on the original hierarchy, so the leg was one separate chain, and the foot another. Make sure to name everything for clarity!</div>
<div style="text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglw__-kgpnyPXZCqF6nyy_6TjbMi1jwH6dvcXahfrB_vWzopJnFd5JTQivPvP0kiT1pfgeU5F_4eHJwp-cx8xL_OnoEsZq5a5Na6bfRm_MTY0AIbNDjwqFUaHjvA_qUGigIbJyFziQMmuE/s1600/mechLeg03_ankleLoc_border.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="196" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglw__-kgpnyPXZCqF6nyy_6TjbMi1jwH6dvcXahfrB_vWzopJnFd5JTQivPvP0kiT1pfgeU5F_4eHJwp-cx8xL_OnoEsZq5a5Na6bfRm_MTY0AIbNDjwqFUaHjvA_qUGigIbJyFziQMmuE/s320/mechLeg03_ankleLoc_border.jpg" width="320" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;">Setting up the foot control and the ankle locator.</span></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
To attach the foot's joint hierarchy to the leg, create a locator named <i>ankle_pos_loc</i> and snap its position to the ankle joint. Create a curve shape named <i>foot_control</i>, position it at the foot, and snap its pivot to the ankle joint as well. Then make sure to freeze transforms on the control. By placing the pivot at the ankle, when you rotate the foot, the leg doesn't move. Now parent <i>ankle_pos_loc</i> and the foot joints to <i>foot_control</i>, as seen below.</div>
<div style="text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj95qOFA_fzipQaMe91Wm9vhZs0MnyjFRgVV9Fzh_ZVIkAXh6UrtYmhFEfrvu66LsnnLDDblit34VvNoLEmpr07JQm6WlQhVosNOJkADJ9o2YOdVIuRigcBtbS06pMuhSp18Q-x8Ns6jek-/s1600/mechLeg05_footControl_border.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="233" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj95qOFA_fzipQaMe91Wm9vhZs0MnyjFRgVV9Fzh_ZVIkAXh6UrtYmhFEfrvu66LsnnLDDblit34VvNoLEmpr07JQm6WlQhVosNOJkADJ9o2YOdVIuRigcBtbS06pMuhSp18Q-x8Ns6jek-/s320/mechLeg05_footControl_border.jpg" width="320" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;">The foot control and foot joints.</span></div>
<br />
Now we'll set up the IK chain that will drive the leg. We'll use a spring solver, which is a somewhat hidden IK solver. It handles these quadrupedal style joint chains quite nicely. I create a an IK handle named <i>leg_spring_ikHandle</i> from the top of the leg (<i>leg_a_jnt</i> in my case) to the bottom (<i>leg_jnt_end</i>). The solver type doesn't really matter, since we'll enable the spring solver next, by typing<br />
<div style="text-align: center;">
ikSpringSolver</div>
<div style="text-align: left;">
into the MEL command line. Now if you check the attribute editor, under IK Solver Attributes, you'll see the IK Solver option menu has the 'ikSpringSolver' option.</div>
<div style="text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_3uCCIo3uNoW9PbZeWCoY1DLb4NONvSji638IJ3V_Xz42JzrQ4oxenBTWjM-mY3Uc58x1uSLi7Xf-Apn53K317I-YVBxFMg4ctwj7offVmSaNaLcdKz3iRFz8sj9B9wWaktx_JKVuyKvj/s1600/mechLeg04_springSolver_border.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="125" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_3uCCIo3uNoW9PbZeWCoY1DLb4NONvSji638IJ3V_Xz42JzrQ4oxenBTWjM-mY3Uc58x1uSLi7Xf-Apn53K317I-YVBxFMg4ctwj7offVmSaNaLcdKz3iRFz8sj9B9wWaktx_JKVuyKvj/s320/mechLeg04_springSolver_border.jpg" width="320" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;"> Selecting the spring solver.</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Point constrain <i>leg_spring_ikHandle</i> to <i>ankle_pos_loc</i>. If you attach the geometry to the joints at this point (I just used parent constraints with Maintain Offset checked on), you'll see something like the image below when you compress or extend the leg.</div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3mzi7BTvuqCIgoNKkgkUXj_Nad5PQjpnCwHtil8y97BzX5W-t_MZYyEt2Afw1U-XIsQHK3SIouZNw5ZTtimZqBfxvATZdaeaupDXcn0iofMGw7P6IXmSEjycf3G7mOPy_O0gBkmM0KSsP/s1600/mechLeg06_flexExtend_border.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="130" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3mzi7BTvuqCIgoNKkgkUXj_Nad5PQjpnCwHtil8y97BzX5W-t_MZYyEt2Afw1U-XIsQHK3SIouZNw5ZTtimZqBfxvATZdaeaupDXcn0iofMGw7P6IXmSEjycf3G7mOPy_O0gBkmM0KSsP/s320/mechLeg06_flexExtend_border.jpg" width="320" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;">From the side, the leg behavior looks good.</span></div>
<div style="text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimrceF7VllrkMqAKVS6_o-WUxXNIodI0DhQF_r8xFXEaGJsF4dgl6ZLaUA7GIqQMpCt7sVuaLXpygwjW0PQqpZQq6VnMIoxkS5osyd8BmOW2ypKAQnTMVLFB2fzEHOGt_pYA0ovY4k2QzT/s1600/mechLeg07_tangent_border.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="244" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimrceF7VllrkMqAKVS6_o-WUxXNIodI0DhQF_r8xFXEaGJsF4dgl6ZLaUA7GIqQMpCt7sVuaLXpygwjW0PQqpZQq6VnMIoxkS5osyd8BmOW2ypKAQnTMVLFB2fzEHOGt_pYA0ovY4k2QzT/s320/mechLeg07_tangent_border.jpg" width="320" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;">Unfortunately, it doesn't work so well from the front view.</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
You'll see the problem inherent to the offset ball joint when you articulate the leg from side to side. Since the top of the leg hierarchy is at the hinge joint, that's where the leg pivots from. You can see the hinge interpenetrating with the ball joint, and it doesn't look like the ball joint is moving at all. The behavior we actually want is sketched out in blue. The angle of the hinge should be tangent to the ball joint's surface in order to look correct.</div>
<div style="text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2E-HL-bEXQePEovsKpKkKYysbV3tShUduXFOGl2z2I7b-_0W8ZRDLOyfB4tQmmmEs0q8AAWRoT3qyiRPGvTgLHA9y-E3j0cFNdStyzB0TUWhJTorEQcG7W7Z5VgTuA1dYnn4hyphenhyphenXHq6lKy/s1600/mechLeg08_ballJoint_border.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="244" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2E-HL-bEXQePEovsKpKkKYysbV3tShUduXFOGl2z2I7b-_0W8ZRDLOyfB4tQmmmEs0q8AAWRoT3qyiRPGvTgLHA9y-E3j0cFNdStyzB0TUWhJTorEQcG7W7Z5VgTuA1dYnn4hyphenhyphenXHq6lKy/s320/mechLeg08_ballJoint_border.jpg" width="320" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;"> Adding the ball joint's joint.</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
To get the hinge to be tangent to the ball joint, it needs to move around the ball joint as the leg moves out to the side. Create a new joint chain for the ball joint by duplicating the top joint of the leg and deleting all of its children. Rename it to <i>ball_jnt</i> and zero out its joint orient fields in the attribute editor. This ensures that the joint is aligned to the world. Duplicate <i>ball_jnt</i> and name it <i>ball_jnt_end</i>. Translate <i>ball_jnt</i> back to 0 in X, so that it is in the center of the ball joint geometry. Now parent <i>ball_jnt_end</i> to <i>ball_jnt.</i></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Create another locator named <i>leg_pos_loc</i> and snap it to <i>ball_jnt_end</i>'s position. Parent it to <i>ball_jnt_end</i>, and point constrain the top joint of the leg hierarchy to the locator.</div>
<div style="text-align: left;">
<i><br /></i></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuE_VsKkkIZm16hF6gCA7fo5Q-er9EBT8ZVderF_BfMupnKivzyJK3hqDggZ1AfoC3u5NwchZofUxM82jbU73ekbF6hzXaGVDC2Y-TYCBnjr9yErw1grmcSmG7FX0GsrZrI6GhV83Ze5Bj/s1600/mechLeg09_legPositionLoc_border.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="269" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuE_VsKkkIZm16hF6gCA7fo5Q-er9EBT8ZVderF_BfMupnKivzyJK3hqDggZ1AfoC3u5NwchZofUxM82jbU73ekbF6hzXaGVDC2Y-TYCBnjr9yErw1grmcSmG7FX0GsrZrI6GhV83Ze5Bj/s320/mechLeg09_legPositionLoc_border.jpg" width="320" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;"> The leg position locator.</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
If you manually rotate <i>ball_jnt</i> when the leg is out to the side, you can line it up so that the leg looks correct.</div>
<div style="text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQcltxWGgm3HHgLquxEaU9hE4RVEIaL4N_CVFuhtdBrZBMiuxPCobCtAFsD1JCWePBPkPOTySnA-rrdHR86gVwUCHwy8CaFZAucKNUY7TeBoEHD2pbY4OgK2y4rXIa9xY7ouQuBLfVvA7V/s1600/mechLeg10_manualControl_border.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="223" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQcltxWGgm3HHgLquxEaU9hE4RVEIaL4N_CVFuhtdBrZBMiuxPCobCtAFsD1JCWePBPkPOTySnA-rrdHR86gVwUCHwy8CaFZAucKNUY7TeBoEHD2pbY4OgK2y4rXIa9xY7ouQuBLfVvA7V/s320/mechLeg10_manualControl_border.jpg" width="320" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;"> The ball joint manually adjusted to match the orientation of the leg.</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Notice that the angle of <i>ball_jnt</i> and the leg make a right angle, so that the hinge is tangent to the ball joint.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
You could just create a control for <i>ball_jnt</i> and call it a day, but that's sort of an inconvenient setup for the animators, who would have to constantly adjust that control to match the leg. It would be nice to automate the rotation of <i>ball_jnt</i>. Fortunately, we can do that with an aim constraint.</div>
<div style="text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgr1r2UqOkwYbWVCfzKGZDMaxjl5KfRX1ZPHBTJ3NI62iKAhMntziYbOwKKnNAwt90k2Mw69N-YYW33tPtPiibNcd76gniBdwIv57gTNzo39aFc1IprPbqxzzImtxiGQr-FIQnsBNniR92T/s1600/mechLeg11_aimLoc_border.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="223" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgr1r2UqOkwYbWVCfzKGZDMaxjl5KfRX1ZPHBTJ3NI62iKAhMntziYbOwKKnNAwt90k2Mw69N-YYW33tPtPiibNcd76gniBdwIv57gTNzo39aFc1IprPbqxzzImtxiGQr-FIQnsBNniR92T/s320/mechLeg11_aimLoc_border.jpg" width="320" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;"> The aim locator in its proper location.</span></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
Create a new locator named <i>ball_joint_lootAt_loc</i> and snap it to <i>ball_jnt</i>. Then move it down until it is at the same height as the ankle. Create an empty group, name it <i>ball_joint_aim_grp</i>, and point constrain it with no offset to <i>ankle_pos_loc</i>. Then parent <i>ball_joint_lookAt_loc</i> to <i>ball_joint_aim_grp</i>, and now it follows along with the foot.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Create yet another locator, call it <i>ball_joint_aimUp_loc</i> and snap it to <i>ball_jnt</i> as well. Then translate it out in front of the ball joint (in this case that's a positive Z translation). This locator will serve as the up object for the aim constraint.</div>
<div style="text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiS6vWaOq13uLVg4uhDENQ5FF_yBaGwevGRT57z2Tr-nB0xCS1G24NklmgvCmokHmXfuYlzQ0QnbQ6gGf0OvKLCcTLMKFsEYti8yFwcNjv7pmXK-nxVDdGEiVHLJcNVyGLHU7efX5pU8OXK/s1600/mechLeg12_aimUpLoc_border.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="242" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiS6vWaOq13uLVg4uhDENQ5FF_yBaGwevGRT57z2Tr-nB0xCS1G24NklmgvCmokHmXfuYlzQ0QnbQ6gGf0OvKLCcTLMKFsEYti8yFwcNjv7pmXK-nxVDdGEiVHLJcNVyGLHU7efX5pU8OXK/s320/mechLeg12_aimUpLoc_border.jpg" width="320" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;"> Placement for the aim up locator.</span></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
Now make an aim constraint from <i>ball_jnt</i> to <i>ball_joint_lookAt_loc</i>. The settings I used were a negative Y vector for the aim axis, positive Z for the up axis, and object up for the up type. The up object should of course be <i>ball_joint_aimUp_loc</i>. After the aim constraint is applied, <i>ball_jnt</i> should still have a rotation of (0, 0, 0).</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
If you move the foot control at this point, you should see that the ball joint and leg work in almost perfect harmony. However, if you lift the foot to be all the way out to the side and at the same level as the ball joint, the hinge joint at the top of the leg is a little out of alignment. This occurs because the angle of the leg is different from the angle between the ball joint and the aim locator. If the aim locator were to adjust its location as the foot moved, such that it more closely copied the angle of the leg, this problem would not be noticeable.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
To get this sort of behavior to work, we need to drive the the position of the aim locator using the angle of the leg. Unfortunately, this would create a dependency cycle, since changing the angle of the leg would affect the aim locator, which would affect the ball joint, which would affect the position of the leg, which would affect the angle of the leg again. So we need a new joint chain that mimics the angle of the leg as close as possible. I haven't managed to figure out a way to EXACTLY duplicate the angle of the leg without running into some sort of dependency, but the solution I've come up with works close enough that you shouldn't be able to see the difference.</div>
<div style="text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuNIVT3X17h4-Wf5cEyEiX_J5YtPHalkhmDrTsCGNY-xL4iejSPhC3kuZAxWzRq1yS6yDy7Ut9o_iH5LHnqcSHzpQFMfsUiHvbIN8zSjMpBbE89t78Wd6aQVvQsJ9FRrqKncgVnvgg6Xo0/s1600/mechLeg13_aimOrientDriver_border.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuNIVT3X17h4-Wf5cEyEiX_J5YtPHalkhmDrTsCGNY-xL4iejSPhC3kuZAxWzRq1yS6yDy7Ut9o_iH5LHnqcSHzpQFMfsUiHvbIN8zSjMpBbE89t78Wd6aQVvQsJ9FRrqKncgVnvgg6Xo0/s320/mechLeg13_aimOrientDriver_border.jpg" width="320" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;"> The aim orient driver joint chain.</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Create a new joint in the perspective viewport and snap it to the <i>ball_joint_lookAt_loc</i>. Call it <i>aim_orient_driver_jnt</i>. By creating a fresh joint in the perspective view, it will be aligned to the world, which is important for a later step. Duplicate this joint and move it up a little bit, then parent it to the driver joint. This will be the <i>aim_orient_driver_jnt_end</i>. Point constrain this joint chain to the foot control WITH offset. You can see in the image above that the joint chain is properly positioned and constrained to the foot control.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Now create a single chain IK solver from <i>aim_orient_driver_jnt </i>to <i>aim_orient_driver_jnt_end</i>. Name it <i>aim_orient_driver_ikHandle</i> and point constrain it WITHOUT offset to <i>ball_jnt</i>. This joint chain now closely reflects the orientation of the leg as you move the foot control. </div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
We've already set up a group, centered on the ankle, that can drive the <i>ball_joint_lookAt_loc</i> around the ankle. Simply use the connection editor to wire the Z rotation from <i>aim_orient_driver_jnt </i>to the Z rotation of <i>ball_joint_aim_grp</i>. Since both the group and the driver joint were created in alignment with world space, their axes correspond perfectly.</div>
<div style="text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaTqTnVGDH67PfVt4D53pR0ZUROP_R3hY4J5QYXhN5S6B45A0_Uij_ky7g7we5tdyy6a0SICVinYxCL7kfXsK628gYUgXq1_Rtoi_cxuKlNPdqbZmlHFN3GPquLfyUTAcfdYExFZ3hPv_S/s1600/mechLeg14_finalSetup_border.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="222" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaTqTnVGDH67PfVt4D53pR0ZUROP_R3hY4J5QYXhN5S6B45A0_Uij_ky7g7we5tdyy6a0SICVinYxCL7kfXsK628gYUgXq1_Rtoi_cxuKlNPdqbZmlHFN3GPquLfyUTAcfdYExFZ3hPv_S/s320/mechLeg14_finalSetup_border.jpg" width="320" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;">The completed offset ball joint setup.</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Now, as you move the foot around, the aim locator rotates around the ankle, so that the angle of the leg closely matches the angle between the ball joint and the aim locator. As you can see from the final image above, the ball joint appears to have the proper behavior, even in very extreme poses.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
This was a fun challenge to work out, and I hope anyone reading this can get some ideas about how to solve similar problems with their own rigs.</div>Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-26979859358673484632012-08-01T19:39:00.003-07:002012-08-01T19:48:56.931-07:00Starting to use custom node networks<div style="text-align: center;">
<iframe src="http://player.vimeo.com/video/46791270?portrait=0" width="500" height="281" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe> <p><a href="http://vimeo.com/46791270">Using Custom Node Networks in Rigging</a> from <a href="http://vimeo.com/kylemr">kyleMR</a> on <a href="http://vimeo.com">Vimeo</a>.</p></div>Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-35568662518562776642012-07-30T05:15:00.000-07:002012-07-30T05:38:55.266-07:00Vector Angle setupFor the past two days or so I've been thinking about vector math, trying to pull off a node setup like <a href="http://www.andylt.com/1/post/2012/03/vloume-range-node.html">this one</a>. I've got the concept in my head, but I'm still working on the details of the implementation, as far as the actual math goes. I've been studying the Maya API as well, and while I'm understanding how everything fits together (the general structure of API plugins), I just don't have enough experience with the API classes to know which MObjects and functions to use to get what's in my head into the code and onto the screen. So I figured I'd mock up a simple node network to see what I could do, albeit with a limited understanding of the math involved. I'd still like to get an API locator node implementation figured out, but I figured I'd share what I've come up with so far.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" frameborder="0" height="375" mozallowfullscreen="" src="http://player.vimeo.com/video/46614805?portrait=0" webkitallowfullscreen="" width="500"></iframe> </div>
<a href="http://vimeo.com/46614805">Ranged Vector Angle Setup</a> from <a href="http://vimeo.com/kylemr">kyleMR</a> on <a href="http://vimeo.com/">Vimeo</a>.<br />
<br />
<br />
Basically, I'm getting an aim vector from an object (in this case, the cone) by using a locator. I subtract the position of the cone from the position of the locator to get the aim vector (which is a normalized vector, since the locator is one unit from the cone) and then I do the same for the target locator, which gives me a target vector. I take the dot product of those vectors and pipe them into a setRange node, which allows me to remap the value between 0 and 1, as well as change the high and low boundaries of the calculation. Pretty simple. Basically, this sort of setup can work as a pose space deformer, although I'm just driving the scale of a sphere for the sake of visualization. The process only takes a few minutes to set up by hand, but I scripted it out just for the hell of it. If anyone is interested in the code just let me know.<br />
<br />
This problem has been churning in my mind for a few days now, and I'll definitely be taking the solution further.Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-18607733400439804882012-07-28T17:14:00.002-07:002012-07-28T17:14:53.135-07:00Check Symmetry UtilityA little while ago I worked out this little melscript utility to check for non-symmetrical vertices in your models, and today I decided to turn it into a python script and rework some of the logic. Basically, you run the script and it returns the number of non-symmetrical vertices in the mesh you have selected. It also selects those vertices for you, so you can see them in the viewport. If you want, you can also specify a certain mesh, mirror axis (the plane across which the symmetry will be determined, default is the YZ plane), tolerance, and turn off the selection of the verts at the end. That way you could use this as a utility to another script that deals with symmetrical meshes. Grab it here: <a href="https://docs.google.com/open?id=0B-8KqCBgGipxQUstT3FDeEhoalE">checkNonSymmetricalVerts</a>.<br />Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-85909050411509076102012-07-27T14:00:00.000-07:002012-07-27T14:00:11.052-07:00Stick a fork in it... because I finally finished my modular autorig. Developed by following along with 3DBuzz's monstrous 50+ hour 'Developing Modular Rigging Systems with Python' DVD, this autorig is by far the most elaborate and involved scripting project I've ever taken on. This all started because I wanted to build my own autorig, but didn't really know exactly where to start, so I picked up the learning DVD to get a better idea of the process. I definitely learned a ton doing this project, so I wanted to share some of those insights here. Below is a quick demo of the system's functionality.<br />
<br />
<div style="text-align: center;">
<iframe allowfullscreen="" frameborder="0" height="281" mozallowfullscreen="" src="http://player.vimeo.com/video/46506061?portrait=0" webkitallowfullscreen="" width="500"></iframe> <br />
<a href="http://vimeo.com/46506061">Modular Autorig Demo</a> from <a href="http://vimeo.com/kylemr">kyleMR</a> on <a href="http://vimeo.com/">Vimeo</a>.</div>
<br />
<div style="text-align: center;">
<h3>
<u>The process:</u></h3>
</div>
The autorig itself spans over 30 python files, written from scratch, and it took a little over 2 months working off and on to finish. The process was pretty simple at first; watch the videos and write the code as they write it, testing frequently. However, it quickly became apparent that the process wouldn't just be a walk in the park, copying code the whole way. Discrepancies in the way UI code is handled by the pre-QT interface of Maya 210 (which was the version the system was developed in) and Maya 2012 meant that subtle changes had to be made in order for all of the elements of the user interface to be displayed correctly. Also, fixing any bugs that I discovered while testing (most due to my own typos, I'll admit) was totally up to me.<br />
<br />
I coded the entire system in Notepad++, rather than relying on the benefits of code completion and error checking in an IDE such as Eclipse. The result is that I've grown extremely adept at catching my own syntax errors, and quickly fixing those that do manage to slip through the cracks. Even some of the trickier and more insidious bugs didn't last much longer than 30 minutes or so of solid debugging.<br />
<br />
The entire system is scripted in the maya.cmds implementation of python rather than pyMel. This has the effect of making the code much more verbose and quite a bit harder to read... but overall it wasn't that bad.<br />
<br />
<div style="text-align: center;">
<h3>
<u>Insights:</u></h3>
</div>
Since I took this on as a learning experience, I wanted to really break down what I learned, the good, the bad, and the ugly, from this project.<br />
The main thing that I learned was that, in a project of this magnitude, construction is king. I was reading <i>Code Complete</i> by Steve McConnell while working on the system, and it was a great combination. It really helped drive home the importance of well designed, well documented, well constructed coding. I'll get more into that in a second.<br />
<br />
Since I had planned to take what I learned and apply it to a new autorigger of my own design, I noted a few things that I would change in my system. The first was the reliance on naming convention and namespaces to store and recall information about where a particular rig part came from and what it could do. This led to namespaces nested three layers deep, and an outliner that quickly became a solid wall of text. It worked, but storing information inside of metaNodes connected directly to rig parts would have been a more elegant, more powerful, and a cleaner solution. Second, once you 'lock' the rig and turn the blueprint modules into actual joints, that's it. the process is pretty much irreversible. It would have been nice to be able to see the joint locations, and then be able to go back and make changes. The other big design choice that I would avoid was the use of locked containers. Containers in Maya may be powerful, and theoretically awesome from a rigger's point of view (animators can't rename or delete important nodes, everything is bundled together), but in practice they're pretty annoying. Having to constantly unlock nested containers in order to debug things is slow and painful. In addition, attributes published to containers behave strangely in the channel box, disallowing middle-mouse scrubbing to change attribute values, and turning the clean list of attributes into an organizational nightmare.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh80Uf1_JN2QiFY3jT5IY1rBor9qY_thpWQE1EMbwEzlkijoGA5kx8CEft-FS0daaFlr_ktZFoqtMas9Npp4fJxnx3NKUfH4yUgmNbwajwmt79XEEaLnOryC7Bi7GVrPWJ5THR6Q7IdbyDc/s1600/containers_channelBox.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="243" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh80Uf1_JN2QiFY3jT5IY1rBor9qY_thpWQE1EMbwEzlkijoGA5kx8CEft-FS0daaFlr_ktZFoqtMas9Npp4fJxnx3NKUfH4yUgmNbwajwmt79XEEaLnOryC7Bi7GVrPWJ5THR6Q7IdbyDc/s320/containers_channelBox.jpg" width="320" /></a></div>
<div style="text-align: center;">
Seen here: the arm controls? I'm not even sure...</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
The main thing I took away from this project though, was the importance of construction. I want to be clear: I mean no disrespect or insult to the guys who developed this system. It was a rapidly developed prototype, meant as a proof of concept and a learning tool -- not a production ready rigging pipeline. What the guys at 3DBuzz managed to pull off in this DVD was nothing short of awesome. That being said, the code itself is pretty rough.</div>
<div style="text-align: left;">
There is almost <i>no documentation whatsoever</i> to the code. This was addressed directly in the videos a few times, as the addition of comments and documentation would have made the videos even longer, but even so, it makes the system a nightmare to read through. I considered adding documentation myself, but I would have never been able to keep up with the videos, and I wouldn't have truly understood the code well enough as I was writing it to comment it well anyways. Since the system was developed bit by bit, there were pieces of the code that weren't actually implemented until many hours later. They were only added when they were because the architect of the system knew that those functions would be needed eventually.</div>
<div style="text-align: left;">
I would have liked to see more wrappers to Maya functions. There are arguments against this sort of thing (see the "<a href="http://dl.dropbox.com/u/3559565/rigging_system.html">Wrapping Commands in Maya</a>" post on Sune Kempf's rigging page), but after you've written this for the umpteenth time:<br />
<br /></div>
<div style="text-align: left;">
<span style="text-align: -webkit-auto;"><code></code></span><code>
</code></div>
<div style="text-align: left;">
</div>
<code>cmds.xform(obj, worldSpace=True, absolute=True, translation=cmds.xform(target, q=True, worldSpace=True, translation=True))</code><br />
<br />
You'll find yourself wishing you had declared a utility function:<br />
<code>
</code><br />
<code>utils.matchWorldSpacePosition(obj, target)</code><br />
<br />
Stuff like this would have also made the routines smaller, since they tend to run on (and on and on).<br />
<br />
The biggest issue I had with the code though, and the one thing that would really make this system solid, was the problem of information hiding, or more specifically, the lack thereof. Throughout the system, routines and functions made assumptions about the data that was being returned to them. This may have worked, since the assumptions were essentially hard-coded by the system's architect himself, but it made the code nigh impossible to read and follow in places. It also cause random bugs to pop up all over the place.<br />
For instance, in one function, there was a check to see if a spine joint chain had 5 or more joints, and if it did, it could have a certain control rig installed on it. The code to check that condition was:<br />
<code></code><br />
<code>blueprintJoints = utils.findJointChain(blueprintJointsGrp)</code><br />
<code>if len(blueprintJoints) >= 6:</code><br />
<code> # do stuff</code><br />
<br />
This seems like a typo. It seemed like a typo to me as I wrote it, and it took me a second to remember that the 'findJointChain' function returned the parent group of the joints in index one of the returned array. So instead of checking to see if there were 5 joints in the returned array, you had to add one, in order to account for that group. You'd never guess that was the case from the title of the routine, but this is one of many examples of this sort of thing. A better implementation of this check would be to write a routine that really did only return the joints (the existing routine could continue to return the group as well), and use a named constant instead of the magic number 6:<br />
<code>
</code><br />
<code>MIN_JOINTS_IN_SPINE_RIG = 5</code><br />
<code>blueprintJoints = utils.findOnlyJointChain(blueprintJointsGrp)</code><br />
<code>if len(blueprintJoints) >= MIN_JOINTS_IN_SPINE_RIG:</code><br />
<div style="text-align: left;">
<code> # do stuff</code></div>
<div style="text-align: left;">
<br />
This makes the code much more readable, almost self-documenting.</div>
<br />
<div style="text-align: center;">
<h3>
<u>ALL the learning:</u></h3>
</div>
<div style="text-align: left;">
This post is getting crazy long, so I'll try and wrap it up. What did I learn from this project? First, I got an INCREDIBLE amount of experience, writing the code, testing it, and debugging it. Second, I got to see how the whole system fits together. How multiple files and classes interrelate and work together to create an incredible amount of functionality. I learned some cool python tricks and techniques as well, such as using __import__ instead of the usual import when you need to bring in a module that is being stored as a variable, and you don't explicitly know which module it is. I also got to use a bit of vector math, which got me thinking of solutions to problems that stumped me a week ago (matching pole vector locations with a no-flip leg setup? I'll probably write a post about it). I also saw how the complexity of a system grows exponentially, and how the design is so import when it comes to the scope of a project, and determining which features get implemented or not.</div>
<div style="text-align: left;">
Finally, I'd just like to say again, what an undertaking the creators of this system have pulled off. Not just building the autorig, but deconstructing it and rebuilding it in a tutorial format, constructing the system piece by piece, adding functionality and keeping it running and testable at every stage. Kudos to those guys at 3DBuzz. Would I recommend the DVD to others? If you've got the basics of python and scripting for maya down, and you're not intimidated by a challenge -- definitely. You'll learn a ton, I know I did.</div>Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com2tag:blogger.com,1999:blog-8999147182496488461.post-79445355252644813532012-07-03T18:24:00.003-07:002012-07-03T18:24:43.611-07:00mr_motionTrail is available now!The mr_motionTrail utility that I demo at the end of my current rigging reel is now available for download at <a href="http://www.creativecrash.com/maya/downloads/scripts-plugins/animation/c/mr_motiontrail">CreativeCrash</a>! I had some people expressing interest in using it for their own animation work, so I decided to put it online for download. Go get it, it's free!Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-50521995274443367532012-06-23T03:12:00.001-07:002012-06-23T03:12:16.347-07:00Facial rigging class at CGSocietyI just signed up for Judd Simantov's character facial rigging workshop on CGSociety! I've been super excited for this class ever since I saw his <a href="https://vimeo.com/18140376">demo reel</a>. The class starts next month, and I'm looking forward to learning all sorts of fun things that I can use for my upcoming rigs for a short film I'm working on.<br />
<br />
<a href="http://workshops.cgsociety.org/courseinfo.php?id=275">Check it out!</a>Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-48605263082899150872012-06-04T02:29:00.000-07:002012-06-04T02:29:09.681-07:00Rigging Reel<iframe allowfullscreen="" frameborder="0" height="281" mozallowfullscreen="" src="http://player.vimeo.com/video/43377702?portrait=0" webkitallowfullscreen="" width="500"></iframe> <br />
<a href="http://vimeo.com/43377702">Kyle Mistlin-Rude Rigging Demo 2012</a> from <a href="http://vimeo.com/kylemr">kyleMR</a> on <a href="http://vimeo.com/">Vimeo</a>.<br />
<br />
<br />
These are a few of the things I've been working on in the past couple of weeks. I'm currently also developing a modular auto-rigging setup, and there's another rig or two coming down the pipeline, so expect to see some more updates soon!<br />
<br />
A few notes on the utilities/scripts I wrote:<br />
<i>SpareParts: Rig Utilities:</i><br />
Fk/Ik matching is handled using metaNodes and a total of 3 functions, and the setup could conceivably be reworked into an even more generic framework. As it is right now, one function handles getting the selection and connecting to the metaNode, which in turn connects to rig components involved in the fk/ik switching process. The other two functions take care of fk to ik switching and vice versa. Any hinge jointed limb with a similar blending setup would work with these functions, allowing for a lot of functionality with very limited script. There's also an option to set keys to 'bake' the blend state and controller positions.<br />
<br />
Space switching is handled using a similar node system, and the same set keys option is available for baking the parent space state.<br />
<br />
Baking animation from the control rig to the bind rig, as well as rig export will also be handled by this script, but at the time of this reel, it was not implemented in the UI. (I had yet to get my hands on the final character model and do some engine tests, and I didn't want to distribute an untested script to the animators.)<br />
<br />
The UI updates based on the current selection, so that only the options that apply to the selected control are available to the user. For instance, any selecting any control on one of the arms will allow the user to switch fk/ik state, but if any other control is selected, the button will be disabled. The same goes for the space switching and export panels.<br />
<br />
<i>mr Motion Trails:</i><br />
This is a handy tool for animators tracking arcs. It uses Maya's built in motionTrails, but in a hierarchy independent of the animated control. This way, the point from which the trail is generated can be moved. In the example on the reel, I created a trail on the head control, which by default tracks an arc from the pivot point of the head joint. I then re-position the trail to draw from the tip of the character's nose, so the trail picks up head rotation and gives me a nice arc. In addition, the user can choose to add spacing markers to the trail, in order to better see slow-ins and slow-outs. The interface also gives the user an easy way of editing trail parameters, as well as removing the trails from the scene. The trails are not selectable in the viewport, so they don't interfere with animation control selection.<br />
<br />
The script was written using pyMel, which seems to lack support for certain motionTrail nodes, causing errors whenever they are cast into PyNodes and variables. Finding a workaround to this was a fun challenge, since I needed to be able to access those nodes in order to edit their settings on the fly via the tool. I'm planning a future update for the script which will move away from Maya's motion trails and instead utilize a system of my own. I'll also include support for user selected colors and more display options.Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-71136404956291901502012-05-23T01:26:00.000-07:002012-05-23T01:26:13.778-07:00FK IK matching with a node networkLately I've been exploring some of the applications of metanodes in rigging, and I came up with this setup for fk/ik matching. Using nodes to connect to the components of the arm rig allows me to run a very compact matching script with essentially no redundant code, and I can switch states with any control in the arm selected. The best part is, the node connections are direct, so the script will still work even if parts of the rig are renamed or the rig is referenced. This sort of setup will work across any limb that is set up similarly, so even if you have a rig with four (or more!) arms, the same script will work for any of them. I'm looking forward to figuring out even more uses for metanode networks.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCZx5VBzbGsz3PpKyj5YUun23kT2QWIQPtB-QdO7MaL1VVSZNVo4nWygmzOUMdYhCkUsCmF4Zl4mB2Aaaofvqs6l51LC-O28SDQH0kmDE_hbVuSVRLy8jKH2NPSo9iY4PJyiyA6fTVqfWo/s1600/metaSwitch.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCZx5VBzbGsz3PpKyj5YUun23kT2QWIQPtB-QdO7MaL1VVSZNVo4nWygmzOUMdYhCkUsCmF4Zl4mB2Aaaofvqs6l51LC-O28SDQH0kmDE_hbVuSVRLy8jKH2NPSo9iY4PJyiyA6fTVqfWo/s320/metaSwitch.jpg" width="320" /></a></div>
<div style="text-align: center;">
<br /></div>Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com1tag:blogger.com,1999:blog-8999147182496488461.post-50015306215119845542012-05-22T01:58:00.003-07:002012-05-22T01:58:43.622-07:00Almost done<div class="" style="clear: both; text-align: center;">
Here's a little preview of something I'm wrapping up. This is the foot setup for the character rig I'm working on for the Frogasaurus Mech team's game. The rig is in the final stages of completion, and I'm preparing to write some ik/fk matching and export utilities.</div>
<div class="" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHnvrJ8-2QhNPZ2VfCEVKEKHholfatFcVg3B-dIwO9_hfl506XY9np6OxAjXou6tj4mfQxCPG891Utl2JLiOx0tnM4aiafOextxTiVqnoZY7AlrgqzRy1TCrqPjKWVe9pEjIyNV2SAKe3Q/s1600/footRig.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHnvrJ8-2QhNPZ2VfCEVKEKHholfatFcVg3B-dIwO9_hfl506XY9np6OxAjXou6tj4mfQxCPG891Utl2JLiOx0tnM4aiafOextxTiVqnoZY7AlrgqzRy1TCrqPjKWVe9pEjIyNV2SAKe3Q/s320/footRig.jpg" width="320" /></a></div>Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-26761905352238274392012-05-02T21:07:00.000-07:002012-06-05T03:15:57.522-07:00Zbrush FinalBeen working on these two projects for quite some time now. Finals are done with now, so it's time to lay these to rest and get a move on my other projects.<br />
<br />
<div style="text-align: center;">
The first project was a human character in the style of an existing video game, in this case, it's Assassins Creed 2.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvMxfT3Buea8jC2AZsNbH7vAvJaWpHNUcazhKiTr8wbzgPxHBbjZCKVaZJqCtjBxzqHGjX3mBthi9IuOXbtIj0Rkie9PVnlfoEVli4gWCS3z6G1J0TFKbmPFW6Kwt9Yeu7i96MVHB7GAcs/s1600/kylemistlinrude_cg305s12_biped_beauty.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvMxfT3Buea8jC2AZsNbH7vAvJaWpHNUcazhKiTr8wbzgPxHBbjZCKVaZJqCtjBxzqHGjX3mBthi9IuOXbtIj0Rkie9PVnlfoEVli4gWCS3z6G1J0TFKbmPFW6Kwt9Yeu7i96MVHB7GAcs/s320/kylemistlinrude_cg305s12_biped_beauty.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGF_01u17ibKbvZRR_P2JWNiXmmW2AfiA7cv1PwHJBgu6NcIGWzlghxS16tt6VpCMXWE11N6rv6PylPgpzJe10rEwpNLaxlafi26dgKEFuyMVYygYitlVnya66waOuWqFj8CBafU6S6b67/s1600/kylemistlinrude_cg305s12_biped_process.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGF_01u17ibKbvZRR_P2JWNiXmmW2AfiA7cv1PwHJBgu6NcIGWzlghxS16tt6VpCMXWE11N6rv6PylPgpzJe10rEwpNLaxlafi26dgKEFuyMVYygYitlVnya66waOuWqFj8CBafU6S6b67/s320/kylemistlinrude_cg305s12_biped_process.jpg" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
The second character was a quadrupedal creature that was either domesticated by humans, or fought them.</div>
<div class="separator" style="clear: both; text-align: center;">
I chose to make a giant lizard that carries a barge across the desert.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYe6cu3tFgdAlcNLIoSVgnPi-l352q68sQWpbxC1R3gI9ExKXUpLsZZtQnvoqnjQ1VCmVv85csr48xjLdJZr226MJtcMwTn9FKz4fzJm_8x3fPXmb3dCTPLE5z2BdvQTSJLKqbUK5CrPEN/s1600/kylemistlinrude_cg305s12_quad_beauty.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYe6cu3tFgdAlcNLIoSVgnPi-l352q68sQWpbxC1R3gI9ExKXUpLsZZtQnvoqnjQ1VCmVv85csr48xjLdJZr226MJtcMwTn9FKz4fzJm_8x3fPXmb3dCTPLE5z2BdvQTSJLKqbUK5CrPEN/s320/kylemistlinrude_cg305s12_quad_beauty.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYDySsn0MwwN-pN-7wOBbdaNX4HWwr6cdU0vVkjVEUYDZug9RYwdhhFc8FBDBdKflw8UL7xnLg8P3UZEmT568WwfW83moVpINY_QdsUhPi0JTWwT6mTdZ5yTM4fx_fhcWWxWAz7YLzNJoB/s1600/kylemistlinrude_cg305s12_quad_process.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYDySsn0MwwN-pN-7wOBbdaNX4HWwr6cdU0vVkjVEUYDZug9RYwdhhFc8FBDBdKflw8UL7xnLg8P3UZEmT568WwfW83moVpINY_QdsUhPi0JTWwT6mTdZ5yTM4fx_fhcWWxWAz7YLzNJoB/s320/kylemistlinrude_cg305s12_quad_process.jpg" width="320" /></a></div>
<br />Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-21418530866522649852012-05-01T03:11:00.002-07:002012-05-01T03:11:18.240-07:00mr_motionTrail<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzF0yVSzIwEmsS5uChnKcY8x-Nf5YoR3VxCZnMXShchfpLrXwIT7CzHMbxCNpR3NH5uLNdgwftoUs7tsAbusLJsj7lLEliN06b6fqOhExoEVv03duzI-btijAIeDn4VdBqgfz9LAwozz0R/s1600/mr_motionTrail+screenshot.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="220" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzF0yVSzIwEmsS5uChnKcY8x-Nf5YoR3VxCZnMXShchfpLrXwIT7CzHMbxCNpR3NH5uLNdgwftoUs7tsAbusLJsj7lLEliN06b6fqOhExoEVv03duzI-btijAIeDn4VdBqgfz9LAwozz0R/s320/mr_motionTrail+screenshot.jpg" width="320" /></a></div>
<br />
Finished up a python script I've been writing for Maya. It extends the functionality of Maya's built in motion trails to track the motion and spacing of animated controls from any point--you can easily track arcs on a character's nose, fingers, props, etc. It also keeps track of the trails in the scene and allows the user to edit the settings of existing trails.Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-35491339548378470242012-03-29T18:13:00.001-07:002012-03-29T18:18:30.633-07:00An awful lot of running.<div style="text-align: center;"><span style="font-family: Georgia, serif; "><iframe src="http://player.vimeo.com/video/39335604?title=0&byline=0&portrait=0&loop=1" width="400" height="300" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe><p><a href="http://vimeo.com/39335604">See Joe Run. Run, Joe, Run!</a> from <a href="http://vimeo.com/kylemr">kyleMR</a> on <a href="http://vimeo.com">Vimeo</a>.</p><p>Playin' around with this little goober. Joe Rig made by Michel Urbanek.</p></span></div>Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-12256080763652561112012-02-29T04:47:00.002-08:002012-02-29T04:54:53.989-08:00Hard Surface Workflow<div style="text-align: center;"><span ><br /></span></div><span ><span style="font-size: 100%;">Here's a little project I've been whittling away at for a day or two. It's based on a crate concept </span></span><span ><span style="font-size: 100%;">from Quake 4 by </span></span><a href="http://www.autodestruct.com/" style="font-family: Georgia, serif; font-size: 100%; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; ">Paul Richards</a><span ><span style="font-size: 100%;">. I'm trying to get through the whole pipeline for modeling a high-poly asset and baking to a low poly. This guy is a little plain, but I wanted to play with something simple before I tackle a larger (and more complex) project.</span></span><div style="font-family: Georgia, serif; font-size: 100%; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; "><br /></div><div style="font-family: Georgia, serif; font-size: 100%; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; ">Progress so far on the high poly:</div><div style="font-family: Georgia, serif; font-size: 100%; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; text-align: center; "><br /></div><div style="font-family: Georgia, serif; font-size: 100%; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; text-align: center; "><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiK1SDkEkvELVo8s_Ay5RUMJJ-o5x8ety90aMag6b8s2oOoc_eNCRVduphD_QWHGE5OM8ALYl5oiU9fsTDx3FcVK8D0eFYX8-HIDs6FhNznyzUnAFXdCMT02G_QUBOrioS-AESgWeJiDYTx/s320/progress_01.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5714540047139372274" style="font-family: 'Times New Roman'; font-size: medium; display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; cursor: pointer; width: 320px; height: 202px; " /></div><div><br /></div>Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-73696744345460719312011-11-17T11:38:00.000-08:002011-11-17T11:41:49.734-08:00It's about time<div><iframe src="http://player.vimeo.com/video/32251833?title=0&byline=0&portrait=0" width="398" height="264" frameborder="0" webkitallowfullscreen="" allowfullscreen=""></iframe><p><a href="http://vimeo.com/32251833">Go get 'em, Starsky</a> from <a href="http://vimeo.com/kylemr">kyleMR</a> on <a href="http://vimeo.com">Vimeo</a>.</p></div><div><br /></div>Finally getting around to posting this. A little test I finished about a month ago. I still want to try another pass at polish and get a decent render of it, but for now, here ya go.Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-50576710886056463732011-11-07T13:45:00.001-08:002011-11-07T14:24:19.939-08:00More projects<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6y8p2Y70zSEGLxfWJq5EymP1zMemTgKfD7UvljvzE9_cEFw1Oy0JEc8MSsQEm6BKS0kzZNPiaAGrq-30Pg6TCeMC-LLzIitgxpcsWXFIYYIkhaYkQUbsXUFXFAjotQHQV4e2NkO4HxBul/s1600/testLookandFeel.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 214px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6y8p2Y70zSEGLxfWJq5EymP1zMemTgKfD7UvljvzE9_cEFw1Oy0JEc8MSsQEm6BKS0kzZNPiaAGrq-30Pg6TCeMC-LLzIitgxpcsWXFIYYIkhaYkQUbsXUFXFAjotQHQV4e2NkO4HxBul/s320/testLookandFeel.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5672382740038545106" /></a><br />Just something I whipped up today... playing around with the character I posted earlier, roughing out an environment and playing with some lighting for a look and feel shot. Plenty of post in Photoshop :PAnonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-47453855741201462152011-11-06T01:00:00.000-07:002011-11-06T01:48:48.435-08:00Background art dump<div style="text-align: center;"><br /></div><div style="text-align: center;"><br /></div><div style="text-align: center;"><br /></div><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEin3NVzmHqSKN38qQUigqxF0KchCg6ah8p7BFiy8sR6ee_M6BxkXnkV75lmDd90jDYjfEtc7XbC35maUV0gwSpIipNL4cCNQiN7DlBfPdCEehySmgT-L-3fR7yKEE-xUjixrTfm-RMDvnbZ/s320/one_pt_perspective_01.jpg" style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 263px; height: 320px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5671815146050972770" /><span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; "></span><div><div style="text-align: center;"><span class="Apple-style-span" ><br /></span></div><div style="text-align: center;"><br /></div><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhd5KVfAkBvEJkVwnOMz8Ok50R7rNLLzp7SJ5vY1ksVn2_1whZB165By2gXwvl9JcdvTNM0GfcYeb9Lc_rarodQ0IxaU1f7zpMBTn4peAiM0Cd7wHN6_Cr6bDg2fONOttG-fR1Bm6i4OyML/s320/two_pt_perspective_01.jpg" style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 309px; height: 320px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5671815151597507698" /><span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; "></span><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9t3VcVRaI7ncuFt2p353aqr811PBhuAQnUmG1Om_AF8TPVjQEymhzFqTnG3I9jzIm1tBBrey6jXiTwhYP8j2aaH60UTLnpnmtTelY1yx0LtGX4MKKbleLFQ4jZu4vfPX1cOmOhdSahoOc/s320/houseFinal.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5671815160569512882" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 206px; " /><span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; "><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3pLQT8isJm5elMjCnZytYf-v3H2KK1QCWUtSXbpOa2BvF0_FU3OE71v8zSGV7rnms2F3qI4VwTU1UpX7rK1JbtoZ9ImHCrBmjJL6wZjxbOLSptR3xVH-HJW1gfT6_eZsbPARhZX5jfftO/s320/bladerunner_final_02.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5671815167253965090" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 320px; height: 256px; " /></span></div><div><div style="text-align: center;"><span class="Apple-style-span" ><br /></span></div><div><div style="text-align: center;">Here's some drawings and paintings from my background art class with <a href="http://happybrush.blogspot.com/">Peter Moehrle</a>. I was taking the class last year, but dropped it in order to ease my workload and spend some more time on other projects. It's been cool to see how much I've improved at this sort of stuff since last year.</div><div style="text-align: center;"><br /></div></div></div>Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-89542634798822422612011-11-04T22:16:00.000-07:002011-11-04T22:19:34.444-07:00Projects<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhW7YKJ1BW-JPzp5XYgaZFCQlLVN8WRJue_Nov9xuv93ZuCqkbYL6vwB-cftC5-51BVsTtjydNnWkqyrR2gVrgldtXWc8bRWRSntOns8JolNhNXKjlUbTKUJitTitNO_oScJ5YOaFcjKsVQ/s1600/character.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 316px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhW7YKJ1BW-JPzp5XYgaZFCQlLVN8WRJue_Nov9xuv93ZuCqkbYL6vwB-cftC5-51BVsTtjydNnWkqyrR2gVrgldtXWc8bRWRSntOns8JolNhNXKjlUbTKUJitTitNO_oScJ5YOaFcjKsVQ/s320/character.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5671377032941878002" /></a><br />Been working on an animated short for school. Here's the character so far... missing some details at this point, and it's just a rough texture so far. Lots more to do!Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-22463138189943796352011-10-16T18:34:00.000-07:002011-10-16T18:39:14.996-07:00Just playin<div style="text-align: left;">I decided to check out <a href="http://www.joshburton.com/">Josh Burton's</a> Morpheus rig, and after playing around with it, I'm going to use it for my next little shot. I've been doing some little tests with it to get familiar with its functionality. It's a really fun rig, with a ridiculous amount of control! So here's a quick sassy morphy lady :)</div><div><br /></div><div style="text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYdMYvwGQikcBkGb_Ccs-R0rqshd1SLNfo9c2QO9_yqDhLj6X2qlVEcqOB8ccTIKyygTNj_J4_nXc6IiLAKEAT68W7MBk_KLzqXAp_jlAqxsjCFBeE5lMkPeGTM4hE3FK63WJH6xt_bgL8/s320/sassyLady.jpg" style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 214px; height: 320px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5664269468525484754" /></div>Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-62250974209437535262011-09-13T20:36:00.001-07:002011-09-13T20:38:34.623-07:00Pose Assignment<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVMqUpsoLRfgqm9lRtMeRU42ibWMmKudhh7xE9WA2c_c6nBu7DmS3K2771X7eo_74PIgZNitVBcQW9n-LdhJ7zDv0SjweSyxw2mWJpejeysXaSbMJFa5dvnNvQjgYSsfNWcxN9E8B8BnGS/s1600/kylemistlinrude_exhausted_render.jpeg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 256px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVMqUpsoLRfgqm9lRtMeRU42ibWMmKudhh7xE9WA2c_c6nBu7DmS3K2771X7eo_74PIgZNitVBcQW9n-LdhJ7zDv0SjweSyxw2mWJpejeysXaSbMJFa5dvnNvQjgYSsfNWcxN9E8B8BnGS/s320/kylemistlinrude_exhausted_render.jpeg" alt="" id="BLOGGER_PHOTO_ID_5652054445690669154" border="0" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZNgPuZX33wD2nAf0tFCMquLQXnNlRQ0ATz58Q184NWUAKMGxkeXrD-m_39NIBC5izychPbhVoLtTh7SJkq2aFqg9NnNGX19Rm2b7Ubo64jZBByaNnWl-2YCTlV7E_WPPhegnTUfs-OuX_/s1600/kylemistlinrude_observation_render.jpeg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 256px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZNgPuZX33wD2nAf0tFCMquLQXnNlRQ0ATz58Q184NWUAKMGxkeXrD-m_39NIBC5izychPbhVoLtTh7SJkq2aFqg9NnNGX19Rm2b7Ubo64jZBByaNnWl-2YCTlV7E_WPPhegnTUfs-OuX_/s320/kylemistlinrude_observation_render.jpeg" alt="" id="BLOGGER_PHOTO_ID_5652054450555706418" border="0" /></a><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9yiQ4_jqVYf16vFvQ8jo5cUdXKZpYOs7ctCt45afLIOaotM8pOsI1-g6DhoL8tL_X3XuC7ZqqOvcDYzAhH6M4eX10-VAyEj-_ajLUeEVz8rAtJSEce6ZaawvtP_M2qhy__keaaYqsIaSe/s1600/kylemistlinrude_balance_render.jpeg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 256px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9yiQ4_jqVYf16vFvQ8jo5cUdXKZpYOs7ctCt45afLIOaotM8pOsI1-g6DhoL8tL_X3XuC7ZqqOvcDYzAhH6M4eX10-VAyEj-_ajLUeEVz8rAtJSEce6ZaawvtP_M2qhy__keaaYqsIaSe/s320/kylemistlinrude_balance_render.jpeg" alt="" id="BLOGGER_PHOTO_ID_5652054298379554466" border="0" /></a><br /><div style="text-align: center;">Part of an assignment for my current animation class :)<br /></div>Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0tag:blogger.com,1999:blog-8999147182496488461.post-14345087099991458502011-08-12T00:08:00.000-07:002011-08-12T00:15:31.280-07:00Siggraph AftermathWhoo! Just got back home from Siggraph, and I am EXHAUSTED. At the same time, I'm feeling totally supercharged. To all the cool folks I met in Vancouver, you guys are awesome! It was great to geek out with everyone. Wishing you all success in your studies and professional endeavors.
<br />Now that I'm back, I feel like I definitely have a better understanding of the direction I need to head in. I'll definitely be heading back out to Siggraph 2012!
<br />I did a fair deal of sketching in between production sessions and screenings, so as soon as I get a chance, I'll post some of those pages.
<br />
<br />Stay classy everyone!
<br />Anonymoushttp://www.blogger.com/profile/02512634775553564764noreply@blogger.com0