在SceneKit中围绕锚点旋转

时间:2018-08-07 17:11:37

标签: ios graphics 3d scenekit arkit

目标:我的场景中有一个SCNCylinder对象。我希望能够拖动圆柱体的一端并向任意方向旋转圆柱体,同时将另一端保持在同一位置。

当前,我正在调用localRotate(by: SCNQuaternion)首先旋转节点,然后计算移动圆柱体所需的位置偏移,以便另一端可以返回其原始位置。

如何一步一步实现目标,而不是现在正在做什么?

1 个答案:

答案 0 :(得分:2)

您正在寻找pivot属性。或者,由于当您使用SIMD类型的simdPivot属性时,现代SceneKit通常可以更好地工作/使Swift变得更好/可以更轻松地与ARKit进行互操作。

请在文档中注意以下内容:

  

更改枢轴变换会以许多有用的方式更改这些行为。您可以:

     
      
  • 相对于其位置偏移节点的内容。例如,通过将枢轴设置为平移变换,可以相对于球在地板上放置的位置而不是相对于其中心的位置,将包含球几何的节点定位。
  •   
  • 移动节点的旋转轴。例如,通过平移变换,可以使节点绕远点旋转而不是围绕其中心旋转;而通过旋转变换,可以使旋转轴倾斜。
  •   

类似地,对于圆柱体,您可以使其圆柱体成为变换矩阵,该变换矩阵将原点平移其高度的一半,从而在一端而不是在中心给出“锚点”(用于位置和旋转更改)。像这样(未经测试):

let cylinder = SCNCylinder(radius: /*...*/, height: /*...*/)
let cylinderNode = SCNNode(geometry: cylinder)

cylinderNode.simdPivot = float4x4(translation: cylinder.height / 2)

extension float4x4 {
    init(translation vector: float3) {
        self.init(float4(1, 0, 0, 0),
                  float4(0, 1, 0, 0),
                  float4(0, 0, 1, 0),
                  float4(vector.x, vector.y, vector.z, 1))
    }
}

更一般而言,每当您使用基于场景图/基于变换层次结构的图形框架时,只要发现自己根据一种变换(旋转,平移等)影响另一种变换而进行数学运算,检查始终是一件好事可以为您完成数学运算的API —因为执行这种数学运算就是转换层次结构的全部内容。

如果没有一个特定于您所需要的API,请记住,层次结构本身非常适合进行相关转换。例如,如果您希望一个节点绕着另一个节点绕圆形轨道运行,则无需使用正弦和余弦来设置其位置...只需使其成为另一个节点的子节点,然后旋转另一个节点即可。

在这种情况下,pivot等效于使用节点层次结构。您也可以创建一个中间节点并在其中移动圆柱体(类似这样):

let cylinder = SCNCylinder(radius: /*...*/, height: /*...*/)
let cylinderNode = SCNNode(geometry: cylinder)

let offsetNode = SCNNode()
offsetNode.addChildNode(cylinderNode)
cylinderNode.simdPosition.y = cylinder.height / 2

offsetNode.position = /*...*/ // set world-space position of end of cylinder
offsetNode.eulerAngles.x = /*...*/ // rotate cylinder around its end