python + maya: 将Y轴旋转至与向量对齐

0 投票
1 回答
2914 浏览
提问于 2025-04-18 01:46

我该如何旋转这个圆形,使它的Y轴与给定的向量对齐呢?在这个示例脚本中,向量是通过场景中的两个定位器创建的。代码分成了三个部分。第一部分只是创建测试场景。第二部分是收集向量。第三部分是我需要帮助的地方,想弄明白如何利用这个向量来调整圆形的旋转,使它的Y轴指向收集到的向量。谢谢大家。

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 )

1 个回答

2

使用像Maya这样的工具的好处在于,你不需要自己做所有的事情。虽然你可以自己完成,但这样做会更慢,也不够高效。如果你坚持要自己做,那就考虑完全放弃Maya,因为那样只是在增加不必要的开支。

Maya提供了一些工具来帮助你。比如,如果你在制作一个角色的骨架,最明显的工具就是约束(constraints)。使用现有的工具没有问题。你在编程时经常调用函数,为什么不也用Maya的节点呢?毕竟它们也是函数。最简单的方法是直接在你想要法线指向的地方创建一个圆圈,nr选项就是为这个目的而设的。不过,看起来你想做一些实际的绑定工作:

#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));

就是这样。不过,如果你想在代码中重现这个过程或修改这个解决方案,还是需要一点解释,因为这并不是一个没有问题的方法。目标节点的作用是手动从三个向量构建一个矩阵,但实际上有无数种不同的方法可以做到这一点。在这个例子中,极点向量(pole vector)有点麻烦,如果你的目标向量指向上方,你会遇到一些问题。

现在,矩阵其实就是一堆指向基本方向的向量,这一点很简单。Maya以行格式存储矩阵,所以一个指向y方向的矩阵,其中a被标准化为单位长度,看起来是这样的:

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

为了让这个工作正常,你需要为标记为问号的向量找到任何正交值。这里需要引入上向量,计算与本地上方向的叉乘,并把它的值放在x列(上向量作为未知上向量的占位符),我们称这个为b,结果是:

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

现在你可以重新计算上向量,因为它必须与a和b正交,所以用a和b的叉乘得到c,结果是:

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

你可以分解这个矩阵来获取欧拉角。你也可以通过在a上加一些变化来得到占位符参考。

撰写回答