+1 tag for Google+

Tuesday, 25 November 2014

Distance Between 2 Positions in 3D Space

The ability to find the distance between 2 points in 3D space is a really important function I need to use time and again.

I found this website that is really helpful with clear explanations on the use of the formula.


From the webpage I learnt the formula for the distance d between points A (expressed as Ax, Ay, Az) and B (expressed as Bx, By, Bz), would be expressed as such:

d = √  Ax-Bx2 + Ay-By2 + Az-Bz2  

I was going to use the distance function on an expression in Maya, so I had to write it with MEL commands:

vector $a = `xform -q -ws -a -rp "objA"`;
vector $b = `xform -q -ws -a -rp "objB"`;
// doing the additions and squaring first
$myDist = `pow ($a.x-$b.x) 2` + `pow ($a.y-$b.y) 2` + `pow ($a.z-$b.z) 2`; 
// applying the square root
$myDist = `sqrt $myDist`; 

I hope you it helps if you are looking for the same information.

Additional notes:
I am writing this a few days after my post because I found a more efficient way to represent the formula.

Instead of using the back ticks "`" for the pow and sqrt, I found that in Maya expressions we can use the equivalent of these commands. They are pow( ) and sqrt( ).

So the shortened single-line expression would be:
$myDist = sqrt(pow(($a.x-$b.x), 2) + pow(($a.y-$b.y),2) + pow(($a.z-$b.z),2))

Saturday, 22 November 2014

Adding ObjectID Pass to Render Output in Maya Part 2: The Script

In my previous post, Autodesk's article showed us how to create an ObjectId pass in our scene.

In the last post I also posted a snippet of PyMel script that creates a unique Id number for each object so each one will turn up a uniquely different colour from its neighbour in the objectId pass.

However the process still needed us to manually create a Mental Ray Output Pass in the camera's Mental Ray section.

Since then I have gone on to write a PyMel script to automate the process. So here is the script.

# -- code start --
from pymel.core import *
def uniqObjIdAssign():
    # Written by Patrick Woo
    # usage:   
    # - make sure mental ray is loaded, and set as your current renderer
    # - select the camera
    # - then select all the objects to give unique objectIDs to, and run this script
    # for more info go to:
    # http://patrickvfx.blogspot.com/2014/11/adding-objectid-pass-to-render-output.html
    if ls(sl=True)[0].getShape().nodeType()=='camera':
        camShape = ls(sl=True)[0].getShape()
        print 'first object selected must be a camera. script aborted.'
    if ls('*miOutputPass_ObjId', type='mentalrayOutputPass'):
        # user has run this before
        select(ls('*miOutputPass_ObjId', type='mentalrayOutputPass'), replace=True)
        print 'an existing mentalrayOutputPass already exists. delete it, or rename it, then run the script again'
    sel = ls(sl=True)[1:]
    opPassNode = createNode("mentalrayOutputPass", name='miOutputPass_ObjId')
    opPassNode.dataType.set(11) # set frame buffer type to "label(integer)1x32bit"
    opPassNode.fileMode.set(1) # sets the outputPass node to output to a file upon rendering
    connectTriesCounter = 0
    connectedFlag = False
    while not connectedFlag:
            connectAttr(opPassNode.message, camShape.miOutputShaderList[connectTriesCounter], f=False)
            connectedFlag = True        
            connectTriesCounter += 1
        if connectTriesCounter > 20:
            print 'too many tries to connect %s to %s, aborting.'%(opPassNode.name(), camShape.name())
            print "check the connections on %s's mental ray -> output shaders before running again"%camShape.name()
    counter = 1 # 0 is black in colour 
    for x in sel:
        if x.getShape():
            # makes sure that the transform node isn't just an empty group 
            if "miLabel" not in str(x.listAttr()):
                addAttr (x, ln='miLabel', at='long', k=True);
            print '%s.miLabel set to %i'%(x,x.miLabel.get())
            counter += 1
# -- code end --

These are the steps you need to do before running the script.
- set your renderer to Mental Ray (the Mental Ray plug-in must be loaded)
- select first your camera
- then select the rest of your objects in the scene you wish to assign objectIds

The script does the following:
- get your camera's shape node
- create a mentalrayOutputPass node
- set the mentalrayOutputPass node's frame buffer type to "Label(Integer)1x32bit"
- set the mentalrayOutputPass node to output to a separate file when rendering
- set a post-fix "_objId" for the output file  (so it does not clash with the file name of your main render)
- connect it to an empty entry in your camera shape's list of output shaders
- then go through the rest of the non-camera selection, and
  -  add the "miLabel" attribute if it does not exist
  - gives a unique integer to the object's "miLabel" attribute

On top of all these the script does some checks:
- to make sure the first selection is a camera
- to make sure the mentalrayOutputPass node with a name "miOutputPass_ObjId" does not already exist in the scene (I do not want the user to end up with a heap of mentalrayOutputPass nodes when he/she runs the script multiple times)

Additional tips and controls for the script:
The order of your selection matters.

If you do not  like the colours given to some of the objects, you can deselect those objects and re-add them to your existing selection in a different selection order, then run the script again. (Just make sure the first selected object is your camera).

If you want to re-run the script, make sure to delete the mentalrayOutputPass node connected to the camera, and you will be able to run the script again. 

