pivot 属性是您正在寻找的。或者,当您使用 SIMD 类型时,现代 SceneKit 通常工作得更好/使 Swift 更好/与 ARKit 互操作更容易,simdPivot 属性。
请注意文档中的这一点:
更改枢轴变换会以许多有用的方式改变这些行为。你可以:
- 相对于其位置偏移节点的内容。例如,通过将枢轴设置为平移变换,您可以将包含球体几何形状的节点相对于球体放置在地板上的位置而不是相对于其中心定位。
- 移动节点的旋转轴。例如,通过平移变换,您可以使节点围绕远处的点旋转,而不是围绕其中心旋转;通过旋转变换,您可以倾斜旋转轴。
同样,对于圆柱体,您可以将其枢轴设为一个变换矩阵,将原点平移一半高度,在一端而不是中心为其提供一个“锚点”(用于位置和旋转变化)。像这样的东西(未经测试):
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