Beer glass scene creation
This course contains a little bit of everything with modeling, UVing, texturing and dynamics in Maya, as well as compositing multilayered EXR's in Photoshop.
# 16 28-05-2012 , 09:45 PM
Registered User
Join Date: Apr 2012
Posts: 32

doh! sirCharles just pointed out a flaw in the original script. If you freeze the transforms on any object using setAttr with the x y z transforms to zero will not move the object at all so I made the following changes to the script.

I use the mel command "move -rpr 0 0 0 $obj" to move the object (relative to its rotate pivot) to the global 0 0 0 position. This means the pivot needs to be centered first which is accomplished with the "xform -cp" command.

Since this is a learning exercise I found the move -rpr command by creating an object and then snapping it to the global origin holding the x-key down and then looked in the script editor to see the command that was generated, then went to the mel reference and read up a little on the move command. This is how a figure out most commands in mel. I did the same thing for the freeze transform block of code. I picked an object and froze its transforms then looked at what was generated in the script editor.

I also added the parameter $ft to control if the objects transforms are frozen after being moved to the global origin. (0 -- don't freeze, 1 -- freeze)

I tack "rm" in front of scripts I write so I can tell at a glance what scripts are mine in the scripts folder so changed the name to rmCenterObjects, and you call it using rmCenterObjects(0 | 1); You can chage it to whatever you want just remember the proc name and the file name must match.

I am not a mel programmer and there are many ways to do things in maya so this may not be the best way but it seems to work.

Code:
// procedure: rmCenterObjects()
// usage: rmCenterObjecst(0|1);
// author: ctbram
// date: 05272012
//
// Place this script into your maya folders scripts folder and use by 
// selecting objects that you want to center  pivot and move to the 
// global origin ( 0 0 0 ).
//
// examples:
// 1. rmCenterObjects(0) moves the selected objects to the global origin while
// 2. rmCenterObjects(1) moves the selected objects to the global origin and
// freezes the objects transforms
//
// modified 05282012
//   added the $ft flag
//   use the move command rather then setAttr to account 
//     for objects that have had their transforms frozen

global proc rmCenterObjects(int $ft)
{
    string $sel[] = `ls -sl`;
    string $obj;
    for ($obj in $sel)
    {
        // center $obj's pivot
        xform -cp $obj;
        
        // move the $obj to the global origin using move
        // relative to the rotation pivot -rpr
        move -rpr 0 0 0 $obj;
        
        // if $ft is 1 then freeze transforms after moving 
        // $obj to theglobal origin
        if ($ft == 1)
        {
           select -r $obj ;
           FreezeTransformations;
           makeIdentity -apply true -t 1 -r 1 -s 1 -n 0;
        }     
    }
    
    // restore the original selection
    select -r $sel;
}

this code is too godly for mere mortals like me..thank u...fancy trying drop to floor? lol

# 17 28-05-2012 , 09:49 PM
NextDesign's Avatar
Technical Director
Join Date: Feb 2004
Posts: 2,988
You might also want to restore the pivot point's previous location.


Imagination is more important than knowledge.
# 18 29-05-2012 , 01:17 AM
ctbram's Avatar
Moderator
Join Date: Jan 2004
Location: Michigan, USA
Posts: 2,998
@juggler7 What would drop to floor do?

@ND you're the mel guy is using move a reasonable approach for this? How would you store and restore the objects relative pivot?

I would use the cave man approach and group each object, center the group pivot, move the group to the global origin, and then simply ungroup the object which would restore its local pivot.

I'd have to do some googling to find how to properly store and restore the local pivot.


"If I have seen further it is by standing on the shoulders of giants." Sir Isaac Newton, 1675

Last edited by ctbram; 29-05-2012 at 01:24 AM.
# 19 29-05-2012 , 02:32 AM
EduSciVis-er
Join Date: Dec 2005
Location: Toronto
Posts: 3,374
I would assume drop to floor would pick the lowest point on the selected object and bring the object so that point is at y = 0. That could be pretty useful I guess. Easy enough to create a floor plane and use the align tool though.

# 20 29-05-2012 , 02:57 AM
ctbram's Avatar
Moderator
Join Date: Jan 2004
Location: Michigan, USA
Posts: 2,998
hmm so I am thinking the pseudo code would be like...

Code:
foreach $obj in selection
{
    select -r $obj;
    $vertsList[] = getListOfVerts();        // get a list of all the vert in the selection
    $lowest = getLowestVert($vertsList);   // find the (x,y,z) coord of the lowest vert
    savePivot();                             // save the selections pivot
    setPivot $lowest;                      // set the selections pivot to the lowest vert
    moveToGlobalYZero;                  // move the current selection pivot to global y=0
    restorePivot();                      // restore the relative pivot of selection
}

hmmm convoluted. maybe find the bounding box of the selection. then there are only 2 verts in the bounding box. find the ymin value and then set and then move the object so its lowest bounding box verts are at the global origin.

I'll have to think on this one a bit.


"If I have seen further it is by standing on the shoulders of giants." Sir Isaac Newton, 1675

Last edited by ctbram; 29-05-2012 at 04:40 AM.
# 21 29-05-2012 , 03:36 AM
NextDesign's Avatar
Technical Director
Join Date: Feb 2004
Posts: 2,988
That's possible, but you're looking at a O(n) algorithm, where n is the number of vertices in the object. It's fine when you have 100-1000 vertices, but once you get higher, 10000+, you'll really start to notice it, especially with a interpreted language such as MEL. A dirty way to get around this could be to have the user select a bunch of vertices near the bottom of the object, and iterate through those, or even have the user click on the bottom point.

Using the bounding box is the better alternative.

Code:
string $sel[] = `ls -sl -dag -geometry`;

float $bbox[] = `exactWorldBoundingBox $sel[0]`;

float $lowestPoint = $bbox[1];
Also, why are you using -rpr? Why not use just absolute positioning? If it's 0, 0, 0, relative to the pivot point, it's the same as using -a.

To store the old pivot point, you would simply store it into a temporary variable, like the following:

Code:
float $oldPivot[] = `xform -q -ws -rp $sel[0]`;
Then, after centering it, and moving the object, restore it by doing the following:

Code:
xform -ws -rp $oldPivot[0] $oldPivot[1] $oldPivota[2] $sel[0];


Imagination is more important than knowledge.
# 22 29-05-2012 , 03:51 AM
ctbram's Avatar
Moderator
Join Date: Jan 2004
Location: Michigan, USA
Posts: 2,998
Thanks ND I will make a note of those commands.

Yes, I realized the complexity for the algorithm looking at all the verts was O(n) and would become cumbersome for objects where n (the number of verts) becomes very large. That is why mentioned the algorithm was "convoluted" and that using the bounding box would be better since it's O(1).

I knew there was a bounding box function just never used it. It seemed to make the most sense.

I used -rpr because when I used -a (which also made the most sense to me) it did not work. I created an object moved it off the origin and froze it's transforms and then tried "move -a 0 0 0 $obj" and it did not move at all so I used the x-key and snapped to the origin the code generated was -rpr so I just went with it and did not bother to investigate why -a did not work..

NOTE: I rechecked and move -a 0 0 0 appears to move an object to its frozen 0 0 0 position not to the absolute global 0 0 0 position and therefore you must use -rpr to move an object to the global 0 0 0 position.


"If I have seen further it is by standing on the shoulders of giants." Sir Isaac Newton, 1675

Last edited by ctbram; 29-05-2012 at 06:22 PM.
# 23 29-05-2012 , 04:26 AM
ctbram's Avatar
Moderator
Join Date: Jan 2004
Location: Michigan, USA
Posts: 2,998
Okay with the help of ND's input here is the rmToFloor procedure to move all selected objects so they sit on the grid...

NOTE: In this version the objects world space (global) pivot position is maintained. I am wondering if maintaining the object space (relative) pivot position would be more useful? It would only take a very small modification to the code to change the behavior.

Code:
// procedure rmToFloor()
// Move the lowest point of all objects in the selection so they sit exactly on the 
// top of the grid (global Y=0).
// 
// usage: rmToFloor();
// Copy this script to your maya scripts folder and source it and then make a selection of all
// the objects you want to move so they are sitting on the grid and enter the command
// rmToFloor;. 
//
// notes: This procedure depends on the mel command "exactWorldBoundingBox $obj" which 
// returns a float[] xmin ymin zmin xmax ymax zmax.  I use ymin to temporarily set
// the Y position of $obj's pivot so I can move it along Y such that it sits on the grid. 
// Moving each object to the grid has a constant complexity O(1).  This procedure has a 
// complexity of O(n), where n is the number of objects in the selection.
// 
// author: ctbram with valuable input from nextdesign
// date: 05292012
//
global proc rmToFloor()
{
    string $sel[] = `ls -sl`;
    string $obj;
    
    for($obj in $sel)
    {
         float $bbox[] = `exactWorldBoundingBox $obj`;               // get bounding box
         float $lowest = $bbox[1];                                   // get lowest vert (Y)
         float $oldPivot[] = `xform -q -ws -rp $obj`;                // save $obj pivot
         xform -ws -rp $oldPivot[0] $lowest $oldPivot[2] $obj;       // reset the pivot to the lowest point
         move -rpr $oldPivot[0] 0 $oldPivot[2] $obj;                 // move the object to the grid
         xform -ws -rp $oldPivot[0] $oldPivot[1] $oldPivot[2] $obj;  // restore the original pivot
    }
}


"If I have seen further it is by standing on the shoulders of giants." Sir Isaac Newton, 1675

Last edited by ctbram; 29-05-2012 at 10:26 AM.
# 24 29-05-2012 , 10:20 AM
ctbram's Avatar
Moderator
Join Date: Jan 2004
Location: Michigan, USA
Posts: 2,998
I have a question for ND. Do we really want to maintain the global world space pivot or would it not be more appropriate to maintain the relative object space pivot?

I would just add a line to save the object space pivot -

float $osPivot[] = `xform -q -os -rp $obj';

and replace the line that restores the world space pivot with -

xform -os -rp $osPivot[0] $osPivot[1] $osPivot[2] $obj;

With this version the objects pivot maintains its relative position to the object when it is moved. Wouldn't this be better?

Here is a modified version of the code to maintain the relative pivot of each object as it is moved...

Code:
// procedure rmToFloor()
// Move the lowest point of all objects in the selection so they sit exactly on the 
// top of the grid (global Y=0).
// 
// usage: rmToFloor();
// Copy this script to your maya scripts folder and source it and then make a selection of all
// the objects you want to move so they are sitting on the grid and enter the command
// rmToFloor;. 
//
// notes: 
//(1) This procedure depends on the mel command "exactWorldBoundingBox $obj" which 
// returns a float[] xmin ymin zmin xmax ymax zmax.  I use ymin to temporarily set
// the Y position of $obj's pivot so I can move it along Y such that it sits on the grid. 
// Moving each object to the grid has a constant complexity O(1).  This procedure has a 
// complexity of O(n), where n is the number of objects in the selection.
//
// [strike](2) this procedure moves the object but leaves the objects pivot in the same worldspace
// location.  I am not sure of the value of doing this and may want to either keep the
// local (relative) pivot location or just center the pivot.
//
// (3) changed the script to maintain the relative pivot when the object is moved.
// 
// author: ctbram with valuable input from nextdesign
// date: 05292012
//
// change log:
// 05292012 - changed the program so the relative pivot of the object is maintained rather
// then the world pivot
//
global proc rmToFloor()
{
    string $sel[] = `ls -sl`;
    string $obj;
    
    for($obj in $sel)
    {
         float $osPivot[] = `xform -q -os -rp $obj`;                // save the object space (relative) pivot
         
	 // move the object using world space coordinates...
	 float $wsPivot[] = `xform -q -ws -rp $obj`;                // save world space $obj pivot
         float $bbox[] = `exactWorldBoundingBox $obj`;              // get bounding box world space coords
         float $lowest = $bbox[1];                                  // get lowest vert (ymin)
         xform -ws -rp $wsPivot[0] $lowest $wsPivot[2] $obj;        // reset the pivot to the lowest point in world space
         move -rpr $wsPivot[0] 0 $wsPivot[2] $obj;                  // move the object to the grid
         
         xform -os -rp $osPivot[0] $osPivot[1] $osPivot[2] $obj;    // restore the object space (relative) pivot
    }
}


"If I have seen further it is by standing on the shoulders of giants." Sir Isaac Newton, 1675

Last edited by ctbram; 29-05-2012 at 10:37 AM.
# 25 29-05-2012 , 11:39 AM
ctbram's Avatar
Moderator
Join Date: Jan 2004
Location: Michigan, USA
Posts: 2,998
The pivot thing was buggin me and I could not sleep so I made a new version of the program and added a pivot control parameter (int $pc) that determines if the object space (relative) or word space (global) position of the pivot is maintained or if the pivot is simply centered.

Code:
// procedure rmToFloor(int $pc)
// Move the lowest point of all objects in the selection so they sit exactly on the 
// top of the grid (global Y=0).
//
// params:
// int $pc - pivot control - (0 | 1 | 2)
// 0 = maintain object space (relative) pivot position
// 1 = maintain world space (global) pivot position
// 2 = center the pivot
// 
// usage: rmToFloor( 0 | 1 | 2);
// Copy this script to your maya scripts folder and source it and then make a selection of all
// the objects you want to move so they are sitting on the grid and enter the command
// rmToFloor 0 | 1 | 2;. 
//
// notes: 
//(1) This procedure depends on the mel command "exactWorldBoundingBox $obj" which 
// returns a float[] xmin ymin zmin xmax ymax zmax.  I use ymin to temporarily set
// the Y position of $obj's pivot so I can move it along Y such that it sits on the grid. 
// Moving each object to the grid has a constant complexity O(1).  This procedure has a 
// complexity of O(n), where n is the number of objects in the selection.
//
// [strike](2) this procedure moves the object but leaves the objects pivot in the same worldspace
// location.  I am not sure of the value of doing this and may want to either keep the
// local (relative) pivot location or just center the pivot.
//
// [strike](3) changed the script to maintain the relative pivot when the object is moved.
//
// (4) changed script to accept a pivot control parameter to control if the object object
// space or world space pivot is maintained or if the pivot is simply centered.
// 
// author: ctbram with valuable input from nextdesign
// date: 05292012
//
// change log:
// 05292012 - 
// (1) changed the program so the relative pivot of the object is maintained rather
// then the world pivot
// (2) added $pc (pivot control) parameter to control how the pivot is handled when the 
// object is moved.  0 = maintain object space, 1 = maintain world space, 2 = center pivot
//
global proc rmToFloor(int $pc)
{
    string $sel[] = `ls -sl`;
    string $obj;
    
    // make sure the pivot control parameter is 0 | 1 | 2.
    if (!(($pc == 0) || ($pc == 1) || ($pc == 2)))
         error("pivot control parameter must be (0 | 1 | 2).");

    for($obj in $sel)
    {
         float $osPivot[] = `xform -q -os -rp $obj`;                // save the object space (relative) pivot
         
    	 // move the object using world space coordinates...
    	 float $wsPivot[] = `xform -q -ws -rp $obj`;                // save world space $obj pivot
         float $bbox[] = `exactWorldBoundingBox $obj`;              // get bounding box world space coords
         float $lowest = $bbox[1];                                  // get lowest vert (ymin)
         xform -ws -rp $wsPivot[0] $lowest $wsPivot[2] $obj;        // reset the pivot to the lowest point in world space
         move -rpr $wsPivot[0] 0 $wsPivot[2] $obj;                  // move the object to the grid
         
         // handle the pivot based on the pivot control parameter $pc
    	 if ($pc == 0)
    	     xform -os -rp $osPivot[0] $osPivot[1] $osPivot[2] $obj;    // restore the object space (relative) pivot
    	 else if ($pc == 1)
    	     xform -ws -rp $wsPivot[0] $wsPivot[1] $wsPivot[2] $obj;    // restore the world space (relative) pivot
    	 else
    	     xform -cp $obj;    // center the pivot
    }
}


"If I have seen further it is by standing on the shoulders of giants." Sir Isaac Newton, 1675

Last edited by ctbram; 29-05-2012 at 11:54 AM.
# 26 30-05-2012 , 04:35 AM
ctbram's Avatar
Moderator
Join Date: Jan 2004
Location: Michigan, USA
Posts: 2,998
LOL this little script keeps becoming more and more complicated. I just discovered another problem. If you rotate any object then that object bounding box also rotates and therefore the lowest point ymin of the bounding box can be lower then the lowest vert in the object and so the result is rotated object end up floating above the y=0 global plane!

So now to fix it I have to figure out how to

(1) save the current transforms (particularly rotation)
(2) freeze the rotation transforms so the bounding bound ymin is once again at the lower vertex in the object
(3) do all the moving
(4) restore the transforms.

This is basically saying I have to freeze then unfreeze transforms and I don't have a clue how to do that and I don't want to change the state of the object by freezing its transforms before moving it. So I will have to do some more research.

For what seems like a simple task, this is getting kind of hard. I think this last thing should fix it for all cases though.

To see the problem create a poly sphere and rotate and then turn on bounding box under the shading tab and you will immediately see the problem. Then freeze the transforms on the sphere and you see the bounding box rotates and the lowest point ymin will be at the lowest vert in the sphere again.

It would be a simple matter to freeze transforms before computing the bounding box and and doing the moving but that leaves the state of the object altered.


"If I have seen further it is by standing on the shoulders of giants." Sir Isaac Newton, 1675

Last edited by ctbram; 30-05-2012 at 04:38 AM.
# 27 30-05-2012 , 05:21 AM
ctbram's Avatar
Moderator
Join Date: Jan 2004
Location: Michigan, USA
Posts: 2,998
hmm trying to control the pivot and transforms of the objects is a pain. Right now the simplest approach I can think of is to

1. duplicate the object
2. freeze the dups transforms
3. get the ymin of the bounding box for the dup = $lowest
4. delete the dup

Now with $lowest follow the algorithm as written. This seems to really be the cave man approach to the problem though as creating a duplicate and then deleting the duplicate for every object seems clumsy.


"If I have seen further it is by standing on the shoulders of giants." Sir Isaac Newton, 1675
# 28 30-05-2012 , 08:04 PM
Registered User
Join Date: Apr 2012
Posts: 32
lol I didn't realise my request was going to trigger an obsession and sleepless nights..so sorry

but it has been interesting following this, learnt a lot..Yes drop to floor is really handy there is a plug for cinema 4d, not sure what the algorithm is, but its quick

thanks again

# 29 30-05-2012 , 08:09 PM
ctbram's Avatar
Moderator
Join Date: Jan 2004
Location: Michigan, USA
Posts: 2,998
yeah. it's trying to maintain the pivots that is making me crazy. I may just freeze transform on each object to correct the bounding box and just live with it. Until I can figure out how to correct for rotation of the bounding box without affecting the transforms


"If I have seen further it is by standing on the shoulders of giants." Sir Isaac Newton, 1675
# 30 30-05-2012 , 08:32 PM
ctbram's Avatar
Moderator
Join Date: Jan 2004
Location: Michigan, USA
Posts: 2,998
Okay, here is the fix to the rotation problem. I have to freezetransformation on each object before using the bounding box to get the lowest vert. This will alter the transforms on every object. I am working on a better solution.

Code:
// procedure rmToFloor(int $pc)
// Move the lowest point of all objects in the selection so they sit exactly on the 
// top of the grid (global Y=0).
//
// params:
// int $pc - pivot control - (0 | 1 | 2)
// 0 = maintain object space (relative) pivot position
// 1 = maintain world space (global) pivot position
// 2 = center the pivot
// 
// usage: rmToFloor( 0 | 1 | 2);
// Copy this script to your maya scripts folder and source it and then make a selection of all
// the objects you want to move so they are sitting on the grid and enter the command
// rmToFloor 0 | 1 | 2;. 
//
// notes: 
//(1) This procedure depends on the mel command "exactWorldBoundingBox $obj" which 
// returns a float[] xmin ymin zmin xmax ymax zmax.  I use ymin to temporarily set
// the Y position of $obj's pivot so I can move it along Y such that it sits on the grid. 
// Moving each object to the grid has a constant complexity O(1).  This procedure has a 
// complexity of O(n), where n is the number of objects in the selection.
//
// [strike](2) this procedure moves the object but leaves the objects pivot in the same worldspace
// location.  I am not sure of the value of doing this and may want to either keep the
// local (relative) pivot location or just center the pivot.
//
// [strike](3) changed the script to maintain the relative pivot when the object is moved.
//
// (4) changed script to accept a pivot control parameter to control if the object object
// space or world space pivot is maintained or if the pivot is simply centered.
// 
// author: ctbram with valuable input from nextdesign
// date: 05292012
//
// change log:
// 05292012 - 
// (1) changed the program so the relative pivot of the object is maintained rather
// then the world pivot
// (2) added $pc (pivot control) parameter to control how the pivot is handled when the 
// object is moved.  0 = maintain object space, 1 = maintain world space, 2 = center pivot
//
// 05302012 -
// (1) Before computing the lower pivot using the bounding box I had to freetransformation
// on each object to zero out the rotation and align the bounding box to the global axis.
// Until I can find a better solution this is going to have to be lived with.
//
global proc rmToFloor(int $pc)
{
    string $sel[] = `ls -sl`;
    string $obj;
    
    // make sure the pivot control parameter is 0 | 1 | 2.
    if (!(($pc == 0) || ($pc == 1) || ($pc == 2)))
         error("pivot control parameter must be (0 | 1 | 2).");

    for($obj in $sel)
    {
         float $osPivot[] = `xform -q -os -rp $obj`;                // save the object space (relative) pivot
         
    	 // move the object using world space coordinates...
    	 float $wsPivot[] = `xform -q -ws -rp $obj`;                // save world space $obj pivot
         
         // Unrotate the bounding box and align it to the global axis so that the ymin 
	 // of the bounding box is also the ymin of the lowest vert in the object.  This alters
	 // the transformations on every object.  I am working on a better solution.
         select $obj; FreezeTransformations;    	 

         float $bbox[] = `exactWorldBoundingBox $obj`;              // get bounding box world space coords
         float $lowest = $bbox[1];                                  // get lowest vert (ymin)
         
         xform -ws -rp $wsPivot[0] $lowest $wsPivot[2] $obj;        // reset the pivot to the lowest point in world space
         move -rpr $wsPivot[0] 0 $wsPivot[2] $obj;                  // move the object to the grid
         
         // handle the pivot based on the pivot control parameter $pc
    	 if ($pc == 0)
    	     xform -os -rp $osPivot[0] $osPivot[1] $osPivot[2] $obj;    // restore the object space (relative) pivot
    	 else if ($pc == 1)
    	     xform -ws -rp $wsPivot[0] $wsPivot[1] $wsPivot[2] $obj;    // restore the world space (relative) pivot
    	 else
    	     xform -cp $obj;    // center the pivot
    }
    
    select $sel;
}


"If I have seen further it is by standing on the shoulders of giants." Sir Isaac Newton, 1675

Last edited by ctbram; 30-05-2012 at 08:39 PM.
Posting Rules Forum Rules
You may not post new threads | You may not post replies | You may not post attachments | You may not edit your posts | BB code is On | Smilies are On | [IMG] code is On | HTML code is Off

Similar Threads