Scene Kit的枢轴矩阵有什么语义?

3
我正在努力理解Scene Kit在节点的变换相关属性上使用的语义。特别是,节点上的枢轴属性不是单个点,而是完整的变换矩阵,在Collada规范或其他文档中没有找到类似的参考资料。
有没有人有使用Scene Kit中的枢轴矩阵或具有类似语义的属性的经验?可以提供简要说明/示例以及如何使用或指向相关文档的指针吗?这看起来是一个潜在有用的方法,但如果可以避免的话,我宁愿不进行逆向工程。
编辑:根据OMZ的回复,似乎枢轴只是变换树中的另一层。然而,如果是这样,它与添加一个中间节点有什么不同?基于什么确定应用哪些变换?
3个回答

3

我尝试了@omz的想法,但得到了一些冲突的结果,因此我更深入地研究了这个问题,并获得了一些有趣的结果。

答案是将反转点作为主变换的子级应用。这提供了与提供中间父节点完全不同的语义。

具体来说,如果我从一个具有变换P的父节点和一个具有变换C的子节点开始,它们组合成一个世界变换W = CATransform3DConcat(C, P)。通过将父节点的反转点设置为C的逆,并在子节点上不设置变换,则可以获得相同的世界变换W。

这种方法似乎提供了一些额外的效用,因为它不能通过插入中间节点来复制,并且在应用之前进行了反转。正如Hal Mueller指出的那样,文档确实说反转点影响旋转和缩放,以及位置,但对影响性质保持沉默。

以下是测试此结论的结果:

Set parent rotation and node position.

Transform:
{  1.00,  0.00,  0.00,  0.00 }
{  0.00,  1.00,  0.00,  0.00 }
{  0.00,  0.00,  1.00,  0.00 }
{  1.00,  2.00,  3.00,  1.00 }

Pivot:
{  1.00,  0.00,  0.00,  0.00 }
{  0.00,  1.00,  0.00,  0.00 }
{  0.00,  0.00,  1.00,  0.00 }
{  0.00,  0.00,  0.00,  1.00 }

World Transform:
{  1.00,  0.00,  0.00,  0.00 }
{  0.00,  0.00,  1.00,  0.00 }
{  0.00, -1.00,  0.00,  0.00 }
{  1.00, -3.00,  2.00,  1.00 }
2013-04-04 13:49:55.453 Model Importer[43504:303] 

CATransform3DConcat(node.transform, node.parentNode.transform)]
{  1.00,  0.00,  0.00,  0.00 }
{  0.00,  0.00,  1.00,  0.00 }
{  0.00, -1.00,  0.00,  0.00 }
{  1.00, -3.00,  2.00,  1.00 }
2013-04-04 13:49:55.454 Model Importer[43504:303] 

Set parent rotation and parent.pivot to inverse position.

Transform:
{  1.00,  0.00,  0.00,  0.00 }
{  0.00,  1.00,  0.00,  0.00 }
{  0.00,  0.00,  1.00,  0.00 }
{  0.00,  0.00,  0.00,  1.00 }

Pivot:
{  1.00,  0.00,  0.00,  0.00 }
{  0.00,  1.00,  0.00,  0.00 }
{  0.00,  0.00,  1.00,  0.00 }
{  0.00,  0.00,  0.00,  1.00 }

World Transform:
{  1.00,  0.00,  0.00,  0.00 }
{  0.00,  0.00,  1.00,  0.00 }
{  0.00, -1.00,  0.00,  0.00 }
{  1.00, -3.00,  2.00,  1.00 }

以下是代码示例:
    // Verification
    SCNVector3 v3 = {1.0, 2.0, 3.0};
    SCNVector4 v4 = {1.0, 0, 0, M_PI/2.0};
    node.parentNode.rotation = v4;
    node.position = v3;
    NSLog(@"\n\nSet parent rotation and node position.%@",
          [self transformsForNodeToString:node]);
    //
    // Verify match with CATransform3DConcat
    NSLog(@"\n\nCATransform3DConcat(node.transform, node.parentNode.transform)]%@",
          [self transformToString:CATransform3DConcat(node.transform, node.parentNode.transform)]);
    //
    // Clear the child node transform and put the inverse in the parent's pivot.
    CATransform3D position = node.transform;
    CATransform3D inversePosition = CATransform3DInvert(position);

    node.transform = CATransform3DIdentity;
    node.parentNode.pivot = inversePosition;
    NSLog(@"\n\nSet parent rotation and parent.pivot to inverse position.%@",
          [self transformsForNodeToString:node]);
    node.parentNode.pivot = CATransform3DIdentity;
    node.parentNode.transform = CATransform3DIdentity;


