Friday, July 31, 2015
Thats what lifes about....
Thursday, July 30, 2015
Stretch Node Maya API Plugin Comparisons
Stretch Node Python API Plugin demo from Tim Forbes on Vimeo.
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.
Wellington - our new home
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
Maya API Matrix Research
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()
OpenMaya.MGlobal.getActiveSelectionList(mSelList)
selItr = OpenMaya.MItSelectionList(mSelList)
#iterate through selection and get the world space positon from the matrix plug
while not selItr.isDone():
selItr.getDagPath(dagPathFn)
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')
print mxPlug.name()
print objDepNodeFn.name()
#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!
print v.x,v.y,v.z
selItr.next()
Positon From Matrix
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...
def compute(self,plug,block):
#method 1
#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)
startPlug.connectedTo(plugArray,True,False)
stObjMx = OpenMaya.MMatrix()
if plugArray.length()>0:
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)
print vec.x,vec.y,vec.z
#method 2
#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.
print startMX(0,0),startMX(0,1),startMX(0,2)
#method 3
#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()
mxData.create(startMX)
stPTransformationMatrix = mxData.transformation()
stPTranslation = stPTransformationMatrix.getTranslation(OpenMaya.MSpace.kWorld)
print stPTranslation.x,stPTranslation.y,stPTranslation.z
block.setClean(plug)
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.
TBC...
Tuesday, July 28, 2015
Stretch Node
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.
Stretch Node from Tim Forbes on Vimeo.
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:-)
Monday, July 27, 2015
Interesting Things with the Maya Python Api
So I was writing a default dependency node template. As I am writing this I am trying to understand why each of the pieces of a node are there, and what they do. Each time I need to use a piece of code, I will refer to the API guide and understand where the command or attribute had come from and how it is returning the data.
The interesting one I just came accross was when working with a MFnNumericAttribute class. I was using this in the initialize() function where the different attributes are built for the dependency node.
What I found was when I came to set the attribute to keyable, storable etc, I could not find any information relating to these attributes in the documentation for MFnNumericAttribute. This is where I realised that these attributes were being inherited from the parent class, MFnAttribute. So by creating a MFnNumericAtribute, I had access to all the attributes associated with this command, but I also had access to everything above. So:
nAttr = OpenMaya.MFnNumericAttribute()
nAttr.create('longName','shortName',OpenMaya.MFnNumericData)
#now you can access attributes from MFnAttribute
nAttr.setKeyable(True)
#or attributes from MFnNumericAttribute
nAttr.setMin(1.0)
Ok I know this is super novice. But one thing I realised when I was starting to learn, is these little things can really help learn how to read the documentation, and I couldn't find that info anywhere out there, a lot of it was assumed knowledge. That being said, to find the information for yourself means that you will always remember it and understand how to apply that same knowledge to different scenarios.
Once I'm done with my default node template I'll bang it up here. Cheers.
Learning the Maya Python API
I think that a time comes when you realise it is time to learn some things. Coding is like learning a language. Without the right mindset or need, it is very difficult. But when offered a good practical reason to learn, new concepts and knowledge seem to be learnt a lot more fluidly. I feel this is where I am now. My python coding has got to a certain point in Maya, and I now see a use for the power that I can harness through the API. Although slow, I am picking it up a lot better than last time I started reading the API.
I find one of the biggest things is realising how to read the help docs, and being able to read the C++ documentation and convert it to python. This will prove useful when delving into C++. For the moment I am learning the Maya Python API so I can focus on learning the API toolset, and not have to worry so much about syntax. Once I have that sorted I will start moving accross to C++.
For the time being my goal is to work though David Goulds Maya Programming Books, and as I do so to build some simple nodes and commands that package up some commonly used rigging node graphs that I often build.
Keep checking back for my progress.
Sunday, July 26, 2015
The road to recovery!
In a few weeks we move to our new home! The commute to work is about 13kms. My plan is to be running that a few times a week in a couple of months. like I said, baby steps, but the will is there and I know I'll get there. I just need to be smart about it!
First Days In Wellington
Last night we had pizza and beers at our pad with Nick and Emma. Some more friends from Vancouver. It is so good to catch up with our friends that we made when we were overseas. It's like we never left!
Having Clooney here has been a blessing. It has really forced us to get outside. We have been walking him a lot and he has been charming everyone. We took him on a big walk through the Botanic Gardens last night, and then he just chilled like a good old dog when Nick and Emma came over for dinner! Funnily enough, he is such a pleasant dog, he has been getting loads of comments while walking around the city. Everyone loves him :-)
Saturday, July 25, 2015
Interesting Blog Written By My Uncle!
Life is good and I am blessed to be leading the life I am. Check the article below.
My nephew just got a job with Weta
Creature TD Reel
Tim Forbes Creature TD Reel 2015 from Tim Forbes on Vimeo.
My latest Creature TD reel with my favorite work. Latest additions to the reel are Chappie and TMNT. I hope to add some more updated personal work soon.
Big props to all the crew at Image Engine for the amazing work.
Music By Arcade Fire. "Sprawl 1" from album "The Suburbs".
Friday, July 24, 2015
Moving To Wellington
Needless to say, that 4.5 weeks was brutally busy, but as Kate and I always do, we smashed it out and got everything done. I worked up to the friday (3 days before we left), which made it difficult to do a lot, so my weekends and after work hours got really busy, but it was fun and finally gave me something to do!
What helped....well, Go Box helped for storing our stuff. Pretty much Go Box delivers a shipping container to your door. You fill it with your stuff (see 3D Tetris Post), then they take it away. Filling that box sucked. I think I am looking forward to unpacking it even more. Gum Tree helped a lot. The amount of shit we sold / gave away is amazing. The saying "One mans trash is another mans treasure" is truly accurate. I feel sorry for the dude that took our lawn mower. That bad boy weighed about a tonne and would have cost a boat load to ditch. We stashed a shitty old clam babies bath on the footpath...it was gone in like 10 mins???
We smashed the cleaning, got the house looking gleaming and employed Toop and Toop to rent our beautiful house. They were onto it and found a tenant within a week of advertising it!
The last few nights in our house were spent on a blow up matress. We had to stay with the house as Clooney needed somewhere to stay up until his departure (about 5 hours after us) on Monday the 20th. So we vacated on the 20th at 3am to the airport and left Clooney in the backyard. Kates parents then came down to make sure that Dogtainers Adelaide picked him up at 9am and took him on his merry way. We arrived in Wellington later on the 20th, after some delays and running to the plane in Melbourne due to a huge delay due to iced up planes...yes, iced up planes in Melbs!
Koa from Weta was there to pick us up, hook us up with a car, take us to the phone dealership to get sim cards and then drop us to our accom. Clooney flew on Tues the 21st, spent the night in Auckland and then arrived in Wellington on Wed the 22nd in the afternoon to a relieved Kate. He's loving it and I don't think he misses Adelaide.
Now we have found a place and are searching for a car. I have another week off and Kate starts on Monday. It has been a hectic week and we have seen a lot of Wellington while looking for housing. This city rocks! It is so beautiful and vibrant. It feels way bigger than the population leads you to believe. I'm now eagerly awaiting starting at Weta. I am so pumped to do some amazing work and to work with an amazing team.
There have been some stressful times, but we are so stoked to be here. So far the move has been so worthwhile and has broken us out of a rut that we had got into in Adelaide. Good times!