代码之家  ›  专栏  ›  技术社区  ›  Willjay

如何使scnnode朝向aranchor

  •  6
  • Willjay  · 技术社区  · 6 年前

    我怎么做一个 ARNode 指向一个 ARAnchor ?

    我想用 art.scnassets/ship.scn 显示在屏幕中央并指向我刚才放置在场景中的某个地方的对象。

    /// ViewController Class
    func placeObject() {
        let screenCentre : CGPoint = CGPoint(x: self.sceneView.bounds.midX, y: self.sceneView.bounds.midY)
        guard let hitTestResult = sceneView.hitTest(screenCentre, types: [.featurePoint]).first else { return }
    
        // Place an anchor for a virtual character.
        let anchor = ARAnchor(name: identifierString, transform: hitTestResult.worldTransform)
        sceneView.session.add(anchor: anchor)
        // add to item model
        ItemModel.shared.anchors.append((identifierString, anchor)
    
    }
    
    func showDirection(of object: ARAnchor) { // object: saved anchor
    
        if !Guide.shared.isExist {
            let startPoint = SCNVector3(0, 0 , -1)
            let targetPoint = SCNVector3(object.transform.columns.3.x, object.transform.columns.3.y, object.transform.columns.3.z)
    
            let guideNode = Guide.shared.setPosition(from: startPoint, to: targetPoint)
    
            // add the ship in the center of the view
            sceneView.pointOfView?.addChildNode(guideNode)
    
        }
    }
    /// Guide Class   
    func setPosition(from start: SCNVector3, to target: SCNVector3) -> SCNNode {
        isExist = true
        guideNode.position = start
        targetPosition = target
    
        // create target node from saved anchor
        let desNode = SCNNode()
        desNode.position = targetPosition
    
        let lookAtConstraints = SCNLookAtConstraint(target: desNode)
        guideNode.constraints = [lookAtConstraints]
    
        return guideNode
    }
    
    // MARK: - ARSCNViewDelegate
    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        if let name = anchor.name, name.hasPrefix(identifierString) {
            // Create 3D Text
            let textNode: SCNNode = createNewBubbleParentNode(identifierString)
            node.addChildNode(textNode)
        }
    
    }
    

    我试过了 SCNLookAtConstraint 但它并没有按预期工作,有什么建议吗?

    demo

    3 回复  |  直到 6 年前
        1
  •  3
  •   Prashant Tukadiya    6 年前

    我不知道这对你的案子有没有帮助。(如果没有,我将删除我的答案)

    所以我也面临同样的问题。我在画两个物体之间的墙。问题是墙壁是双面的,所以在某些情况下,相机可以看到的部分会翻转。

    例如,如果从两个向量绘制墙,然后添加另一个节点(平面节点),具有相同的欧拉角,则添加的节点(平面)将垂直翻转。

    我已经搜索了很多解决方案,尝试了很多东西,但这对我很有用。

    class func node(from:SCNVector3,
                    to:SCNVector3,height:Float,needToAlignToCamera:Bool) -> SCNNode {
        let distance = MathHelper().getMeasurementBetween(vector1: from, and: to)
    
        let wall = SCNPlane(width: CGFloat(distance),
                            height: CGFloat(height))
        wall.firstMaterial = wallMaterial()
        let node = SCNNode(geometry: wall)
    
        // always render before the beachballs
        node.renderingOrder = -10
    
    
        // HERE IS MAGIC LINES 
        //============================================
    
        let normalizedTO = to.normalized()
        let normalizedFrom = from.normalized()
        let angleBetweenTwoVectors = normalizedTO.cross(normalizedFrom)
    
        var from = from
        var to = to
    
        if angleBetweenTwoVectors.y > 0 && needToAlignToCamera {
            let temp = from
            from = to
            to = temp
        }
        //============================================
    
    
        node.position = SCNVector3(from.x + (to.x - from.x) * 0.5,
                                   from.y + height * 0.5,
                                   from.z + (to.z - from.z) * 0.5)
    
        // orientation of the wall is fairly simple. we only need to orient it around the y axis,
        // and the angle is calculated with 2d math.. now this calculation does not factor in the position of the
        // camera, and so if you move the cursor right relative to the starting position the
        // wall will be oriented away from the camera (in this app the wall material is set as double sided so you will not notice)
        // - obviously if you want to render something on the walls, this issue will need to be resolved.
    
    
        node.eulerAngles = SCNVector3(0, -atan2(to.x - node.position.x, from.z - node.position.z) - Float.pi * 0.5, 0)
    
    
        return node
    }
    

    延伸

    func cross(_ vec: SCNVector3) -> SCNVector3 {
            return SCNVector3(self.y * vec.z - self.z * vec.y, self.z * vec.x - self.x * vec.z, self.x * vec.y - self.y * vec.x)
        }
    
    func normalized() -> SCNVector3 {
            if self.length() == 0 {
                return self
            }
    
            return self / self.length()
        }
    
        2
  •  2
  •   Ladumor Dineshkumar    6 年前

    ARKit 更新通过委托方法提供的锚和相应节点的位置 renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode?

    所以您的约束思想是正确的,但是您需要通过委托方法提供节点,而不是直接将它们添加到场景中。

    像那样的-

        func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
            switch anchor {
            case MyAnchor:
              let constraint = // ...
              let node = // ...
              node.constraints = [constraint]
              return node
            default:
              return nil
            }
        }
    
        3
  •  1
  •   Willjay    6 年前

    我注意到 SCNLookAtConstraint 当我的手机方向与地平线平行时工作。(屏幕朝上)

    这一行代码有魔力!! guideNode.pivot = SCNMatrix4Rotate(guideNode.pivot, Float.pi, 0, 1, 1)

    如果您感兴趣,请参阅 here .

     public func showDirection(of object: arItemList) {
    
        guard let pointOfView = sceneView.pointOfView else { return }
    
        // remove previous instruction
        for node in pointOfView.childNodes {
            node.removeFromParentNode()
        }
    
        // target
        let desNode = SCNNode()
        let targetPoint = SCNVector3.positionFromTransform(object.1.transform)
        desNode.worldPosition = targetPoint
    
        // guide
        let startPoint = SCNVector3(0, 0 , -1.0)
        let guideNode = loadObject()
        guideNode.scale = SCNVector3(0.7, 0.7, 0.7)
        guideNode.position = startPoint
    
        let lookAtConstraints = SCNLookAtConstraint(target: desNode)
        lookAtConstraints.isGimbalLockEnabled = true
        // Here's the magic
        guideNode.pivot = SCNMatrix4Rotate(guideNode.pivot, Float.pi, 0, 1, 1)
    
        guideNode.constraints = [lookAtConstraints]
        pointOfView.addChildNode(guideNode)
    }