gpt4 book ai didi

ios - Scenekit - 基于世界轴的旋转子子节点的 convertTransform

转载 作者:行者123 更新时间:2023-11-28 15:16:42 24 4
gpt4 key购买 nike

我有以下场景:

         [Root Node]
|
[Main Container]
| |
[Node A Wrapper] [Node B Wrapper]
| |
[Node A] [Node B]

我设置了平移手势识别器,当您在开放空间中平移时,[Main Container] 会在选定的方向上旋转 +/- Double.pi/2 (90deg)。当平移在子节点 A、B 之一上开始时(我在 touchesBegan 上对此进行了 HitTest ),我想沿世界轴方向旋转子节点(再次 90 度增量)。

我正在使用 rootNode 的 convertTransform() 旋转 [Main Container],它工作正常,并且旋转是沿着世界轴执行的 - 主容器的位置是 (0,0,0),我相信这使得容易多了。

我包裹子节点的原因是它们在包裹器内有局部位置 (0,0,0),这应该有助于围绕它们的原点旋转。但是当我在 [Main Container] 上执行旋转时它们也会旋转,它们的局部轴的方向会改变并且旋转是围绕与我想要的不同的轴执行的。

根据我对变换矩阵的(非常有限的)理解,我假设我需要以某种方式链接和乘以由父节点的 convertTransform 生成的矩阵,或者以某种方式使用 worldTransform 属性,但我尝试的任何事情都会导致奇怪的旋转。任何帮助,将不胜感激!

最佳答案

我已经建立了一个基于 SceneKit 模板的小型示例项目,其中的控件与您描述的类似。它在 Objective C 中,但相关部分几乎相同:

- (void) handlePan:(UIPanGestureRecognizer*)gestureRecognize {

CGPoint delta = [gestureRecognize translationInView:(SCNView *)self.view];
if (gestureRecognize.state == UIGestureRecognizerStateChanged) {
panHorizontal = NO;
if (fabs(delta.x) > fabs(delta.y)) {
panHorizontal = YES;
}

} else if (gestureRecognize.state == UIGestureRecognizerStateEnded) {

SCNMatrix4 rotMat;
int direction = 0;
if (panHorizontal) {
if (delta.x <0) {
direction = -1;
} else if (delta.x >1) {
direction = 1;
}
rotMat= SCNMatrix4Rotate(SCNMatrix4Identity, M_PI_2, 0, direction, 0);
} else {
if (delta.y <0) {
direction = -1;
} else if (delta.y >1) {
direction = 1;
}
rotMat= SCNMatrix4Rotate(SCNMatrix4Identity, M_PI_2, direction, 0, 0);
}


if (selectedNode == mainPlanet) {
selectedNode.transform = SCNMatrix4Mult(selectedNode.transform, rotMat);

} else { //_selectedNode is a child node of mainPlanet, i.e. moons.
//get the translation matrix of the child node
SCNMatrix4 transMat = SCNMatrix4MakeTranslation(selectedNode.position.x, selectedNode.position.y, selectedNode.position.z);

//move the child node the origin of its parent (but keep its local rotation)
selectedNode.transform = SCNMatrix4Mult(selectedNode.transform, SCNMatrix4Invert(transMat));

//apply the "rotation" of the mainPlanet extra (we can use the transform because mainPlanet is at world origin)
selectedNode.transform = SCNMatrix4Mult( selectedNode.transform, mainPlanet.transform);

//perform the rotation based on the pan gesture
selectedNode.transform = SCNMatrix4Mult(selectedNode.transform, rotMat);

//remove the extra "rotation" of the mainPlanet (we can use the transform because mainPlanet is at world origin)
selectedNode.transform = SCNMatrix4Mult(selectedNode.transform,SCNMatrix4Invert(mainPlanet.transform));

//add back the translation mat
selectedNode.transform = SCNMatrix4Mult(selectedNode.transform,transMat);

}
}
}

在 handleTap 中:

selectedNode = result.node;

在viewDidLoad中:

 mainPlanet = [scene.rootNode childNodeWithName:@"MainPlanet" recursively:YES];
orangeMoon = [scene.rootNode childNodeWithName:@"orangeMoon" recursively:YES];
yellowMoon = [scene.rootNode childNodeWithName:@"yellowMoon" recursively:YES];

UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
[gestureRecognizers addObject:panGesture];

和本地变量:

SCNNode *mainPlanet;
SCNNode *orangeMoon;
SCNNode *yellowMoon;
SCNNode *selectedNode;
BOOL panHorizontal;

Layout of the 3 nodes, the cubes were merely to test

MainPlanet 将是您的 mainContainer 并且不必可见(在我的示例中它是可见的,因为必须点击它才能知道要旋转什么...)。两个月亮就是你的节点A和B,主节点的子节点。不需要 wrapper 。关键部分显然是注释部分。

通常在局部空间旋转子节点(如果父节点在 0,0,0)

  1. 首先将其变换与其平移的逆相乘,将其移回节点。
  2. 应用旋转矩阵。
  3. 应用我们在第 1 步中删除的原始翻译。

正如您所注意到的,这将在其局部轴心点和局部轴上旋转子节点。在您旋转父节点之前,这可以正常工作。解决方案是在基于平移手势旋转子节点之前将相同的旋转应用到子节点(步骤 2),然后再次将其删除。

所以为了得到你想要的结果:

  1. 首先将其变换与其平移的逆相乘,将其移回节点。
  2. 应用父节点的旋转(因为它在 0,0,0,我假设没有缩放,我们可以使用变换)。
  3. 根据平移手势应用旋转矩阵。
  4. 去除父节点的旋转
  5. 应用我们在第 1 步中删除的原始翻译。

我确定还有其他可能的路线,也许可以使用转换为/从转换矩阵将旋转矩阵转换为主节点,而不是第 2 步和第 4 步,但通过这种方式您可以清楚地知道发生了什么。

关于ios - Scenekit - 基于世界轴的旋转子子节点的 convertTransform,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46723827/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com