Im having trouble getting two definitions to speak to each other using a UI. I would like to create a bunch of locators place them in the scene and name them. Then in a different definition create some joints and use the locators name and position to position the joints and name them according to the locators I previously created.
My problem is the variable named rootJnt is not being recognized in the joint creation definition. All others are except rootJnt. I don't understand why, all the other variables are being recognized. Can some one please explain?
from maya import cmds
def proxySkel (self):
target = cmds.ls (selection = True)
DDD = cmds.textField (textNam,
query = True,
text = True)
# CREATE THE LOCATOR
_endOutLoc = cmds.spaceLocator (position = (0, 0, 0), name = DDD + '_locEndOut')
_startOutLoc = cmds.spaceLocator (position = (0, 0, 0), name = DDD + '_locStartOut')
_rootLoc = cmds.spaceLocator (position = (0, 0, 0), name = DDD + '_locRoot')
# MOVE END LOCATOR IN SPACE
cmds.move (5, 0, 3, _endOutLoc, absolute = True)
cmds.move (0, 0, 3, _startOutLoc, absolute = True)
return _endOutLoc, _startOutLoc, _rootLoc
def jointsCreate (self):
target = cmds.ls (selection = True)
DDD = cmds.textField (textNam,
query = True,
text = True)
# CREATE THE JOINTS
rootJnt = cmds.joint (position = (0.0, 0.0, 0.0), name = _rootLoc + '_jnt')
endOutJnt = cmds.joint (position = (0.0, 0.0, 0.0), name = _endOutLoc[0] + '_jnt')
startOutJnt = cmds.joint (position = (0.0, 0.0, 0.0), name = _startOutLoc[0] + '_jnt')
# PLACE THE JOINTS INTO SPACE
rootConst = cmds.parentConstraint (_rootLoc, rootJnt, mo = False)
endOutConst = cmds.parentConstraint (_endOutLoc, endOutJnt, mo = False)
startInConst = cmds.parentConstraint (_startInLoc, startInJnt, mo = False)
# CREATE THE JOINT HIERARCHY
cmds.parent (startInJnt, rootJnt)
cmds.parent (startInJnt, startOutJnt)
if(cmds.window('window1',q=1,ex=1)):
cmds.deleteUI('window1')
cmds.window('window1',menuBar=1)
cmds.columnLayout()
textNam = cmds.textField(width=150,
text='Name',
backgroundColor=[0.6233005264362554, 1.0, 0.9765011062790875])
cmds.separator()
cmds.rowLayout(numberOfColumns=3)
cmds.button(width=65,
command = proxySkel,
backgroundColor=[0.0, 0.2187533379110399, 1.0],
label='Locators')
cmds.separator(style='none',
width=3)
cmds.button(width=78,
command = jointsCreate,
backgroundColor=[0.7971007858396277, 0.0, 0.0],
label='Joints')
cmds.showWindow('window1')
To have access to your variables between two functions, you have to define them in an outer scope. In your case _endOutLoc, _startOutLoc, _rootLoc are defined locally to ProxySkel function and they are not visible to jointsCreate function
In additional to that, there are several other mistakes
as it was mentioned in the comments to your question, _rootLoc have to be passed with index 0, because it stores value as a list, not as a string
if you are using parent constraint for the alignment, I would guess you want to delete them once the alignment is finished
there is no need to call parent command for the joints, as they are already parented in the order of cmds.joint calls. Here is a note from documentation "In the creation mode, a new joint will be created as a child of a selected transform or starts a hierarchy by itself if no transform is selected." if you don't want such behaviour, you should clear the selection
cmds.window('window1',menuBar=1) have to be always called, not inside the existance window condition, otherwise the UI elements will be attached to the script editor window
here is an updated script
from maya import cmds
global _endOutLoc
global _startOutLoc
global _rootLoc
def proxySkel (self):
global _endOutLoc, _startOutLoc, _rootLoc
target = cmds.ls (selection = True)
DDD = cmds.textField (textNam,
query = True,
text = True)
# CREATE THE LOCATOR
_endOutLoc = cmds.spaceLocator (position = (0, 0, 0), name = DDD + '_locEndOut')
_startOutLoc = cmds.spaceLocator (position = (0, 0, 0), name = DDD + '_locStartOut')
_rootLoc = cmds.spaceLocator (position = (0, 0, 0), name = DDD + '_locRoot')
# MOVE END LOCATOR IN SPACE
cmds.move (5, 0, 3, _endOutLoc, absolute = True)
cmds.move (0, 0, 3, _startOutLoc, absolute = True)
return _endOutLoc, _startOutLoc, _rootLoc
def jointsCreate (self):
global _endOutLoc, _startOutLoc, _rootLoc
if None in [_endOutLoc, _startOutLoc, _rootLoc]:
print('locators are not created yet')
return
target = cmds.ls (selection = True)
DDD = cmds.textField (textNam,
query = True,
text = True)
# CREATE THE JOINTS
rootJnt = cmds.joint (position = (0.0, 0.0, 0.0), name = _rootLoc[0] + '_jnt')
endOutJnt = cmds.joint (position = (0.0, 0.0, 0.0), name = _endOutLoc[0] + '_jnt')
startOutJnt = cmds.joint (position = (0.0, 0.0, 0.0), name = _startOutLoc[0] + '_jnt')
# PLACE THE JOINTS INTO SPACE
rootConst = cmds.parentConstraint (_rootLoc, rootJnt, mo = False)
endOutConst = cmds.parentConstraint (_endOutLoc, endOutJnt, mo = False)
startInConst = cmds.parentConstraint (_startOutLoc, startOutJnt, mo = False)
# DELETE CONSTRAINTS AFTER ALIGNMENT
cmds.delete (rootConst, endOutConst, startInConst)
# CREATE THE JOINT HIERARCHY
#cmds.parent (endOutJnt, rootJnt)
#cmds.parent (startOutJnt, endOutJnt)
if(cmds.window('window1',q=1,ex=1)):
cmds.deleteUI('window1')
cmds.window('window1',menuBar=1)
cmds.columnLayout()
textNam = cmds.textField(width=150,
text='Name',
backgroundColor=[0.6233005264362554, 1.0, 0.9765011062790875])
cmds.separator()
cmds.rowLayout(numberOfColumns=3)
cmds.button(width=65,
command = proxySkel,
backgroundColor=[0.0, 0.2187533379110399, 1.0],
label='Locators')
cmds.separator(style='none',
width=3)
cmds.button(width=78,
command = jointsCreate,
backgroundColor=[0.7971007858396277, 0.0, 0.0],
label='Joints')
cmds.showWindow('window1')
Related
I've been trying to figure out for a while now how to connect 2 shader nodes for the material I'm making in a blender, Been googling all over but I can't seem to wrap my head around how to connect them; The last 2 lines of code below are my best attempts. Hopefully, someone can see through this object madness as I cannot.
class WM_OT_textOpBasic(bpy.types.Operator):
"""Creates the Base Planet"""
bl_idname = "wm.textopbasic"
bl_label = " Text Tool Operator"
def execute(self, context):
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=6, radius=1.0, calc_uvs=True, enter_editmode=False, align='WORLD', location=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0), scale=(1.0, 1.0, 1.0))
planet = bpy.context.selected_objects[0]
planet.name = "Planet"
planet_material = bpy.data.materials.get("planet material")
if planet_material is None:
# create material
planet_material = bpy.data.materials.new(name="planet material")
planet.data.materials.append(planet_material)
planet_material.use_nodes = True
nodes = planet_material.node_tree.nodes
ColorRamp1 = nodes.new('ShaderNodeValToRGB')
ColorRamp1.location = -400,100
ColorRamp2 = nodes.new('ShaderNodeValToRGB')
ColorRamp2.location = -700,100
ColorRamp3 = nodes.new('ShaderNodeValToRGB')
ColorRamp3.location = -1000,100
Noise1 = nodes.new('ShaderNodeTexNoise')
Noise1.location = -1100,300
Noise2 = nodes.new('ShaderNodeTexNoise')
Noise2.location = -900,300
Bump = nodes.new('ShaderNodeBump')
Bump.location = -150,-150
planet.active_material.node_tree.links.new(Noise1.outputs[0],Noise2.inputs[1])
planet_material.node_tree.links(Noise1.outputs[0],Noise2.inputs[1])
```
Your question doesn't specify the exact configuration of the nodes but this code shows a bit of how it works
import bpy
bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=6, radius=1.0, calc_uvs=True, enter_editmode=False, align='WORLD', location=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0), scale=(1.0, 1.0, 1.0))
planet = bpy.context.selected_objects[0]
planet.name = "Planet"
planet_material = bpy.data.materials.get("planet material")
if planet_material is None:
# create material
planet_material = bpy.data.materials.new(name="planet material")
planet.data.materials.append(planet_material)
planet_material.use_nodes = True
if planet_material.node_tree:
planet_material.node_tree.links.clear()
planet_material.node_tree.nodes.clear()
nodes = planet_material.node_tree.nodes
links = planet_material.node_tree.links
ColorRamp1 = nodes.new('ShaderNodeValToRGB')
ColorRamp1.location = -400,100
Noise1 = nodes.new('ShaderNodeTexNoise')
Noise1.location = -1100,300
output = nodes.new(type='ShaderNodeOutputMaterial') # you need an output node to display
links.new(Noise1.outputs[0], ColorRamp1.inputs[0]) # Noise1.output[0] just takes the start node of noise one at spot 0, ColorRamp1.inputs[0] is the input spot for the noise again at spot 0
links.new(Noise1.outputs[0], output.inputs[1])
links.new(ColorRamp1.outputs[0], output.inputs[1])
planet.data.materials.append(planet_material)
I wanted to try out some raycasting with Python in Maya using OpenMaya.MFnMesh.anyIntersection().
I just want to cast a ray from on object downwards and hit a plane, not go any further so I get only one raycasthit and get the translation values from the raycasthit.
I got the code from a video and made it a bit clearer to understand.
For the code to run properly in Maya you need an object that is higher in the Y-axis than a different one, preferably a polyPlane(for example: having a polySphere at position [0, 3, 0] and a polyPlane at position [0, 0, 0], select the polySphere and run the code)
import maya.OpenMaya as OpenMaya
import maya.cmds as cmds
def RayReposition(*args):
direction = (0.0, -1, 0)
sel = cmds.ls(sl = True)
fromPositionRay = cmds.xform(sel[0], query = True, translation = True)
selShape = cmds.listRelatives(shapes = True)
meshes = cmds.ls(geometry = True)
cmds.select(clear = True)
for x in meshes:
if x == selShape[0]:
continue
else:
OpenMaya.MGlobal.selectByName(x)
sList = OpenMaya.MSelectionList()
OpenMaya.MGlobal.getActiveSelectionList(sList)
item = OpenMaya.MDagPath()
sList.getDagPath(0, item)
item.extendToShape()
fnMesh = OpenMaya.MFnMesh(item)
raySource = OpenMaya.MFloatPoint(fromPositionRay[0], fromPositionRay[1], fromPositionRay[2], 1.0)
rayDir = OpenMaya.MFloatVector(direction[0], direction[1], direction[2])
faceIds = None
triIds = None
idsSorted = False
testBothDirections = False
worldSpace = OpenMaya.MSpace.kWorld
maxParam = 999999
accelParams = None
sortHits = True
hitPoints = OpenMaya.MFloatPointArray()
hitRayParams = OpenMaya.MFloatArray()
hitFaces = OpenMaya.MIntArray()
hitTris = None
hitBarys1 = None
hitBarys2 = None
tolerance = 0.0001
hit = fnMesh.anyIntersection(raySource, rayDir, worldSpace, maxParam, testBothDirections, faceIds, triIds, idsSorted, accelParams, tolerance, hitPoints, hitRayParams, hitFaces, hitTris, hitBarys1, hitBarys2)
OpenMaya.MGlobal.clearSelectionList()
firstHit = (hitPoints[0].x, hitPoints[0].y, hitPoints[0].z)
print firstHit
RayReposition()
I expected to get the translation values from the raycasthit but I get the following error:
TypeError: in method 'MFnMesh_anyIntersection', argument 4 of type 'MIntArray const *'
Using the OpenMaya.MFnMesh.allIntersections() function instead works perfectly fine but I get every single hit from the raycast, but I only want the first hit.
Links to the OpenMaya.MFnMesh API:
link: https://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__py_ref_class_open_maya_1_1_m_fn_mesh_html
The main thing is that anyIntersection is looking for a single intersection it hits first, not multiple. So your out parameters are of the wrong types because they're arrays.
I would also avoid clearing or making new selections in your loop as it would just slow down performance by having to redraw the viewports every time.
Here's a working example that will create a locator on the first mesh it hits:
import maya.OpenMaya as OpenMaya
import maya.cmds as cmds
def RayReposition(*args):
direction = (0.0, -1, 0)
sel = cmds.ls(sl=True)
fromPositionRay = cmds.xform(sel[0], query=True, translation=True)
selShape = cmds.listRelatives(shapes=True)
meshes = cmds.ls(geometry=True)
for x in meshes:
if x == selShape[0]:
continue
else:
sList = OpenMaya.MSelectionList()
sList.add(x)
item = OpenMaya.MDagPath()
sList.getDagPath(0, item)
item.extendToShape()
fnMesh = OpenMaya.MFnMesh(item)
raySource = OpenMaya.MFloatPoint(fromPositionRay[0], fromPositionRay[1], fromPositionRay[2], 1.0)
rayDir = OpenMaya.MFloatVector(direction[0], direction[1], direction[2])
worldSpace = OpenMaya.MSpace.kWorld
maxParam = 999999
testBothDirections = False
faceIds = None
triIds = None
idsSorted = False
accelParams = None
sortHits = True
hitPoints = OpenMaya.MFloatPoint()
hitRayParams = None
hitFaces = None
hitTris = None
hitBarys1 = None
hitBarys2 = None
tolerance = 0.0001
hit = fnMesh.anyIntersection(
raySource, rayDir, faceIds, triIds, idsSorted, worldSpace, maxParam, testBothDirections, accelParams,
hitPoints, hitRayParams, hitFaces, hitTris, hitBarys1, hitBarys2, tolerance)
if hit:
firstHit = (hitPoints.x, hitPoints.y, hitPoints.z)
loc = cmds.spaceLocator()[0]
cmds.xform(loc, ws=True, t=firstHit)
print "Hit on {} at {}".format(x, firstHit)
break
RayReposition()
I find the c++ documentation a bit more clearer of what the method expects for parameters.
I want to use a checkbox to control the ratio multiplied in slider function.
First I try to change the variable directly, but failed.
Then I try to change the dragCommand, but also failed.
How can I control it?
import pymel.core as pm
import math
myRatio = math.sqrt(2) * 0.5
def myPolyBevel(*args):
# called by convert
def convertOn(*args):
#myRatio = math.sqrt(2) * 0.5
myOffsetSlider.dragCommand = myOffsetOn
def convertOff(*args):
#myRatio = 1.0
myOffsetSlider.dragCommand = myOffsetOff
# called by offset
def myOffsetOn(*args):
temp = pm.floatSliderGrp( myOffsetSlider, query = True, value = True ) * myRatio
pm.setAttr( myBevel.name()+".offset", temp )
def myOffsetOff(*args):
temp = pm.floatSliderGrp( myOffsetSlider, query = True, value = True )
pm.setAttr( myBevel.name()+".offset", temp )
# main
if pm.selected():
# add Bevel
newBevel = pm.polyBevel3( pm.selected(), offset = 0.1 * myRatio, segments = 2, smoothingAngle = 30, chamfer = 1 )
myBevel = newBevel[0]
# UI
bevelWindow = pm.window(title = 'Bevel')
bevelLayout = pm.columnLayout()
myConvert = pm.checkBoxGrp( numberOfCheckBoxes = 1, label = '', label1 = 'Convert', value1 = 1, onCommand = convertOn, offCommand = convertOff )
myOffsetSlider = pm.floatSliderGrp( label='Offset', field = True,
minValue = 0.0, maxValue = 5.0,
fieldMinValue = 0.0, fieldMaxValue = 100.0,
value = 0.1, step = 0.001,
dragCommand = myOffsetOn, changeCommand = myOffsetOn )
pm.showWindow()
# Main
mainWindow = pm.window(title = 'Star')
mainLayout = pm.gridLayout( cellWidthHeight = (40,40), numberOfColumns = 5 )
bevelButton = pm.button( label = 'Bevel', command = myPolyBevel)
pm.showWindow()
You may have to not nest all this command, it makes it harder (or use some Class method)
use partial to pass args :
Maya Python - Using data from UI
here a useful post you can refer, check theodor and my answers on the topic (we often answer this question )
I need to import multiple files into Maya and assign multiple materials to each one.
I have the following code in Python:
import maya.cmds as cmds
import glob
def importFile(i):
cmds.file(i, i=True, groupReference=True, groupName="myobj")
def moveFile():
cmds.select("myobj")
cmds.scale(1,1,1, r=True)
cmds.move (0, 14, 0, r=True)
cmds.rotate (-90, 0, 0, r=True)
def materialFile():
cmds.select("myobj")
myMaterial = "blinn1"
cmds.sets( e=True, forceElement= myMaterial + 'SG' )
def renderFile(i):
cmds.setAttr("defaultRenderGlobals.imageFilePrefix", i, type="string")
cmds.render(batch=True)
def deleteFile():
cmds.select("myobj")
cmds.delete()
myglob = glob.glob("/The/path/of/your/Obj_files/*.obj")
for i in myglob:
importFile(i)
moveFile()
materialFile()
renderFile(i)
deleteFile()
With this code I can assign only one shader to the whole piece of geometry.
Is it possible to assign different shaders to the same piece of geometry?
Definitely, you can assign different shaders to the same piece of geometry as well as any accessible shader for multiple 3d models.
import maya.cmds as mat
d = 0
shader_node1 = mat.shadingNode( "anisotropic", asShader = True, n = 'ani' )
shader_node2 = mat.shadingNode( "phong", asShader = True, n = 'pho' )
shader_node3 = mat.shadingNode( "lambert", asShader = True, n = 'lam' )
mat.setAttr( (shader_node1 + '.color'), 1.0, 0.0, 0.0, type = 'double3' )
mat.setAttr( (shader_node2 + '.color'), 0.0, 1.0, 0.0, type = 'double3' )
mat.setAttr( (shader_node2 + '.transparency'), 0.25, 0.25, 0.25, type = 'double3' )
mat.setAttr( (shader_node3 + '.color'), 0.0, 0.0, 1.0, type = 'double3' )
shading_group1 = mat.sets( renderable = True, noSurfaceShader = True, empty = True )
shading_group2 = mat.sets( renderable = True, noSurfaceShader = True, empty = True )
shading_group3 = mat.sets( renderable = True, noSurfaceShader = True, empty = True )
mat.connectAttr( '%s.outColor' %shader_node1, '%s.surfaceShader' %shading_group1 )
mat.connectAttr( '%s.outColor' %shader_node2, '%s.surfaceShader' %shading_group2 )
mat.connectAttr( '%s.outColor' %shader_node3, '%s.surfaceShader' %shading_group3 )
mat.polySphere( radius = 5 )
mat.polySphere( radius = 7 )
mat.polySphere( radius = 3 )
mat.select( 'pSphere1' )
mat.move( 7, 6, 0, r = True )
mat.hyperShade( assign = shader_node1 )
mat.select( 'pSphere2' )
mat.hyperShade( assign = shader_node2 )
mat.select( 'pSphere3' )
mat.move( -7, -2, 0, r = True )
mat.hyperShade( assign = shader_node3 )
d += 1
Also you can access your shaders within an array using random function:
import random as random
myArray = [shader_node1, shader_node2, shader_node3]
for i in myArray :
mat.select( 'pSphere1' )
mat.move( 7, 6, 0, r = True )
mat.hyperShade( assign = myArray[int(random.uniform(0,3))] )
mat.select( 'pSphere2' )
mat.hyperShade( assign = myArray[int(random.uniform(0,3))] )
mat.select( 'pSphere3' )
mat.move( -7, -2, 0, r = True )
mat.hyperShade( assign = myArray[int(random.uniform(0,3))] )
I've only just started coding, so I thought I would try and make something simple, however, I can't select the objects from my ls, I know the error is in my def attrLockT and was wondering if anyone could help me to fix this issue and understand what I am doing wrong?
import maya.cmds as cmds
#Selects the attributes
sat = ['.tx', '.ty', '.tz']
sar = ['.rx', '.ry', '.rz']
sas = ['.sx', '.sy', '.sz']
#Creates the list of currently selected objects
myList = cmds.ls(sl = True)
#Lock the translate attributes of the selected objects
def attrLockT(*args):
checkAttr=cmds.getAttr (myList[0] + sat)
if (checkAttr == 0):
cmds.setAttr(myList[0] + sat, lock = 1)
#Delete window if it is already open
if cmds.window('animationCtrl', exists=True):
cmds.deleteUI('animationCtrl', window=True)
#Setup the window
cmds.window(
'animationCtrl',
title = "Animation Controls",
widthHeight = (300, 500),
s = False)
form = cmds.formLayout()
tabs = cmds.tabLayout(innerMarginWidth=5, innerMarginHeight=5)
cmds.formLayout(
form,
edit=True,
attachForm=(
(tabs, 'top', 0),
(tabs, 'left', 0),
(tabs, 'bottom', 0),
(tabs, 'right', 0)))
#Layout for the first tab
child1 = cmds.gridLayout( numberOfRowsColumns=(4, 3) , cwh = (100, 50))
cmds.text(label = "")
cmds.text(label = "Lock", align = "center", h = 20, w = 250)
cmds.text(label = "")
cmds.button(label = "Translate", h = 300, w = 250, c = attrLockT)
cmds.button(label = "Rotate", h = 50, w = 250)
cmds.button(label = "Scale", h = 50, w = 250)
cmds.text(label = "")
cmds.text(label = "Unlock", align = "center", h = 20, w = 250)
cmds.text(label = "")
cmds.button(label = "Translate", h = 50, w = 250)
cmds.button(label = "Rotate", h = 50, w = 250)
cmds.button(label = "Scale", h = 50, w = 250)
cmds.setParent( '..' )
#Layout for the second tab
child2 = cmds.rowColumnLayout(numberOfColumns=3)
cmds.button()
cmds.button()
cmds.button()
cmds.setParent( '..' )
cmds.tabLayout(
tabs,
edit=True,
tabLabel=((child1, 'Lock/Unlock'), (child2, 'Keyable/Unkeyable')))
cmds.showWindow('animationCtrl')
The error that is thrown is
# Error: coercing to Unicode: need string or buffer, list found
# Traceback (most recent call last):
# File "<maya console>", line 16, in attrLockT
# TypeError: coercing to Unicode: need string or buffer, list found
Does this work?
myList[0] + sat
Is myList[0] type of list ? Because the sat variable is certainly list.
If myList is just a list of string then myList[0] will be just one element of type string and it will produce an error.
Simplify your program, just leave only locking routine and window with button to see what will happen, be sure that the right name of an object + attribute is passed to getAttr - just string like 'obj.attrib'.
Some python specific clues for your function
If you need to sum two lists:
[ objName + attName for objName, attName in zip(myList, sat) ]
that will result, for example, in ['obj1.tx', 'obj2.ty', 'obj3.tz']
If you need apply a list of attributes to an object:
[ myList[0] + a for a in sat ]
that will result in ['obj1.tx', 'obj1.ty', 'obj1.tz']
If you need apply the same list of attributes to all objects:
[ objName + attName for objName in myList for attName in sat ]
will result in ['obj1.tx', 'obj1.ty', 'obj1.tz', 'obj2.tx', ..., 'obj3.tz']
Then you can call your locking function over that result list:
def locker(a):
checkAttr = cmds.getAttr(a)
if (checkAttr == 0):
cmds.setAttr(a, lock = 1)
and finally it should look:
def attrLockT(*args):
atrlist = [ ..... ]
for a in atrlist:
locker(a)
Two issues:
first, you want to loop through the individual attributes and concatenate them with object names:
def lockTranslate(*args):
for obj in mylist:
for attr in ['.tx', '.ty', '.tz']:
cmds.setAttr(obj + "." + attr, l=True)
second, and maybe more important, you will likely have problems the scope of your functions. In the form you have it typed in, variables like myList and sat, etc are accessible to the function through closure - it will work if you execute all of this in the listener, but if you break the closure (for example, if this goes into a function that gets called by another function) things wont work -- myList will be stuck pointing at whatever was selected when the function was defined.
In this particular case you probably want to just operate on selection instead of inheriting myList:
def lockTranslate(*args):
for obj in cmds.ls(sl=True, type = 'transform'):
for attr in ['.tx', '.ty', '.tz']:
cmds.setAttr(obj + "." + attr, l=True)