If you'd like to keep an existing mentalrayOutputPass node, you can rename it with a "01" at the back, and the script will now run by adding yet another mentalrayOutputPass node, which you can then manually delete when the new node gets created. Ideally you should only have only one mentalrayOutputPass node attached to your camera, since all other mentalrayOutputPass nodes will command mental ray to re-render the same objectId passes and save the exact images back to the exact filenames, resulting in wasted rendering time.

I hope you find this useful. 

Drop me a note if it has helped you, or if you have ideas on how to improve it. :)

Thursday, 20 November 2014

Adding ObjectID Pass to Render Output in Maya

(This article has a second part, with a more complete script, which you should check out later. Read part 2 of this article)

So I was trying to find out how to generate ObjectIDs for Mental Ray renders in Maya. Peering into render passes and render layers settings, I could not find an objectId setting or preset. So I had to search the Internet for some answers.

Here's a little help from Autodesk folks on how to generate object ID pass for your mental ray renders.

Quoting from the page:

-- start quote --

To obtain an object ID pass, please follow these steps:
  1. Select all the objects that you wish to include in the pass, and execute the following MEL script:

    addAttr -ln miLabel -at long -k 1;

    This will add a new attribute called “MI Label” for all the objects in the Extra Attributes section.
  2. Once you create a different MI Label for each object, you will assign a different ID value, thus making each object unique during render time.
  3. Select the render camera and under the mental ray section > Output Shaders, select the Create button. This will create a mentalrayOutputPass.
  4. Change the Frame Buffer Type to Label (Integer) 1x32 Bit.
Note: You can change the image format and the name of the pass according to your needs.
The result will be a separate rendered file in the format selected in the Image Format field.
-- end quote --

I believe after we set up the objects adding the extra attribute, we need to give a unique integer number to every object that has the added "miLabel" attribute.
Thus I have coded a procedure in PyMel that goes through every transform node that is selected, makes sure it has a shape node (ie, it is not an empty group). For each one of the qualifying objects, the script creates the "miLabel" attribute if it does not exist, and assigns an incrementing integer. 

# -- code start --
from pymel.core import *
def uniqObjIdAssign():
    # Written by Patrick Woo
    # usage: select all the objects to give unique objectIDs to
    #        and run this script
    # for more info go to:
    # http://patrickvfx.blogspot.com/2014/11/adding-objectid-pass-to-render-output.html
    counter = 0; 
    for x in ls(sl=True, type='transform'):
        if x.getShape():
            # makes that the transform node isn't just an empty group 
            # without a shape node
            if "miLabel" not in str(x.listAttr()):
                addAttr (x, ln='miLabel', at='long', k = True);
            print '%s.miLabel set to %i'%(x,x.miLabel.get())
            counter += 1

# -- code end --

Even with the script the camera output pass will still need to be set-up as per instructed on the Autodesk page above.

Read part 2 of this article where I post my fully automated script

This is one of the resulting renders from the MentalRayOutputPass, with file mode turned on, and written to an external file, separate from the main rendered image.

Saturday, 15 November 2014

Unity 3D Test with a Serial Port Ranging Sensor

I've trying my hands at working with Unity3D, and getting used to the workflow, including scripting and working with external input devices. In this video I successfully get Unity to receive input from a Ranging Sensor connected to the computer via a serial port.

When I put my hand within range, the code triggers the small cubes to move up, and the larger cube to turn red and rotating.

After removing my hand for about 4 seconds the cubes are programmed to fall back to their original positions.

The ranging sensor chips were programmed by someone else before hand. In the future I want to look into programming these chips as well! :)

Wednesday, 12 November 2014

Black Magic Releases Fusion 7 Absolutely FREE

From the text message of an excited friend today, I learnt that Fusion 7 from EyeOn software has become absolutely free. This sounds like a bogus piece of news. However, a quick search through the internet confirmed the news!

This is definitely exciting. From an article on the StudioDaily site, I found more news. Eyeon Software has been bought over by BlackMagic Design 2 months ago, and Fusion will now be developed  by them.
Fusion has a long-standing and solid history in the history of high-end compositing software for visual effects work in TV and Film. In its latest version, Fusion 7 comes in 2 flavours: Fusion 7 and Fusion 7 Studio. While Fusion 7 was originally US$2.495, it is now free. the Studio version now costs US$995 to upgrade to. Read here for a complete list that compares the two versions.

When BlackMagic Design released Fusion for free, they want to continue their spirit of revolutionising the industry, delivering high quality and high performance products at very affordable prices.

BlackMagic stresses that Fusion is not tied to subscription of annual maintenance fee, does not need an Internet connection, and does not have additional charges for per-node rendering licenses. BlackMagic also promises that it has no intention in the future to introduce the subscription based model into Fusion.

BlackMagic Design has definitely set itself up to shake-up the market and turn heads in an industry where technology is pivotal in the business, and ever so often, developers of high end tools tries to bleed the wallets of studios and production facilities at every chance they can.

I really applaud the spirit of BlackMagic Design, and I sincerely hope that with an ease in the cost of the software, companies now have some headroom to reapportion their resources so that hardworking and deserving people (like under-paid artists at the bottom, hint hint) get better remuneration.  :)

Current owners of Fusion 7 will get a free upgrade to the Fusion 7 Studio.

Download Fusion 7 today!