30 April, 2010

Python: Import a Module and Get a given Class

Python offers different ways to import a module. The most flexible one is to use __import__ function. This allows script to load a module dynamically. So we can load a particular module based on user input.

Since everything in python is an object even the python module has some useful properties. One of them is __dict__ property. This is how you can use it.
className = 'MyClass'
modObj = __import__('moduleName')
# This gives us the class reference
MyClass = modObj.__dict__[className]
# So we can create class instance like this
inst = MyClass(params)

Edit:
This logic works if you are using just modules. For packaging this may need to be modified.

Modular Rigging System : Goals

As I have started writing my modular rigging system, I am constantly thinking about the main goals. I feel that at each stage as I put a concept on paper or write code that should satisfy the main goals. After a lot of thinking I have decided on the following goals,
  1. One should be to be able to change/extend pretty much everything in the system
  2. All the parts of the system should be as much independent as possible
  3. Whenever possible not be specific to Maya 
  4. Editable template/skeleton/rig at any stage

So any module that I create can be changed or replaced. This will create very minimal core modules. We are not really defining the logic of rigging in the core modules. I think the core modules define the concept of modular rigging. And the modules that has some common logic for rigging are defined in core utility modules. Hence the core system modules represent only the idea of the modular rigging system.

Rigging modules should not be constrained to a personal workflow.
Example:
In general, there is a template system that lets us define blueprint of the rig and then we create joints and rig on top of it. So roughly there are three parts to this system, locators(guides), joints(skeleton), rig(controls). But,
what if I already have my joint chains created manually? What if I have my own guide system? or I want to change the way animation controls are aligned or created? etc...

There is really no right or wrong way to do things here. But I am doing my planning based on what I think a modular system should be.

29 April, 2010

Being Pythonic

I mentioned in my earlier post that we can assign a tuple/list to multiple variables. However both number of elements should match on both sides. One of the options is to assign only fixed number of elements to variables like this
mylist = [1,2,3,4,5]
x,y,z = mylist[:3]
mylist[:3] will return 3 elements from the beginning.

28 April, 2010

Being Pythonic

Tuple is a very important data structure in python. You can directly assign tuple elements to variables like this.

Tuple assignment
tup = (3,'xyz',[1,2,3])
ind, myKey, myList = tup 
This is called unpacking. It is wise to do this only on tuples since they are immutable and it is sure that the number of elements being unpacked is same as the number of variables on the left side. This can be very useful when using *args and **kwargs. More on that later.

Use negative index
myList[-1] returns the last element

And Now I am a Python Fan

I was a little hesitant towards learning one more language since I get mixed up easily after working with many different languages: c, c++, ActionScript, mel, php, .Net, qlikview and now python (no boasting but I get surprised myself thinking what human brain can do). For example,

String concatenation,

php : $str1.$str2
c++: str1 + str2
vb: str1 & str2

Defining functions,
mel : global int[] proc getMyAnts(string $place)
c++: int* MyClass::getMyAnts(MString place)
python: def getMyAnts(self, place)

However, after learning python I am thinking about making it my main focus amongst all programming languages. The ease of use, elegant syntax and flexibility to create magic is what sets this language apart from other languages. However, I don't claim it's the best language out there, but it surely is powerful and different in a way that I have started loving it.

Since I am still young in using python I thought it would be a good idea to post tricks and helpful language features that I learn on my own or from others.

24 April, 2010

Coding Tricks Using Arithmetic

When I was in 4th semester (if I remember correctly) of computer engineering studies I had a light bulb moment about using simple arithmetic in programming to avoid many if conditions. This was when I looked at my classmate's (who is now my life partner :) ) C program and found out how modulas operator can save me if conditions while implementing a program to convert decimal to binary.

From that day I always try to use arithmetic to avoid conditions. However, many times I forget about this technique and I keep rediscovering this method. So this time I am writing it down here hoping that I remember it and hoping that someone may find it useful.

Problem: I want to pass one axis in a single 1D parameter and later for calculation I need corresponding vector in an array

