我有两个 SCNSphere,我想用 SCNCylinder“链接”它们(类似于这个 O<->O),但是我无法实现它我尝试使用 SCNNode pivot 属性应用旋转,lookAt(_:)但它们都不允许我实现我想要的。

作为约束,出于架构原因,我希望柱面成为第一个球体的子线。

假设我们有一个简单的情况,第一个和第二个球体的半径为 0.1,并且没有对它们应用旋转,只有位置是相关的:

static func createSphere(position: SCNVector3, color: UIColor = .red) -> SCNNode {
    let shape = SCNSphere(radius: 0.1)
    shape.firstMaterial?.diffuse.contents = color
    let node = SCNNode(geometry: shape)
    node.position = position
    return node
}

并创建“链接节点”:

static func createCylinder(position: SCNVector3, color: UIColor = .green) -> SCNNode {
    let shape = SCNCylinder(radius: 0.2, height: 1.0)
    shape.firstMaterial?.diffuse.contents = color
    let node = SCNNode(geometry: shape)
    node.position = position
    return node
}

所有这些都是这样使用的:

/// Create a sphere and the related link if there is a next sphere
 static func createPOI(position: SCNVector3, nextPosition: SCNVector3? = nil) -> SCNNode {
    var node: SCNNode = createSphere(position: position, color: .black)

    if let nextPosition = nextPosition {
        let lineNode = createLine(position: SCNVector3.zero, targetPosition: nextPosition)
        node.addChildNode(lineNode)
    }

    return node
}

static func createLine(position: SCNVector3, targetPosition: SCNVector3) -> SCNNode {
    let node = createCylinder(position: position)

    //step 1: handle rotation
    node.position = position
    //node.look(at: targetPosition)
    node.eulerAngles.x = Float.pi/2
    node.eulerAngles.y = atan2f(targetPosition.y, targetPosition.magnitude)

    //step 2: handle scaling and positioning
    node.pivot = SCNMatrix4MakeTranslation(-0.5, 0, 0)
    let width = CGFloat((targetPosition - position).magnitude)
    (node.geometry as? SCNCylinder)?.height = width

    //TODO: Cylinder should link source and target nodes
    //Tried a lot of things above but didn't manage to do it

    return node
}