Как сделать SCNNode лицом к ARAnchor - PullRequest
0 голосов
/ 29 ноября 2018

Как я могу сделать 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 ]

0 голосов
/ 06 декабря 2018

Не знаю, поможет ли это вам в вашем случае или нет.(Если нет, я удалю свой ответ)

Так что я столкнулся с той же проблемой.Где я рисую стену между двумя объектами SCNVector.Проблема в том, что стена двусторонняя, поэтому в некоторых случаях видимая для камеры часть переворачивается.

как если вы рисуете стену из двух векторов, а затем добавляете другой узел (плоскость) с тем же углом Эйлера, добавляется узел (плоскость)Вертикально перевернуто.

Я искал много решений и пробовал много вещей, но это работает для меня.

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()
    }
0 голосов
/ 07 декабря 2018

Я заметил, что SCNLookAtConstraint работает, когда ориентация моего телефона параллельна горизонту.(экран направлен вверх)

И эта строка кода делает волшебство !!guideNode.pivot = SCNMatrix4Rotate(guideNode.pivot, Float.pi, 0, 1, 1)

Если вам интересно, см. здесь .

 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)
}
0 голосов
/ 29 ноября 2018

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
        }
    }
...