Maxscript:撰写转换

Maxscript: Compose Transformations

我正在尝试修复具有负比例的动画模型(我知道这可能是个坏主意)。在查看 max 脚本中的变换时,我注意到一些有趣的事情,这可能与 3ds max 中左手坐标系的内部使用有关。我将节点的变换与节点的 PRS 值进行了比较:我的期望是通过乘以 PRS 值,我也应该得到变换。但是,如果对象被旋转或镜像,则情况并非如此,请参阅:

  $.transform =
   row1    [0.866,-0.500,0.000] 
   row2    [-0.500,-0.866,0.000] 
   row3    [0.000,0.000,1.000] 
   row4    [13.000,-3.000,1.000] 
  ...scale * ...rotation * ...pos =
   row1    [-0.866,0.500,0.000] 
   row2    [-0.500,-0.866,0.000] 
   row3    [0.000,0.000,-1.000] 
   row4    [13.000,-3.000,1.000] 
  ...transform.scalepart * ...transform.rotationpart * ...transform.translationpart =
   row1    [-0.866,0.500,0.000] 
   row2    [0.500,0.866,0.000] 
   row3    [0.000,0.000,-1.000] 
   row4    [13.000,-3.000,1.000] 

任何想法,为什么这些转换不一样?我试图了解 3ds max 的幕后工作原理。非常感谢您的任何见解!

这里发生了一些事情。

首先,MaxScript $.transform.scalepart$.transform.rotationpart 似乎有问题并且不支持反向缩放。这些可能与 this post 上的第一个答案类似地实现,它总是给出正比例坐标,而负比例矩阵的答案是错误的。

其次,当请求 $.scale.controller.value$.rotation.controller.value 时,旋转部分也有问题,returns 与镜像之前的值相同,而比例 returns 是镜像的价值。如果您考虑(缩放 * 旋转 * 位置)矩阵组合的工作原理,您会发现,例如,X 中的镜像需要反转缩放的第一个分量,但也需要反转围绕 X 轴的所有旋转。

显然(我在这里推测)镜像模式在应用时会做两件事。 (1) 它激活 PRS 控制器内部的特殊情况处理,这样,当将 scale/rotation/transform 子控制器值组合成矩阵时,它会翻转一些坐标而不进行真正的矩阵组合。例如,X 方向的镜像反转变换矩阵前三行中每一行的第一个坐标,否则 PRS 控制器期望预镜像旋转值作为输入。 (2) 它翻转比例子控制器值的组件。例如,X 中的镜像会反转第一个坐标。但旋转子控制器不受影响。

所有这一切的结果是您在向 MaxScript 请求转换部分时获得了不正确的 maxtrix 合成。当直接组合 position/rotation/scale 子控制器值时,您也会得到不正确的组合。

您需要的是一种更好的方法来分解 position/rotation/scale 组件中的最终(正确)转换。这是基于所示算法的 MaxScript here。它returns 是一个包含ScaleMatrix、RotationMatrix、PositionMatrix 的数组,因此可以用(result[1] * result[2]) * result[3] 再次获得原始变换。将 $.transform 作为输入传递。

fn matrixDecompose t =
(
    trans = t.pos
    trn = ( matrix3 [1,0,0] [0,1,0] [0,0,1] trans )

    scaleX = length [ t[1][1], t[2][1], t[3][1] ]
    scaleY = length [ t[1][2], t[2][2], t[3][2] ]
    scalez = length [ t[1][3], t[2][3], t[3][3] ]    

    tempZ = cross t[1] t[2]
    if( (dot tempZ t[3]) < 0 ) then
    (
        scaleX = -scaleX
        t[1] = -t[1]
    )
    scl = ( matrix3 [scaleX,0,0] [0,scaleY,0] [0,0,scaleZ] [0,0,0] )    

    t[1] = normalize t[1]
    t[2] = normalize t[2]
    t[3] = normalize t[3]
    rot = t.rotationPart as matrix3

    #( scl, rot, trn )
)