Saturday, August 1, 2015
I built a command that searches the dependencyGraph for a given node type. You specify the node type to search for and the direction to search in. YOu then call it just as though it is another maya command. So rad as this can now be built into my code as if it were just part of maya.
So my command is: findConnectedNodeType. You call it like:
node = cmds.findConnectedNodeType('blendColors','up')
The return value is either False or the found node name. The command looks through the upstream dependencyGraph until the first instance of that node is found. It then stops the iteration and returns the node name.
Cool stuff I learnt.
To return from a MPxCommand you must use the public function of MPxCommand setResult.
self.setResult(return value goes here)
This comes at the end of the doIt() function.
Enumerators are also making a bit more sense now that I am using them more. For example I had to use MItDependencyGraph. You can specify the direction to search, up or down stream. The help docs show this for the direction.
MItDependencyGraph ( MObject & rootNode,
MPlug & rootPlug,
MIteratorType & infoObject,
Direction direction = kDownstream,
Traversal traversal = kDepthFirst,
Level level = kNodeLevel,
MStatus * ReturnStatus = NULL
So because this enumerator is a child of the class MItDependencyGraph , it must be specified in context of this class hierarchy. (OpenMaya.MItDependencyGraph). You can then set any number of the enum options that the help displays, in this case kDownstream or kUpstream and the class call will know to look for that enum if you set it (you don't have to specify anything and maya will use the default)
Ok. Hope that is a bit clearer than mud. Till next time.
Friday, July 31, 2015
Thursday, July 30, 2015
Test stretch node plugin using matrix connections rather than channel connections. This video compares two test plugins briefly. One plugin using Matrix connections, the other using Transform channel connections. This is a test purely to look at different types of data handling and how I can use Mayas API to simplify node graphs for common rigging techniques.
However NZ has been really nice to us. I get this feeling, unlike in Australia, that everyone isn't out to screw you. It just seems a bit fairer here. This may be due to the smaller population, there's still a bit more personal care. I've found companies here really helpful and transparent, at least more so than their counterparts in Australia.
Anyways, we found a nice house. After being scared that we wouldn't find a dog friendly property, we really hit the rental market hard and got offered a few properties. In the end w chose the on that felt right, and in the end it ended up being perfect to split the difference between my work and Kates work! Some things just work out right.
We are now going through the painful task of finding a used car. I hate looking for cars. Anyways, we'll get there, but it is growing tiresome sifting through all the crap on trademe.
Kate has started working and is absolutely loving it which is just the best news, and we have been catching up with good friends from Vancouver which has been really nice.
What an life change Clooney has gone through! 8 months ago he was in a cage, no where to go. Fat forward 8 months and he's getting lots of walks and now has his own Wellington registration number. We have really given him a second look at life and it is just beautiful to have him around. Although he now associated plastic bags with walks (we always grab a few to collect his business). So now every time I grab an apple from a bag, he gets all excited and thinks it's time to go and starts whining, so that lucky dog is getting walked A LOT!
I start at Weta next Monday and am so excited. It's going to be so amazing to be part of a team that is creating such amazing work. I am feeling very inspired and pumped to create some amazing work.
Wednesday, July 29, 2015
Build a locator. Move it somewhere other than the origin (origin is fine but the data would just read 0.0,0.0,0.0. I wanted something in there as it makes it easier to verify that the data is returning correctly.
I then started writing some API code that would:
#get the active selection
#loop through selected nodes and for each node
#find the plug for the matrix attribute
#get that plug as matrix data
#extract the transformation data
#print the x,y and z coordinates.
I chose this test as that is exactly what is going on in my stretch node. In the node the .matrix attr is connected into the node, and from that plug I try to retrieve the x,y and z position. However it is returning incorrectly.
So the code in my Maya test scene is working, so the error must be in the creation of the node attribute, or the way in which I extract the data from the data block. Anyways, here is the code I used to the the t.x,t.y and t.z of a selected object from the matrix plug. I hope you find it useful.
import maya.OpenMaya as OpenMaya
dagPathFn = OpenMaya.MDagPath()
#get active selection
mSelList = OpenMaya.MSelectionList()
selItr = OpenMaya.MItSelectionList(mSelList)
#iterate through selection and get the world space positon from the matrix plug
while not selItr.isDone():
nObj = dagPathFn.node()
#we got the node from the dagPathFn#now we get the dependency node
objDepNodeFn = OpenMaya.MFnDependencyNode(nObj)
#find the .matrix plug
mxPlug = objDepNodeFn.findPlug('matrix')
#get plug as MObject which we will attach MFnMatrixData to.
mxObj = mxPlug.asMObject()
mxDataFn = OpenMaya.MFnMatrixData(mxObj)
#query the transformation, returns MTransformationMatrix
trfnMX = mxDataFn.transformation()
#get the translate in world space
v = trfnMX.getTranslation(OpenMaya.MSpace.kWorld)
#print it out!
startMXDataH = block.inputValue(stretchNodeMX.aStartMX).asMatrix()
Now this was not playing nce with me. As I went further down the track I was not getting the correct information returned.
So here's what I have..I'll delve deeper tomorrow...
#get matrix and translate from finding the dependency node and working from there
#returns the correct t.x,t.y and t.z
#-12.0540640814 5.6978884254 7.7806477623
sNode = self.thisMObject()
plugArray = OpenMaya.MPlugArray()
depNodeFn = OpenMaya.MFnDependencyNode(sNode)
startPlug = depNodeFn.findPlug(stretchNodeMX.aStartMX)
stObjMx = OpenMaya.MMatrix()
for i in range(0,plugArray.length()):
stObj = plugArray[i].node()
stDagNodeFn = OpenMaya.MFnDagNode(stObj)
stObjMx = stDagNodeFn.transformationMatrix()
stP = OpenMaya.MTransformationMatrix(stObjMx)
vec = stP.getTranslation(OpenMaya.MSpace.kWorld)
#get the matrix data from the input plug and work from there
#returns the incorrrect t.x,t.y and t.z
#5.26354424712e-315 0.0 0.0078125
startMXDataH = block.inputValue(stretchNodeMX.aStartMX)
startMX = startMXDataH.asMatrix()
#just print the "translate" parts of the matrix - does not return what I'd expect.
#returns the incorrrect t.x,t.y and t.z
#0.0 5.26354424712e-315 0.0
#get the transformation matrix to query the translation from there. Once again it returns the incorrect imformation
mxData = OpenMaya.MFnMatrixData()
stPTransformationMatrix = mxData.transformation()
stPTranslation = stPTransformationMatrix.getTranslation(OpenMaya.MSpace.kWorld)
Obviously something's going screwy with my coding here, and my use of the API. But anyways, it's all about digging through it and working out whats wrong...to be continued tomorrow. Something's going wrong with either my creation of the matrix attribute and the kind of data there..but I'm pretty sure thats good. So it must be in the way I am querying the data from the dataBlock...hmmm.
Tuesday, July 28, 2015
The node is really very easy to write, and the longest part of it is actually setting up the attributes on the node and how they affect each other. Once you have a template for a MPxNode you can just copy and paste it as a starting point. However it is always nice to write this out and make sure you understand it rather than just copying and pasting it.
So this stretch node has 3 inputs. the startPoint and endPoint, as well as a length attribute which the user sets to the length at which stretching will start. There are then two outputs. Distance, which just returns the distance between the two in points at any given time (useful for determining the point at which stretching will occur), and the main output which outputs the final stretch value which will generally get piped into the scaleX of the necessary joints.
What awesome things did I learn when writing this plugin. The attribute that enables MPoint to return the distance between two points.
posA = OpenMaya.MVector()
posB = OpenMaya.MVector()
p0 = OpenMaya.MPoint(posA)
p1 = OpenMaya.MPoint(posB)
distance = p0.distanceTo(p1)#returns double
Next awesome thing.In the initialize() function we call this:
plugin = OpenMayaMPx.MFnPlugin(obj,'Tim Forbes','0.0','Any')
We then register the plugin type. Now this is different depending on what plugin you are creating, and will require different input data. Somewhere to get caught out, especially if you copy your template from a OpenMayaMPx.MPxCommand type plugin...like I did :p
The differences here are below:
OpenMayaMPx.MPxCommand will be plugin.registerCommand('command name', creator)
The command only requires the command name and the creator function, however the node requires a few extra things as seen below.
OpenMayaMPx.MPxCommand will be plugin.registerNode('stretchNode', stretchNode.kPluginNodeId,creator,initialize)
Because we are creating a node that will be connected to the dependency graph we need a unique node ID, we need the node name, the creator function and also the initialize function. The initialize function is where all the node attributes are added. The creator function is where our pointer is created to access the plugin within maya.
The unique Node Id is created using the inbuilt maya function: kPluginNodeId = OpenMaya.MTypeId(0x00000882)
For home use I have generated an arbitrary ID, however in production you would want to make sure you used an ID that would not clash with in house node IDs.Currently I built the node to take on the translates of the two input points. This was for ease of building and proof of concept. My next version will take wither the world matrix or transforms, thus making the node more adaptable to different rigging scenarios. Anyway, I built this node into a rig and you can view it working below.
Maya Python API Stretch Node
Next Up. Add in matrix connections to the StretchNode. Following that I'm going to make a MPxCommand plugin that traverses the dependency graph to find connected skin clusters. This will be useful in a convoluted node graph if you need to manupulate the skin cluster in a specific way, or really any specific node I guess:-)