JokerMartini
JokerMartini

Reputation: 6147

python + maya: Rotate Y axis to be along vector

How can I rotate the circle shape so it's y axis is along the supplied vector? The vector in this sample script is created using the two locators in the scene. The code is broken up into 3 sections. The first section just creates the test scene. The second part collects the vector. The third part is where I need help figuring out how to use the vector to adjust the rotation of the circle so it's Y axis is pointing along the collected vector. Thank you guys.

import maya.cmds as cmds
import random
import math

cmds.select(all=True)   
cmds.delete()

#------------------------------TEST SCENE SETUP

def genPos():
    x = random.uniform(-5,5)
    y = random.uniform(0,5)
    z = random.uniform(-5,5)
    return (x, y, z)

a = cmds.spaceLocator(n='ctrl_00')
b = cmds.spaceLocator(n='ctrl_00')

cmds.xform(a, t=(genPos()) )
cmds.xform(b, t=(genPos()) )

cmds.createDisplayLayer(name="Ctrls")
cmds.editDisplayLayerMembers('Ctrls', a, b)
cmds.setAttr('Ctrls.color' ,14)

cmds.select(clear=True)


#-----------------------THE SCRIPT
def normlizedVector(vecA,vecB,offset):

    nX = vecB[0] - vecA[0]
    nY = vecB[1] - vecA[1]
    nZ = vecB[2] - vecA[2]

    #vectorLength = distance vecA vecB
    # find the distance between the two supplied point3 values
    distX = pow( (vecA[0] - vecB[0] ) , 2.0 ) 
    distY = pow( (vecA[1] - vecB[1] ) , 2.0 ) 
    distZ = pow( (vecA[2] - vecB[2] ) , 2.0 )

    vecLength = math.sqrt(distX + distY + distZ)

    # the normalized vector is calculated by dividing the X, Y and Z coordinates by the length
    calcX = nX / vecLength
    calcY = nY / vecLength
    calcZ = nZ / vecLength

    # project point along vector, offset by a given value
    ptX = vecB[0] + (calcX * offset)
    ptY = vecB[1] + (calcY * offset)
    ptZ = vecB[2] + (calcZ * offset)

    return (ptX, ptY, ptZ)


posA = cmds.xform(a,q=1,ws=1,rp=1)  
posB = cmds.xform(b,q=1,ws=1,rp=1)  

pt = normlizedVector(posA,posB,10)

#--------MOVE AND ALIGN CIRCLE
cir = cmds.circle( nr=(0, 0, 1), c=(0, 0, 0) )
cmds.xform(cir, t=posB )

Upvotes: 0

Views: 3011

Answers (1)

joojaa
joojaa

Reputation: 4434

The power of using a package like Maya is in the fact that you don't need to do all of the stuff on your own. You can do it, but it will be slower and less efficient than working with Maya. In fact if you insist on doing it this way you should consider disposing Maya entirely, because its just a extra cost center you no longer need.

Now maya offers tools for this. The obvious tool in this case is constraints if your building a rig. There's nothing wrong in calling an existing tool. You do it all the time with functions, why not with maya nodes they are functions after all. The most obvious is to create the circle directly in the position where you want the normal pointing the nr option is for this purpose. But looks like you want some actual rigging:

#aim 00 to 01 swap if you need the other way around
cmds.aimConstraint("ctrl_01", "ctrl_00", 
                   aimVector=(0, 1, 0), upVector=(0, 0, 1), 
                   worldUpType="vector", worldUpVector=(0, 1, 0));

That is it. However a bit of explanation should you want to ever reproduce this in code or to modify the solution, since this is not a problem free approach. What the aim node does is it builds manually a matrix from 3 vectors, but there is a infinite number ow ways you could do this differently. In this case the pole vector is a bit of a problem if your aim vector ever points in up vector direction your going to experience some problems.

Now the matrix is just a bunch of vectors pointing in the cardinal direction is trivial. Maya stores matrices in in vectors are rows format so a matrix that points in y along a vector, where a is normalized to unit length, a would look as follows:

?   ?   ?   ?
a.x a.y a.z a.w=0 
?   ?   ?   ? 
0   0   0   1

Now for this to work out you need any orthogonal values for the question marked vectors. enter up vector, in this case take a cross product with the local up direction. and place its value in the x column (up vector applies as a placeholder for the unknown up vector), let us call this b and you get:

b.x b.y b.z b.w=0
a.x a.y a.z a.w=0 
?   ?   ?   ? 
0   0   0   1

Now you can recompute the up vector because it must be orthogonal to a and b so cross a b for c and you get:

b.x b.y b.z b.w=0
a.x a.y a.z a.w=0 
c.x c.y c.z c.w=0 
0   0   0   1

You can decompose this matrix to get Euler angles. You could use variations of this theme by adding up to a to get the paceholder reference for example

Upvotes: 2

Related Questions