Driving an objects translation with a slider(using a different objects space)


#1

Hi all,

I want to create a slider which drives an objects translate Y value, however I want the object to move according to a different objects “object space”

eg in this script a sphere object is created, whose translation Y value is being driven by the slider.

There’s also a cube which has been rotated 45 degrees in X.

When I move the slider, I would like the sphere to move in the cubes translate Y(according to the cubes object space), so instead of moving straight up, it will move up at an angle of 45 degrees.

I feel like I maybe need to make use of the world matrix to query the vectors for each objects translation, then find the offset between the two sets of vectors.

Then somehow add this offset to the spheres translation.

But I’m just guessing really, this stuff is a bit beyond me :surprised

Anyone have any ideas how to do this?

Thanks.


import maya.cmds as cmds
#create ball and cube objects
cube_obj = cmds.polyCube()
cmds.move( 2,0,0,cube_obj)
cmds.rotate( 45,0,0,cube_obj)
ball_obj = cmds.sphere()
# create slider
cmds.window( title='Attr Field Slider Groups' )
cmds.columnLayout()
cmds.attrFieldSliderGrp( min=-0, max=20, at='nurbsSphere1.translateY')
cmds.showWindow()
  

#2

I just realized that one thing I can do is parent the sphere to the ball before using the slider, then after moving it using the slider, unparent it(with preserve position checked)

It would be nice if there’s a more elegant solution though.


#3

Maybe create a zero group above the sphere and orientConstrain the zeroGroup to the cube.

David


#4

You could just use some simple matrix multiplication no?

For this example, you could use the “pointMatrixMult” node, pipe in the local/world (depending on how you’re doing this) matrix of the object and then just set the “inPoint” values, this will move the point in the space of the given matrix.

So, in your example:

Cube.worldMatrix[0] -> pointMatrixMult.inMatrix
pointMatrixMult.output -> sphere.translate (better with leaf connections)
Then your slider could setAttr “pointMatrixMult.inPointY” 10.

If you need offsets and such, you can build a local matrix with multMatrix nodes based on your heirarchy.


#5

Thanks for the help,

I managed to get this far using the ‘pointMatrixMult1’ node.
To get around the ball snapping to the cube position, I first created a group at the cube location and then parented the ball to the group. For some reason the script gives an error message although it seems to work ok.

The problem is that I want this script to work on scenes which are referenced in, so in that case the ball will not be able to be parented to anything, as it will have been referenced in.

import maya.cmds as cmds
#create ball and cube objects
cube_obj = cmds.polyCube()[0]
cmds.move( 2,0,0,cube_obj)
cmds.rotate( 45,0,0,cube_obj)
ball_obj = cmds.sphere()[0]

# get world space position of cube
pos = cmds.xform(cube_obj, ws=1, q=1, t=1)

# create empty group and place at location of cube
cmds.group(name = 'ball_grp', em=True)
cmds.setAttr('ball_grp.translate', pos[0],pos[1],pos[2])

# parent 'ball_obj' to 'ball_grp'
cmds.parent(ball_obj, 'ball_grp')

# create 'pointMatrixMult' node and conect to the ball and the cube
cmds.createNode('pointMatrixMult')
cmds.connectAttr(cube_obj+'.worldMatrix', 'pointMatrixMult1.inMatrix')
cmds.connectAttr('pointMatrixMult1.output', 'ball_grp.translate')

# create slider
cmds.window( title='Attr Field Slider Groups' )
cmds.columnLayout()
cmds.attrFieldSliderGrp( min=-0, max=20, at='pointMatrixMult1.inPointY')
cmds.showWindow()


So instead of grouping the ball object, maybe the balls offset from the cube can somehow be added to the calculation. I’ll try and look into what you suggested, I’ve never used the node editor though so I’m very new to all this stuff :slight_smile:

Thanks.


#6

Sorry about the delayed reply. But did you have any luck?

If you want to preserve the offset, all you really need to do is find the difference between the two transforms and use that as the inPoint values.

Something like this will work:

import maya.api.OpenMaya as om
import maya.cmds as cmds

sel = ['pSphere1','pCube1']

sphereMat = om.MMatrix(cmds.xform(sel[0],q=1,m=1,ws=1))
cubeMat = om.MMatrix(cmds.xform(sel[1],q=1,m=1,ws=1))
diffMat = sphereMat * cubeMat.inverse()

pmm = cmds.createNode("pointMatrixMult")

cmds.connectAttr("{}.worldMatrix[0]".format(sel[1]), "{}.inMatrix".format(pmm))
[cmds.setAttr("{}.inPoint{}".format(pmm,axis),diffMat[element]) for axis,element in zip(["X","Y","Z"],[12,13,14])]
cmds.connectAttr("{}.output".format(pmm),"{}.translate".format(sel[0]))

You could probably slot a plusMinusAverage node before the inPoint, so that you can add values onto the originals, that way you can connect your UI to the attribute starting from “0”.

Hope that makes sense.