Cocoa 场景工具包';什么是轴心矩阵?

Cocoa 场景工具包';什么是轴心矩阵?,cocoa,opengl,3d,collada,scenekit,Cocoa,Opengl,3d,Collada,Scenekit,我正在努力理解Scene Kit为节点使用变换相关属性的语义。特别是,节点上的pivot属性不是一个单点,而是一个完整的变换矩阵,我在Collada规范或其他文档中没有找到任何类似的参考 是否有人有使用场景工具包中的透视矩阵或具有类似语义的属性的经验?有人能提供一个简短的解释/示例,说明如何使用它,或者提供一个指向相关文档的指针吗?这看起来是一种潜在的有用方法,但如果可以避免的话,我宁愿不必对其进行反向工程 编辑:根据OMZ的响应,轴心可能只是变换树中的另一层。然而,如果是这样的话,它与仅仅添加

我正在努力理解Scene Kit为节点使用变换相关属性的语义。特别是,节点上的pivot属性不是一个单点,而是一个完整的变换矩阵,我在Collada规范或其他文档中没有找到任何类似的参考

是否有人有使用场景工具包中的透视矩阵或具有类似语义的属性的经验?有人能提供一个简短的解释/示例,说明如何使用它,或者提供一个指向相关文档的指针吗?这看起来是一种潜在的有用方法,但如果可以避免的话,我宁愿不必对其进行反向工程


编辑:根据OMZ的响应,轴心可能只是变换树中的另一层。然而,如果是这样的话,它与仅仅添加一个中间节点有什么不同?确定在何处应用哪些变换的BAI是什么?

我对SceneKit没有太多经验,但在3D建模应用程序中,轴是一个可以旋转的点(有时称为定位器)是很常见的。例如,这允许您使对象更容易围绕其自身的轴旋转(不一定对应于世界轴)

对于未旋转的轴,矩阵将只是
CATTransferorM3dMakeTransation(x,y,z)

编辑:我认为将pivot指定为完整矩阵只是因为它是一种方便的数据结构,并且与模型的其余部分保持一致。我想不出哪种情况下你会想要缩放一个轴心,但是将它表示为一个矩阵,可以很容易地使用通常的矩阵操作函数对其进行操作

当然,您可以将轴表示为另一个中间节点,并获得相同的结果,但轴是表示对象中心的更“语义”的方式,更适合于交互式编辑。在建模应用程序中选择对象时,通常会将变换工具手柄定位在轴所在的位置,这样您就可以围绕对象的“自然”中心旋转/缩放对象,而无需在节点层次中向上导航


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

我想您会在核心动画材料中找到一些相关示例。
SCNNode
pivot
被定义为
cattransferm3d
,在Mac和iOS上的整个核心动画中使用

我还没有深入到场景工具包中去,没有足够的权威性。但我发现:“核心动画提供的用于操纵CALayers的CATTransform3D结构在结构上与OpenGL中的模型视图矩阵相同”


GitHub上还有一个很酷的可视化工具。Honcheng的演示版仅限于iPad,但我认为仍然有帮助。

我尝试了@omz的想法。但是有一些相互矛盾的结果,所以我用一些有趣的结果进一步研究了这个问题

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

具体地说,如果我从带有transform p的父节点和带有transform C的子节点开始,它们将组合起来生成一个世界变换W=CATTransformorM3DCONCAT(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;
}

欢迎评论

谢谢你的回复!但是,当pivot指定一个完整的矩阵时,我仍然对语义感到困惑。我试着在定位器上搜索,但是,像pivot一样,该术语的用法似乎模棱两可,没有一个匹配您描述的内容,或者我在场景工具包中看到的内容。您知道任何链接或参考资料吗?谢谢,@omz,这似乎有道理。我只是不想开始使用它的方式,导致问题的进口模型的道路上。我将尝试一些方法,看看这是否成立,然后跟进。@omz的注释与doc中的属性
位置
比例
,和
旋转
:都是相对于
@HalMueller,omz指定的。谢谢你的帮助!我已经根据你的两个回答对此进行了深入研究。有关详细信息,请参阅我的答案,如果您认为我的结论有任何错误,请告诉我。感谢您提供GitHub演示的链接。看起来这可能是一个很好的资源。然而,我知道变换通常是如何工作的,但我试图理解场景工具包中节点的这个特定属性的意图,特别是因为我不知道它如何映射到Collada规范,而场景工具包中的大多数其他功能都是这样做的。