Take the 2-minute tour ×

I want to randomly rotate a list of objects on a given axis with a random amount retrieved from a specified range. This is what I came up with:

import pymel.core as pm
import random as rndm

def rndmRotateX(targets, axisType, range=[0,180]):
    for obj in targets:
        xDeg='%sDeg' % (rValue)
        #if axisType=='world':
        #    pm.rotate(rValue,0,0, obj, ws=1)
        #if axisType=='object':
        #    pm.rotate(rValue,0,0, obj, os=1)

targetList= pm.ls(sl=1)

Im using pm.rotate() because it allows me to specify whether I want the rotations done in world or obj space (unlike setAttr, as far as I can tell). The problem is, it raises this error when I try to run this:

# Error: MayaNodeError: file C:\Program Files\Autodesk\Maya2012\Python\lib\site-packages\pymel\internal\pmcmds.py line 140:  #

It must be something with they way I enter the arguments for pm.rotate() (Im assuming this due to the line error PyMel spits out, which has to do with its arguments conversion function), but I cant figure out for the life of me wth I did wrong. :/

share|improve this question
Just for debugging stuff like this, it's probably worth setting the stack trace to be on. From the error, it looks like you've got just line numbers on, but if you'd had the stack trace on, you'd get something closer to: # MayaNodeError: Maya Node does not exist: u'55Deg' # which would point you at that first argument being a bit off –  tanantish Dec 16 '12 at 7:45
add comment

3 Answers

up vote 0 down vote accepted

Just as a straight debug of what you've got...

Issue 01: it's case sensitive

pm.rotate("20deg",0,0) will work fine, but pm.rotate("20Deg",0,0) will fail and throw a MayaNodeError because it thinks that you're looking for a node called '20Deg'. Basically, you want to build your string as per: xDeg='%sdeg' % (rValue)

Issue 02: you're relying on pm.rotate()'s implicit "will apply to selected objects" behaviour

You won't see this til you apply the above fix, but if you have two selected objects, and ran the (patched) rndmRotateX function on them, you'd get both objects rotating by the exact same amount, because pm.rotate() is operating on the selection (both objects) rather than a per-object rotation.

If you want a quick fix, you need to insert a pm.select(obj) before the rotate. And you possibly want to save the selection list and restore it...however IMHO, it's a Really Bad Idea to rely on selections like this, and so I'd push you towards Kim's answer.

share|improve this answer
add comment

I think the problem is in this line

pm.rotate(rValue,0,0, obj, os=1)

obj should be the first argument, so it should be

pm.rotate(obj, (rValue,0,0), os=1)

but to make it even prettier you could use

obj.setRotation((rValue,0,0), os=1)

And also. Use pm.selected() instead of pm.ls(sl=1). It looks better

share|improve this answer
Nope, that's not it; :/ which would have been weird anyways, the arguments are similarly written to mine in the documentation. pymel.googlecode.com/svn/docs/generated/functions/… Any other suggestions? This is really weird. :/ –  Nils Diefenbach Nov 20 '12 at 10:08
Well like the documentation says, the syntax should be: rotate(OBJECT, *args, **kwargs). You try to write rotate(*args, OBJECT, **kwargs). Also you need to keep the XYZ arguments in a tuple or list. So (X,Y,Z) or [X,Y,Z]. –  Kim Bourdette Nov 20 '12 at 16:23
Niels you have a syntax error of kinds, and kim is right. You problem is that you say pm.rotate(... but you think you say obj.rotate(... You are doing a very classic error of reading what you think is there not reading what is there. Or then you have a paste error. –  joojaa Nov 21 '12 at 7:03
So it should be like this, right? def rndmRotateX(targets, axisType, range=[0,180]): for obj in targets: rValue=rndm.randint(range[0],range[1]) xDeg='%sDeg' % (rValue) pm.rotate(obj,(xDeg,0,0,),r=True) It still isn't working though. Still gives me this stupid error >_< –  Nils Diefenbach Nov 27 '12 at 15:03
and just fyi, in the example objects aren't first either, nor are the values in lists/tuples: >>> # Set the rotation values for group1 to (90, 0, 0). This is >>> # equivalent to: >>> # pm.setAttr('group1.rx',90) >>> # pm.setAttr('group1.ry',0) >>> # pm.setAttr('group1.rz',0) >>> pm.rotate( '90deg', 0, 0, 'group1' ) –  Nils Diefenbach Nov 27 '12 at 15:07
show 1 more comment

Another way to go about doing this..

from pymel.core import *
import random as rand

def rotateObjectsRandomly(axis, rotateRange):
    rotateValue = rand.random() * rotateRange
    for obj in objects:
        PyNode(str(selected()) + ".r" + axis).set(rotateValue)
    objectRotation = [[obj, obj.r.get()] for obj in selected()]
    print "\nObjects have been rotated in the {0} axis {1} degrees.\n".format(axis, rotateValue)
    return objectRotation

rotateObjectsRandomly("z", 360)

Since rand.random() returns a random value between 0 - 1, I just multiplied that by the rotateRange specified by the user..or in my preference I would just do away with that all together and just multiply it by 360...

You also don't need all the feedback I just think it looks nice when ran..

Objects have been rotated in the z axis 154.145898182 degrees.

# Result: [[nt.Transform(u'myCube'), dt.Vector([42.6541437517, 0.0, 154.145898182])]] # 
share|improve this answer
add comment

Your Answer


