在 SceneKit 中围绕锚点旋转

Rotating around anchor point in SceneKit

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

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

我怎样才能一步实现 objective 而不是我现在正在做的事情?

pivot 属性 就是您要找的。或者,由于当您使用 SIMD 类型时,现代 SceneKit 通常工作得更好/做得更好 Swift/与 ARKit 的互操作更容易,simdPivot 属性.

注意文档中的这一点:

Changing the pivot transform alters these behaviors in many useful ways. You can:

  • Offset the node’s contents relative to its position. For example, by setting the pivot to a translation transform you can position a node containing a sphere geometry relative to where the sphere would rest on a floor instead of relative to its center.
  • Move the node’s axis of rotation. For example, with a translation transform you can cause a node to revolve around a faraway point instead of rotating around its center, and with a rotation transform you can tilt the axis of rotation.

类似地,对于圆柱体,您可以将其轴心设为变换矩阵,将原点平移其高度的一半,在一端而不是中心为其提供一个“锚点”(用于位置和旋转变化) .像这样的东西(未经测试):

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