+ (NSString*)transformsForNodeToString: (SCNNode*)node {
    NSString* result = @"\n";
    result = [result stringByAppendingFormat:
          @"\nTransform:%@\nPivot:%@\nWorld Transform:%@",
          [self transformToString:node.transform],
          [self transformToString:node.pivot],
          [self transformToString:[node worldTransform]]];
    return result;
}

+ (NSString*)transformToString: (CATransform3D)transform {
    NSString* result = @"\n";
    result = [result stringByAppendingFormat:
              @"{ % .2f, % .2f, % .2f, % .2f }\n", transform.m11, transform.m12, transform.m13, transform.m14];
    result = [result stringByAppendingFormat:
              @"{ % .2f, % .2f, % .2f, % .2f }\n", transform.m21, transform.m22, transform.m23, transform.m24];
    result = [result stringByAppendingFormat:
              @"{ % .2f, % .2f, % .2f, % .2f }\n", transform.m31, transform.m32, transform.m33, transform.m34];
    result = [result stringByAppendingFormat:
              @"{ % .2f, % .2f, % .2f, % .2f }\n", transform.m41, transform.m42, transform.m43, transform.m44];
    return result;
}

欢迎留言!


2

我对SceneKit没有很多经验,但在3D建模应用程序中,枢轴点通常是可以旋转的点(有时称为定位器)。这使您能够更轻松地使对象围绕其自身轴旋转(这不一定对应于世界坐标系)。

对于未旋转的枢轴,矩阵将简单地为CATransform3DMakeTranslation(x, y, z)

编辑:我认为指定枢轴作为完整矩阵的事实只是因为它是一种方便的数据结构,并与模型的其余部分保持一致。我想不出任何你想要缩放枢轴的情况,但将其表示为矩阵使得可以使用通常的矩阵操作函数轻松操作它。

当然,您可以将枢轴表示为另一个中间节点并获得相同的结果,但枢轴是更“语义化”的表达对象中心的方式,更适合交互式编辑。在建模应用程序中选择对象时,通常会将变换工具手柄定位在枢轴处,以便您可以在不必向上导航到节点层次结构的情况下围绕其“自然”中心旋转/缩放对象。

我真的找不到关于这方面的好参考资料。大多数出现的内容似乎涉及各种软件包中的具体实现细节。


谢谢您的回复!我仍然对语义感到困惑,因为枢轴指定完整矩阵时。我尝试在定位器上搜索,但是像枢轴一样,该术语的用法似乎是含糊不清的,并且没有与您描述的或我在场景工具包中看到的匹配。您是否知道任何链接或参考资料? - Steven McGrath
谢谢,@omz,这似乎很有道理。我只是不想以后在使用时与导入的模型造成问题。我会尝试一些东西来看看它是否能够保持稳定,并跟进。 - Steven McGrath
@omz的评论与positionscalerotation属性的文档一致:都是相对于pivot指定的。 - Hal Mueller
@HalMueller,omz。感谢你们的帮助!我已经根据你们两个的回答进行了深入研究。请查看我的答案以获取详细信息,并让我知道是否有任何错误的结论。 - Steven McGrath

1

我认为在核心动画资料中会找到一些相关示例。一个SCNNodepivot被定义为一个CATransform3D,这在Mac和iOS上的核心动画中都有使用。

我自己还没有深入研究场景工具包,因此不太权威。但我发现Brad Larson的这篇文章:“Core Animation提供的CATransform3D结构用于对CALayer进行操作,其结构与OpenGL中的模型视图矩阵完全相同”。

Github上也有一个很酷的可视化工具,https://github.com/honcheng/CATransform3D-Test。Honcheng的演示只适用于iPad,但我认为仍然很有帮助。


感谢提供 GitHub 演示链接,看起来可能是一个不错的资源。然而,我一般了解变换的工作原理,但我正在尝试理解 Scene Kit 中节点的这个特定属性的意图,特别是因为我不明白它如何映射到 Collada 规范,因为 Scene Kit 中的大多数其他功能都可以实现。 - Steven McGrath

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接