Solution 1:
One option is to pass "x", "y" or "z" and then use if conditions to find an array form of vector. I have to consider negative axis too so to minimize number of if conditions, I can pass another variable as a multiplier.
proc int[] getVectorOfAxis(string $axis, int $dir)
{
    int $axisVec[3]={0,0,0};
   $axis = tolower($axis);
    if($axis=="x")
        $axisVec = {$dir, 0, 0};
    else if($axis =="y")
        $axisVec = {0, $dir, 0};
    else if($axis == "z")
        $axisVec = {0, 0, $dir};
    return $axisVec;
}

getVectorOfAxis("y", -1);
Solution 2:
However, if we pass integer for axis then we can use arithmetic to find the axis vector without a single if condition.
proc int[] getVectorOfAxis(int $axis)
{
    int $axisVec[3]={0,0,0};
    int $tempInd;
    $tempInd = abs($axis);
    $axisVec[$tempInd-1] =$tempInd/$axis;
    return $axisVec;
}

getVectorOfAxis(-2);
You can argue that the first is easy to understand and it's really not a big deal considering speed is not an issue for us here. However, training mind to use arithmetic can give more flexible options and you can avoid "if" conditions in many cases. I use this trick a lot in making node networks in maya by using multiplyDivide nodes to replace condition nodes.

Solution 3:
If you find passing integers 1,2,3 for axis unintuitive you can still use "x", "y", "z" without conditions. Here is one more solution :)
def getVectorOfAxis(axis, dir):
    axisVec=[0,0,0]
    axisNum = ord(axis.lower())- ord("x")
    axisVec[axisNum] =dir
    return axisVec

getVectorOfAxis("X", -1)

23 April, 2010

Procedural Rigging System vs Auto Rigger

This is somewhat subjective, but I have started believing that there is a fundamental difference between procedural rigging system and auto rigging scripts.

Auto rigging scripts basically automates tasks for you and generates rig or rigging parts. Many times they are limited by many assumptions or fixed concepts. On the other end procedural rigging system defines how the rig will be generated automatically. It defines a system which helps rigging scripts do their jobs.

For example, in one system all nodes contain basic metadata information like, object type(animControl, bindJoint), dir(R,L,C) etc. These nodes are connected to some other metadata nodes that defines a set of objects, e.g. a metanode that lists all the animation controls for a given rig part. Extending this idea will give a system that allows flexibility to give different inputs and create many possible outputs.

Auto Rigger will use this information from meta system to build the rig or rig parts. So for me Auto Rigging Tool is divided into two main components:
  1. A system that defines how meta information is created and stored
  2. Auto rigging scripts that create rig based on meta information

21 April, 2010

Reason for Cycle Errors While Constraining

When creating a constraint system many times we encounter cycle errors even if we know that some transfroms should not change. For example if a joint is affecting translation of a locator in some way and locator calculates the rotation of this joint, they should be unaffected by each other because they change different parts of the transformation. However, we end up having cycle because we are using world space transformation values.

When we are using worldspace transformation values, we use worldMatrix of the transform node. If the object is moved by any mean worldMatrix needs to be calculated causing it to be marked dirty. So even if we change only rotation the whole matrix attribute is marked dirty. Hence we will see a cycle error in the above example. 

One way to avoid cycle errors is to use the parent of the object that you want to constrain to. Or you can use local space transformation if it works as part of the whole setup.

Using curve 'normal' from PointOnCurveInfo

We can use PointOnCurveInfo node to get information about any point along the given curve. I have been using it for constraining a locator on a curve. It is the same logic used in constraining a transform on a NURBS surface. In this method normal and tangent vectors are used to aim constraint a locator to get the right orientation on the geometry. However, since curve is one dimensional in size, i.e. it has only length and no width, the curve normal tends to swing around when we go pass certain angle. This makes it difficult to use 'normal' vector for aim constraint. We can skip connecting normal vector with up object and just use floating transform or use object rotation axis based on requirement.